使用Kotlin读取大型(+ - 50MB)JSON文件

发布于 2025-01-25 17:52:31 字数 2049 浏览 1 评论 0原文

我开始使用“ OpenWeatherMap.org” API在天气应用程序上工作,它们为您提供JSON格式可用城市的列表。

在继续项目之前,我希望能够使用此JSON文件中的数据。

问题在于,每当我尝试阅读并解析该文件时,我都会变得无效。

这是代码:

主要活动:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val jsonFileString = getJsonDataFromAsset(applicationContext, "citylist.json")
        Log.i("gabs Data", jsonFileString ?: "Empty Data")
        val gson = Gson()
        val listOfCities = object : TypeToken<List<CityList>>() {}.type
        var cities: List<CityList> = gson.fromJson(jsonFileString, listOfCities)
        cities.forEachIndexed { idx, city -> Log.i("data", "> Item $idx:\n$city") }
    }
}

utils.kt:

fun getJsonDataFromAsset(context: Context, fileName: String): String? {
    val jsonString: String
    try {
        jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
    } catch (ioException: IOException) {
        ioException.printStackTrace()
        return null
    }
    return jsonString
}

和数据类(城市数组数据):

class CityList : ArrayList<CityList.CityListItem>(){
    data class CityListItem(
        @SerializedName("coord")
        val coord: Coord,
        @SerializedName("country")
        val country: String,
        @SerializedName("id")
        val id: Double,
        @SerializedName("name")
        val name: String,
        @SerializedName("state")
        val state: String
    ) {
        data class Coord(
            @SerializedName("lat")
            val lat: Double,
            @SerializedName("lon")
            val lon: Double
        )
    }
}

错误:

java.lang.runtimeexception:无法启动活动componentInfo {com.example.weatherdisplay/com.example.weatherdisplay.weatherdisplay.weatherdisplay 。

引起的: 在com.example.weatherdisplay.ui.activities.mainactivity.oncreate(MainActivity.kt:21)

I'm starting to work on a weather app using "openweathermap.org" API, and they provide you with a list of available cities in Json format.

Before i continue with the project, i would like to able to work with the data from this Json file.

The problem is that i get Null whenever i try to read and parse that file.

Here is the code:

Main Activity:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val jsonFileString = getJsonDataFromAsset(applicationContext, "citylist.json")
        Log.i("gabs Data", jsonFileString ?: "Empty Data")
        val gson = Gson()
        val listOfCities = object : TypeToken<List<CityList>>() {}.type
        var cities: List<CityList> = gson.fromJson(jsonFileString, listOfCities)
        cities.forEachIndexed { idx, city -> Log.i("data", "> Item $idx:\n$city") }
    }
}

Utils.kt:

fun getJsonDataFromAsset(context: Context, fileName: String): String? {
    val jsonString: String
    try {
        jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
    } catch (ioException: IOException) {
        ioException.printStackTrace()
        return null
    }
    return jsonString
}

And the data class (Array of cities data):

class CityList : ArrayList<CityList.CityListItem>(){
    data class CityListItem(
        @SerializedName("coord")
        val coord: Coord,
        @SerializedName("country")
        val country: String,
        @SerializedName("id")
        val id: Double,
        @SerializedName("name")
        val name: String,
        @SerializedName("state")
        val state: String
    ) {
        data class Coord(
            @SerializedName("lat")
            val lat: Double,
            @SerializedName("lon")
            val lon: Double
        )
    }
}

And the error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.weatherdisplay/com.example.weatherdisplay.ui.activities.MainActivity}: java.lang.NullPointerException: gson.fromJson(jsonFileString, listOfCities) must not be null.

Caused by: java.lang.NullPointerException: gson.fromJson(jsonFileString, listOfCities) must not be null
at com.example.weatherdisplay.ui.activities.MainActivity.onCreate(MainActivity.kt:21)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

仲春光 2025-02-01 17:52:31

代码中存在一些问题:

  1. 您没有关闭BufferedReader
  2. 您不应将文件加载到主线程上,因为它将阻止UI

我创建了一些与您的数据结构相对应的示例数据:

[
  {
    "id": 1,
    "country": "Germany",
    "state": "Saxony",
    "name": "Dresden",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 2,
    "country": "Germany",
    "state": "Berlin",
    "name": "Berlin",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 3,
    "country": "Germany",
    "state": "Baden-Wuerttemberg",
    "name": "Stuttgart",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 4,
    "country": "Germany",
    "state": "Hessen",
    "name": "Frankfurth",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 5,
    "country": "Germany",
    "state": "Nordrhine-Westphalia",
    "name": "Cologne",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  }
]

