GVKun编程网logo

如何在 Kotlin 中使用 moshi 解析 json 本地文件(kotlin monad)

13

如果您想了解如何在Kotlin中使用moshi解析json本地文件和kotlinmonad的知识,那么本篇文章将是您的不二之选。我们将深入剖析如何在Kotlin中使用moshi解析json本地文件的各

如果您想了解如何在 Kotlin 中使用 moshi 解析 json 本地文件kotlin monad的知识,那么本篇文章将是您的不二之选。我们将深入剖析如何在 Kotlin 中使用 moshi 解析 json 本地文件的各个方面,并为您解答kotlin monad的疑在这篇文章中,我们将为您介绍如何在 Kotlin 中使用 moshi 解析 json 本地文件的相关知识,同时也会详细的解释kotlin monad的运用方法,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

如何在 Kotlin 中使用 moshi 解析 json 本地文件(kotlin monad)

如何在 Kotlin 中使用 moshi 解析 json 本地文件(kotlin monad)

如何解决如何在 Kotlin 中使用 moshi 解析 json 本地文件?

目前我正在使用一个 api,我使用 RetroFit-2 和 moshi 将它解析为 kotlin-Object,我知道因为我正在使用一个 rest API,所以我必须使用 RetroFit。但这就是我的问题的来源,(我的想法是下载 api (.json))以将其保存在设备本地,但我不知道如何从“本地”文件中传递它。

目前这是我获取api的代码

//Url donde se aloja el api
private const val BASE_URL = "https://proyect.com/api/"

interface DataSetService {

    @GET("arch.json")
    fun getAllUser(): Deferred<List<DataSetItem>>
}

//Configuracion de moshi
//parse JSON into Kotlin objects
private val moshi = moshi.Builder()
    .add(KotlinjsonAdapterFactory())
    .build()

object Network {
    //Obtenemos el api http y lo trasnformamos a moshi (kotlin Objects)
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(moshiConverterFactory.create(moshi))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .build()
    val respuestaDataSet = retrofit.create(DataSetService::class.java)
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Java 如何在Kotlin中解析JSON?

Java 如何在Kotlin中解析JSON?

我从服务中接收到非常深的JSON对象字符串,我必须将其解析为JSON对象,然后将其映射到类。

如何在Kotlin中将JSON字符串转换为对象?

在映射到各个类之后,我使用了Jackson的StdDeserializer。当对象具有必须反序列化为类的属性时,就会出现问题。我无法在另一个反序列化器中获取对象映射器,至少我不知道该怎么做。

在此先感谢您的帮助。最好是在本地,我试图减少所需的依赖项数量,因此,如果答案仅是用于JSON操作并且解析就足够了。

答案1

小编典典

您可以使用此库 https://github.com/cbeust/klaxon

Klaxon是一个轻量级的库,用于解析Kotlin中的JSON。

答案2

小编典典

毫无疑问,在Kotlin中进行解析的未来将是kotlinx.serialization。它是Kotlin库的一部分。目前仍处于孵化器编写阶段。

https://github.com/Kotlin/kotlinx.serialization

import kotlinx.serialization.*import kotlinx.serialization.json.JSON@Serializabledata class MyModel(val a: Int, @Optional val b: String = "42")fun main(args: Array<String>) {    // serializing objects    val jsonData = JSON.stringify(MyModel.serializer(), MyModel(42))    println(jsonData) // {"a": 42, "b": "42"}    // serializing lists    val jsonList = JSON.stringify(MyModel.serializer().list, listOf(MyModel(42)))    println(jsonList) // [{"a": 42, "b": "42"}]    // parsing data back    val obj = JSON.parse(MyModel.serializer(), """{"a":42}""")    println(obj) // MyModel(a=42, b="42")}

kotlin - 如何读取 json 数据?

kotlin - 如何读取 json 数据?

如何解决kotlin - 如何读取 json 数据??

我希望我的 android 应用从 Google Sheet 读取数据。 我已经试过了,得到了下面的响应,

{"items":[{"Company":"Tata","Car":"Nexon","Model":"XZ","Price":1400000,"Range":320,"BatterySize": 30},{"Company":"Tata","Model":"XZ+","Price":1500000,"BatterySize":30}]}>

我想做的第一件事是使用像“公司”或其他的键来获取价值。

我还想过滤,只显示价格低于 1500000 的所有商品。

这是我从 URL 获取数据的操作

val url = URL("My_URL")

val client = OkHttpClient()

val request = okhttp3.Request.Builder()
    .url(url)
    .get()
    .build()

val response = client.newCall(request).execute()

val responseBody = response.body!!.string()

val jsonArray = JSONObject(responseBody)
val name = jsonArray.getString("items")

println(name)

It Prints-> [{"Company":"Tata","BatterySize":30 },"BatterySize":30}]

我猜这不是 List 而是 Sting。无法理解如何处理这个字符串。

如果您需要更多信息,请告诉我。

解决方法

您可能想尝试 kotlinx.serialization,它是 Kotlin 语言的一部分。要在您的 Android 项目中使用它(Groovy 语法,如果您在 Gradle 文件中使用 Kotlin DSL,它会略有不同):

