0

I prepared a data set for the dictionary application I will make and converted this data set to json file. I want to extract the data in this json file according to the letters that the user clicks, for example, if the user clicked on the letter A, the collocations related to A would come, but I could not find how to parse it manually in andorid kotlin compose, can you help?

my json file example

{
    "A": [
        {
            "collocation": "above average",
            "meaning": "more than average, esp. in amount, age, height, weight etc. "
        },
        {
            "collocation": "absolutely necessary",
            "meaning": "totally or completely necessary"
        }
], 
"B": [
        {
            "collocation": "back pay",
            "meaning": "money a worker earned in the past but hasn't been paid yet  "
        },
        {
            "collocation": "back road",
            "meaning": "a small country road "
        }
]

presentation layer (view)

 val jsonFileString = viewModel.getJsonDataFromCollocationsJson(context,fileName = "collocations.json")
                                    Log.i("data", jsonFileString?:"null")

                                    val gson = Gson()
                                    val listCollocationType = object : TypeToken<List<Collocations>>() {}.type

                                    var collocations: List<Collocations> = gson.fromJson(jsonFileString, listCollocationType)
                                    collocations.forEachIndexed { idx, Collocations -> Log.i("data", "> Item $idx:\n$Collocations") }

presentation layer (viewmodel)

  fun getJsonDataFromCollocationsJson(context: Context ,fileName:String) : String?{

        var jsonString: String?=null

        try {
             jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
        }catch (e :IOException){
            e.printStackTrace()
            return null
        }
        return jsonString
    }

When I run this code, I get an error like this. but all data is also coming. I don't want all data to come

error

/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.enestigli.dictionaryapp, PID: 5885
    com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
        at com.google.gson.Gson.fromJson(Gson.java:939)
        at com.google.gson.Gson.fromJson(Gson.java:892)
        at com.google.gson.Gson.fromJson(Gson.java:841)
        at com.enestigli.dictionaryapp.presentation.CollocationScreen.CollocationScreenKt$gridView$2$1$1$1$1$1$1.invoke(CollocationScreen.kt:166)
        at com.enestigli.dictionaryapp.presentation.CollocationScreen.CollocationScreenKt$gridView$2$1$1$1$1$1$1.invoke(CollocationScreen.kt:158)
        at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$2.invoke-k-4lQ0M(Clickable.kt:153)
        at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$2.invoke(Clickable.kt:142)
        at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1$1.invokeSuspend(TapGestureDetector.kt:220)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
        at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
        at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:560)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:452)
        at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:465)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:310)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:297)
        at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:179)
        at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:98)
        at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:80)
        at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1261)
        at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1211)
        at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1150)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3121)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2802)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:498)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1899)
        at android.app.Activity.dispatchTouchEvent(Activity.java:4262)
E/AndroidRuntime:     at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:456)
        at android.view.View.dispatchPointerEvent(View.java:15263)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6548)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6348)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5804)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5861)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5827)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5992)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5835)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:6049)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5808)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5861)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5827)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5835)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5808)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8857)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8808)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8777)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8980)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:267)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:335)
        at android.os.Looper.loopOnce(Looper.java:161)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@8b42480, androidx.compose.runtime.BroadcastFrameClock@2d2bab9, StandaloneCoroutine{Cancelling}@cb40efe, AndroidUiDispatcher@baff65f]
    Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
        at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
        at com.google.gson.Gson.fromJson(Gson.java:927)

1 Answer 1

1

Have I understood your question properly:

  1. User enters a letter, say "B"
  2. You want your application to provide the "collocations" for B, i.e. "back pay" and "back road"
  3. So you are proposing reading a part of the JSON file to retrieve only the "B" data?

If so, only parsing part of JSON file will be hard, since you will have to parse it anyway to find the start of the A data, the start of the B data, etc.

Why not read it all into a Map<String, List<Collocations>> where the Map's key is A, B, etc and then you can just access the map with the desired letter.

But perhaps you don't want to do this, because, say, the data is too large. OK, well since you say you authored the JSON file... just create many JSON files - one for each letter? A.json, B.json, etc


You said in a comment

so can you tell me how can I read all data from json file ? because you said reading a specific data from json file is hard. I am getting below error when I try to read data from json

The error com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

is simply because your source String isn't actually JSON.

You have a Log statement Log.i("data", jsonFileString?:"null") what is that showing? Are you seeing your JSON file at this time?

This following code works - but notice I am inlining the JSON data, rather than reading from a resource file which is not what you want to do, but shows you the JSON parsing code - you just need debug your file reading:

import com.google.common.reflect.TypeToken
import com.google.gson.Gson

data class Collocation(
    val collocation: String,
    val meaning: String,
)

fun main(args: Array<String>) {
    val jsonFileString = getJsonDataFromCollocationsJson(fileName = "collocations.json")
    println(jsonFileString)

    val gson = Gson()
    val listCollocationType = object : TypeToken<Map<String, List<Collocation>>>() {}.type

    var collocationsByLetter: Map<String, List<Collocation>> = gson.fromJson(jsonFileString, listCollocationType)
    collocationsByLetter.forEach { letter, collocations ->
        println("$letter : $collocations")
    }

}

fun getJsonDataFromCollocationsJson(fileName: String) =
    """
        {
          "A": [
            {
              "collocation": "above average",
              "meaning": "more than average, esp. in amount, age, height, weight etc. "
            },
            {
              "collocation": "absolutely necessary",
              "meaning": "totally or completely necessary"
            }
          ],
          "B": [
            {
              "collocation": "back pay",
              "meaning": "money a worker earned in the past but hasn't been paid yet  "
            },
            {
              "collocation": "back road",
              "meaning": "a small country road "
            }
          ]
        }
    """.trimIndent()

prints (after the JSON)

A : [Collocation(collocation=above average, meaning=more than average, esp. in amount, age, height, weight etc. ), Collocation(collocation=absolutely necessary, meaning=totally or completely necessary)]
B : [Collocation(collocation=back pay, meaning=money a worker earned in the past but hasn't been paid yet  ), Collocation(collocation=back road, meaning=a small country road )]
Sign up to request clarification or add additional context in comments.

2 Comments

okey I understand what you said I will look into.
so can you tell me how can I read all data from json file ? because you said reading a specific data from json file is hard. I am getting below error when I try to read data from json.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.