您的活动:

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MyApplication"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycleScope.launchWhenStarted {
            launch(Dispatchers.IO) {
                var reader: BufferedReader? = null
                try {
                    // Create a reader and read the file contents
                    reader = assets.open("data.json").bufferedReader()
                    val rawData = reader.use { it.readText() }

                    // Create a Type token that Gson knows how to parse the raw data
                    val cityListType = object : TypeToken<List<City>>() {}.type

                    // Parse the raw data using Gson
                    val data: List<City> = Gson().fromJson(rawData, cityListType)

                    // TODO: Do something with the data
                } catch (e: IOException) {
                    // Handle IOException: Gets thrown when the file wasn't found or something similar
                    Log.e(TAG, "An error occurred while reading in the data:", e)
                } catch (e: JsonParseException) {
                    // Handle JsonParseException: Gets thrown when there is a problem with the contents of the file
                    Log.e(TAG, "An error occurred while reading in the data:", e)
                }
                finally {
                    // Close the reader to release system resources
                    reader?.close()
                }
            }
        }
    }

}

您的数据结构:

data class City(
    @SerializedName("id")
    val id: Int,

    @SerializedName("country")
    val country: String,

    @SerializedName("state")
    val state: String,

    @SerializedName("name")
    val name: String,

    @SerializedName("coord")
    val coordinate: Coordinate
) {
    override fun toString(): String {
        return "#$id[$name $state $country]@[${coordinate.lat}|${coordinate.lon}]"
    }
}

data class Coordinate(
    @SerializedName("lat")
    val lat: Double,

    @SerializedName("lon")
    val lon: Double
)

在最好的情况下,您会将获取文件内容的代码放在viewModel中,但这将超出此答案的范围。

有关ViewModels的其他信息: https://developer.android。 com/topic/libraries/Architecture/ViewModel

There were some problems in your code:

  1. You were not closing the BufferedReader
  2. You should not load the file on the Main thread since it will block the UI

I created some sample data corresponding to your data structure:

[
  {
    "id": 1,
    "country": "Germany",
    "state": "Saxony",
    "name": "Dresden",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 2,
    "country": "Germany",
    "state": "Berlin",
    "name": "Berlin",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 3,
    "country": "Germany",
    "state": "Baden-Wuerttemberg",
    "name": "Stuttgart",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 4,
    "country": "Germany",
    "state": "Hessen",
    "name": "Frankfurth",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  },
  {
    "id": 5,
    "country": "Germany",
    "state": "Nordrhine-Westphalia",
    "name": "Cologne",
    "coord": {
      "lat": 0.0,
      "lon": 0.0
    }
  }
]

Your activity:

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MyApplication"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycleScope.launchWhenStarted {
            launch(Dispatchers.IO) {
                var reader: BufferedReader? = null
                try {
                    // Create a reader and read the file contents
                    reader = assets.open("data.json").bufferedReader()
                    val rawData = reader.use { it.readText() }

                    // Create a Type token that Gson knows how to parse the raw data
                    val cityListType = object : TypeToken<List<City>>() {}.type

                    // Parse the raw data using Gson
                    val data: List<City> = Gson().fromJson(rawData, cityListType)

                    // TODO: Do something with the data
                } catch (e: IOException) {
                    // Handle IOException: Gets thrown when the file wasn't found or something similar
                    Log.e(TAG, "An error occurred while reading in the data:", e)
                } catch (e: JsonParseException) {
                    // Handle JsonParseException: Gets thrown when there is a problem with the contents of the file
                    Log.e(TAG, "An error occurred while reading in the data:", e)
                }
                finally {
                    // Close the reader to release system resources
                    reader?.close()
                }
            }
        }
    }

}

Your data structure:

data class City(
    @SerializedName("id")
    val id: Int,

    @SerializedName("country")
    val country: String,

    @SerializedName("state")
    val state: String,

    @SerializedName("name")
    val name: String,

    @SerializedName("coord")
    val coordinate: Coordinate
) {
    override fun toString(): String {
        return "#$id[$name $state $country]@[${coordinate.lat}|${coordinate.lon}]"
    }
}

data class Coordinate(
    @SerializedName("lat")
    val lat: Double,

    @SerializedName("lon")
    val lon: Double
)

In the best case you would put the code in which you get the file contents and parse the data in a ViewModel, but this would to go beyond the scope for this answer.

Additional information about ViewModels: https://developer.android.com/topic/libraries/architecture/viewmodel

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文