  1. 将此添加到您的顶级 build.gradle:classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"

  2. 在您的模块级 build.gradle 中,添加 apply plugin: ''kotlinx-serialization'' 或者如果您使用较新的语法,请将 kotlinx-serialization 添加到您的 plugins {}

要(反)序列化您的数据,请考虑添加以下帮助程序扩展(注意:此示例使用默认的 Json;请参阅下文以了解如何配置您自己的实例):

import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

inline fun <reified T> T.toJson(): String = Json.encodeToString(this)

inline fun <reified T> String.fromJson(): T = Json.decodeFromString(this)

警告:使用默认的Json,如果你的API实际提供的数据与你声明的格式不匹配,你会遇到麻烦,所以你可能需要配置一个Json实例在您的(反)序列化程序中使用(并为您的数据字段分配默认值):

val json = Json {
    ignoreUnknownKeys = true
    coerceInputValues = true
    // more config if needed
}

This article 很好地解释了该配置。

问:我什么时候需要自己配置 Json?
答:如果您确定您的 API 将始终返回您期望的数据,那么您最好使用默认的 API。在所有其他情况下,最好使用自定义配置。

根据您的示例,列表中的单个项目如下所示:

@Serializable
data class Item(
    @SerialName("Company") val company: String,@SerialName("Car") val car: String,@SerialName("Model") val model: String,@SerialName("Price") val price: Float,@SerialName("Range") val range: Int,@SerialName("BatterySize") val batterySize: Int
)

您还需要一个用于解析项目的“持有人”:

@Serializable
data class Items(@SerialName("items") val data: List<Item>)

获取数据的方法如下:

val url = URL("My_URL")
val client = OkHttpClient()
val request = okhttp3.Request.Builder()
    .url(url)
    .get()
    .build()

val response = client.newCall(request).execute()
val items = response.body!!.string().fromJson<Items>().data

我还想过滤并只显示价格所在的所有项目 小于 1500000。

当然,您现在可以对数据应用任何列表操作:

items.filter { it.price < 1500000 }.forEach { item ->
    println("item $item passed the price filter")
}

需要注意的几点:

  • 在 Android 上,考虑使用 Retrofit 进行 API 调用。 Jake Wharton 提供了一个 converter factory,它允许您将 kotlinx.serialization 与 Retrofit 结合使用
  • 避免在生产代码中使用非空断言 (!!),始终使用安全调用 (?) 运算符

Kotlin Gson 解析 Json 对象和数组

Kotlin Gson 解析 Json 对象和数组

如何解决Kotlin Gson 解析 Json 对象和数组?

我对 Kotlin 和 Json 很陌生,在我的工作中,我使用 GSON 来解析 Json。 我需要使用 GSON 将以下 Json 文件解析为一个类。

 {
      "apiKey": "blablabla","baseUrl": "blablabla","requestData": [
        {
          "lng": "6.971","lat": "50.942","rad": "1.5","type": [
                  "diesel","super"
          ]
        },{
          "lng": "6.442","lat": "51.180","type": [
            "diesel",{
          "lng": "7.136","lat": "50.991","super"
          ]
        }
      ]
    }

现在我尝试制作一个这样的数据类:

data class ApiParameterData(
    var apiKey: String? = null,var baseUrl: String? = null,var requestData: String? = null) {

}

我还创建了另一个类来存储 Json 信息,如下所示:

class Tankstelle: JsonDeserializer<ApiParameterData> {
    override fun deserialize(json: JsonElement?,typeOfT: Type?,context: JsonDeserializationContext?
    ): ApiParameterData {
        json as JsonObject

        val apiKey = json.get("apiKey").asstring
        val baseUrl = json.get("baseUrl").asstring
        val requestDataJson = json.get("requestData")
        val requestData = if (requestDataJson.isJsonObject) requestDataJson.asJsonObject.toString() else requestDataJson.toString()

        return ApiParameterData(apiKey,baseUrl,requestData)
    }
}

我试着这样称呼它:

val gsonConfig = GsonBuilder().registerTypeAdapter(ApiParameterData::class.java,Tankstelle()).create()
val tanke = gsonConfig.fromJson(readJson,ApiParameterData::class.java)
println(tanke.requestData?.get(0))

当然,我得到的输出是 "[" 。我想是因为我得到了一个字符串或其他东西,这是它的第一个符号?

我需要遍历 requestData 列表并将其存储为类的实例,并且需要访问每个不同的值。 问题是我想为 Json 文件提供不同的位置和范围,它应该寻找加油站。通过读取 Json,它应该获取所有部分并为我在 requestData 列表中写入的每个位置创建一个链接。所以在这种情况下,我最后需要 3 个不同的链接。但这是我可以自己做的另一部分。我只是不知道如何解析它,以便我可以访问和存储此 Json 中的每个值。

谢谢你,祝你周末愉快!

如果您需要更多信息,请告诉我

解决方法

首先,您需要定义两种映射到您的 JSON 结构的类型

class ApiParameterData(
        val apiKey: String,val baseUrl: String,val requestData: List<RequestObject>
)

class RequestObject(
        val lng: String,val lat: String,val rad: String,val type: List<String>
)

现在简单地将其解析为

val apiData = Gson().fromJson(readJson,ApiParameterData::class.java)     // No need to add TypeAdapter

// To get requestData
val requestData = apiData.requestData
requestData.forEach { 
  print("${it.lng},${it.lat},${it.rad},${it.type})
}

Kotlin 中使用 Hilt 的开发实践

Kotlin 中使用 Hilt 的开发实践

Hilt 是基于 Dagger 开发的全新的依赖项注入代码库,它简化了 Android 应用中 Dagger 的调用方式。本文通过简短的代码片段为您展示其核心功能以帮助开发者们快速入门 Hilt。

配置 Hilt

如需在应用中配置 Hilt,请先参考 Gradle Build Setup。

完成安装全部的依赖和插件以后,仅需在您的 Application 类之前添加 @HiltAndroidApp 注解即可开始使用 Hilt,而无需其它操作。

@HiltAndroidApp
class App : Application()

定义并且注入依赖项

当您写代码用到依赖项注入的时候,有两个要点需要考虑:

  1. 您需要注入依赖项的类;
  2. 可以作为依赖项进行注入的类。

而上述这两点并不互斥,而且在很多情况下,您的类既可以注入依赖项同时也包含依赖。

使依赖项可注入

如果需要在 Hilt 中使某个类变得可注入,您需要告诉 Hilt 如何创建该类的实例。该过程叫做绑定 (bindings)。

在 Hilt 中定义绑定有三种方式:

  1. 在构造函数上添加 @Inject 注解;
  2. 在模块上使用 @Binds 注解;
  3. 在模块上使用 @Provides 注解。

⮕ 在构造函数上使用 @Inject 注解

任何类的构造函数都可以添加 @Inject 注解,这样该类在整个工程中都可以作为依赖进行注入。

class OatMilk @Inject constructor() {
  ...
  }

⮕ 使用模块

在 Hilt 中另外两种将类转为可注入的方法是使用模块。

Hilt 模块 就好像 "菜谱",它可以告诉 Hilt 如何创建那些不具备构造函数的类的实例,比如接口或者系统服务。

此外,在您的测试中,任何模块都可以被其它模块所替代。这有利于使用 mock 替换接口实现。

模块通过 @InstallIn 注解被安装在特定的 Hilt 组件 中。这一部分我会在后面详细介绍。

选项 1: 使用 @Binds 为接口创建绑定

如果您希望在需要 Milk 时候,使用 OatMilk 在代码中取而代之,那么可以在模块中创建一个抽象方法,然后为该方法添加 @Binds 注解。注意 OatMilk 本身必须是可注入的,仅需在 OatMilk 的构造函数上添加 @Inject 注解即可。

interface Milk { ... }

class OatMilk @Inject constructor(): Milk {
  ...
}

@Module
@InstallIn(ActivityComponent::class)
abstract class MilkModule {
  @Binds
  abstract fun bindMilk(oatMilk: OatMilk): Milk
}

选项 2: 使用 @Provides 来创建工厂函数

当实例无法被直接创建,您可以创建一个 provider。provider 就是可以返回对象实例的工厂函数。

一个典型的例子就是系统服务,比如 ConnectivityManager,它们的实例需要通过 Context 对象来返回。

@Module
@InstallIn(ApplicationComponent::class)
object ConnectivityManagerModule {
  @Provides
  fun provideConnectivityManager(
    @ApplicationContext context: Context
  ) = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}

只要使用注解 @ApplicationContext 或者 @ActivityContextContext 对象就是默认可注入的。

注入依赖

当依赖可注入后,您可以使用 Hilt 通过两种方式:

  1. 作为构造函数的参数注入;
  2. 作为字段注入。

⮕ 作为构造函数参数注入

interface Milk { ... }
interface Coffee { ... }

class Latte @Inject constructor(
  private val Milk milk,
  private val Coffee coffee
) {
  ...
}

如果构造函数使用了注解 @Inject,Hilt 会根据您为类型所定义的绑定来注入所有的参数。

⮕ 作为字段注入

interface Milk { ... }
interface Coffee { ... }

@AndroidEntryPoint
class LatteActivity : AppCompatActivity() {
  @Inject lateinit var milk: Milk
  @Inject lateinit var coffee: Coffee

  ...
}

如果类是入口点,这里特指使用了 @AndroidEntryPoint 注解的类 (后面章节会详细介绍),那么该类中所有包含 @Inject 注解的字段均会被注入。

使用 @Inject 注解的字段必须是 public 类型的。也可以添加 lateinit 来避免字段空值,因为它们在注入之前的初始值就是 null

请注意作为字段注入依赖项的场景仅仅适合类必须包含无参构造函数的情况,比如 Activity。在大多数场景下,您更应通过构造函数的参数来注入依赖项。

其它重要的概念

入口点

还记得我在上文里提到,在很多情况下,您的类会在通过依赖注入创建的同时包含被注入的依赖项。有些情况下,您的类可能不是通过依赖项注入来创建,但是仍然会被注入依赖项。一个典型的例子就是 activity,它是由 Android 框架内部创建的,而不是由 Hilt 创建。

这些类属于 Hilt 依赖图谱的 入口点,而且 Hilt 需要知道这些类包含要注入的依赖。

⮕ Android 入口点

大部分入口点是所谓的 Android 入口点:

  • Activity

  • Fragment

  • View

  • Service

  • BroadcastReceiver

如果是 Android 入口点,请添加 @AndroidEntryPoint 注解。

@AndroidEntryPoint
class LatteActivity : AppCompatActivity() {
  ...
}

⮕ 其它入口点

Android 入口点对于大多数应用已经足够,但是如果您使用了不含有 Dagger 的库或者尚未在 Hilt 中支持的 Android 组件,那么您可能需要创建您自己的入口点来手动访问 Hilt 依赖图谱。详情请查看 将任意类转换为入口点。

ViewModel

ViewModel 是一个特例: 因为框架会创建它们,它既不是被直接实例化的,也不是 Android 入口点。ViewModel 需要使用特殊的 @HiltViewModel 注解,当 ViewModel 通过 byViewModels() 创建的时候,该注解使 Hilt 能够向 ViewModel 注入依赖,和其它类的 @Inject 注解的原理相似。

interface Milk { ... }
interface Coffee { ... }

@HiltViewModel
class LatteViewModel @Inject constructor(
  private val milk: Milk,
  private val coffee: Coffee
) : ViewModel() {
  ...
}

@AndroidEntryPoint
class LatteActivity : AppCompatActivity() {
  private val viewModel: LatteViewModel by viewModels()
  ...
}

如果您需要访问 ViewModel 已缓存的状态,可以添加 @Assisted 注解,将 SavedStateHandle 作为构造函数参数进行注入。

@HiltViewModel
class LatteViewModel @Inject constructor(
  @Assisted private val savedState: SavedStateHandle,
  private val milk: Milk,
  private val coffee: Coffee
) : ViewModel() {
  ...
}

要使用 @ViewModelInject,您可能需要添加更多依赖。更多详细内容请详见 Hilt 和 Jetpack 集成指南。

组件

各个模块都是安装在 Hilt 组件 中的,通过 @InstallIn(<组件名>) 指定。模块的组件主要用于防止意外将依赖注入到错误的位置。比如,@InstallIn(ServiceComponent.class) 可以防止注解所修饰的模块中的 binding 和 provider 被 activity 调用。

此外,binding 的作用域会被限制在组件所属的整个模块。也就是接下来我们要讲的...

作用域

默认情况下,绑定都未被限定作用域。正如上面的示例,意味着每次注入 Milk 的时候,您都可以获得一个新的 OatMilk 实例。如果添加了 @ActivityScoped 注解,那么您会将绑定的作用域限制到 ActivityComponent

@Module
@InstallIn(ActivityComponent::class)
abstract class MilkModule {
  @ActivityScoped
  @Binds
  abstract fun bindMilk(oatMilk: OatMilk): Milk
}

现在您的模块被限制作用域了,Hilt 在每个 activity 实例中仅创建一个 OatMilk 实例。此外,OatMilk 实例会绑定到 activity 的生命周期中——当 activity 的 onCreate() 被调用的时候,它会被创建,而当 activity 的 onDestroy() 被调用的时候,它会被销毁。

@AndroidEntryPoint
class LatteActivity : AppCompatActivity() {
  @Inject lateinit var milk: Milk
  @Inject lateinit var moreMilk: Milk //这里的实例和上面的相同

  ...
}

在本例中,milkmoreMilk 指向同一个 OatMilk 实例。然而,如果您有多个 LatteActivity 实例,它们会包含各自的 OatMilk 实例。

相应的,其它被注入到该 activity 的依赖,它们的作用域是一致的。因此它们也会引用到相同的 OatMilk 实例:

// Milk 实例的创建会在 Fridge 存在之前,因为它被绑定到了 activity 的生命周期中
class Fridge @Inject constructor(private val Milk milk) { ... }

@AndroidEntryPoint
class LatteActivity : AppCompatActivity() {
  // 下面四项共享了同一个 Milk 实例
  @Inject lateinit var milk: Milk
  @Inject lateinit var moreMilk: Milk
  @Inject lateinit var fridge: Fridge
  @Inject lateinit var backupFridge: Fridge

  ...
}

作用域依赖于您的模块所安装的组件,比如 @ActivityScoped 仅仅用于在 ActivityComponent 安装的模块内的绑定。

作用域同样决定了注入实例的生命周期: 在本例中,被 FridgeLatteActivity 使用的 Milk 的单独实例会在 LatteActivityonCreate() 被调用的时候被创建——而当 onDestroy() 被调用的时候被销毁。这也意味着当配置发生改变的时候,Milk 不会 "幸免",因为配置发生改变的时候会调用 activity 的 onDestroy()。您可以通过使用生命周期更长的作用域来避免该问题,比如使用 @ActivityRetainedScope

如果想要了解可用的作用域列表、相关的组件以及所遵循的生命周期,请参见 Hilt 组件。

Provider 注入

有些时候您希望能够更加直接地控制注入实例的创建。比如,您可能希望基于业务逻辑,注入某个类型的一个实例或者几个实例。针对这样的场景,您可以使用 dagger.Provider:

class Spices @Inject constructor() { ... }

class Latte @Inject constructor(
  private val spiceProvider: Provider<Spices>
) {
  fun addSpices() {
    val spices = spiceProvider.get()// 创建 Spices 的新实例
    ...
  }
}

provider 注入可以忽略具体的依赖类型以及注入的方式。任何可被注入的内容均可以封装在 Provider<...> 中来使用 provider 注入的方式。

依赖注入框架 (像 Dagger 和 Guice) 通常被用于大型且复杂的项目。而 Hilt 既容易上手,配置起来又非常简单,同时作为独立的代码包,还兼顾了 Dagger 中可被各种类型应用,无论代码规模大小,均可兼容的强大特性。

如果您希望了解更多关于 Hilt 的内容、它的工作原理,以及其它对您来说有用的特性,请移步官方网站,了解更多详细的介绍和参考文档。

今天关于如何在 Kotlin 中使用 moshi 解析 json 本地文件kotlin monad的分享就到这里,希望大家有所收获,若想了解更多关于Java 如何在Kotlin中解析JSON?、kotlin - 如何读取 json 数据?、Kotlin Gson 解析 Json 对象和数组、Kotlin 中使用 Hilt 的开发实践等相关知识,可以在本站进行查询。

本文标签: