【问题标题】:How to load data class that include MutableList<Uri> from SharedPreference?如何从 SharedPreference 加载包含 MutableList<Uri> 的数据类?
【发布时间】:2021-02-17 06:22:30
【问题描述】:

我正在尝试使用 SharedPreference,但在加载数据时出现错误。我认为问题是我的数据类包含MutableList,但我不知道如何处理。

private lateinit var albumData:MutableList<Album>

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

    loadData()

    connectAdapter()

    btnAddAlbum.setOnClickListener {
        if(isStoragePermitted()) {
            openGallery()
        }
    }
}

fun saveData() {
    val sharedPreferences = getSharedPreferences("shared preferences", Context.MODE_PRIVATE)
    val editor = sharedPreferences.edit()
    val gson = GsonBuilder().create()
    val json = gson.toJson(albumData)
    editor.putString("Album data", json)
    editor.apply()
}

fun loadData() {
    val sharedPreferences = getSharedPreferences("shared preferences", Context.MODE_PRIVATE)
    val gson = GsonBuilder().create()
    val json = sharedPreferences.getString("Album data", null)
    var test = mutableListOf<Album>()
    if(json != null) {
        Log.d("Log_show", "data load 1")
        val type = object : TypeToken<MutableList<Album>>() {}.type
        Log.d("Log_show", "data load 2")
        albumData = gson.fromJson<MutableList<Album>>(json, type)
        Log.d("Log_show", "data load 3")
    }else{
        albumData =  mutableListOf()
    }
}

override fun onDestroy() {
    saveData()
    Log.d("Log_show", "shut down")
    super.onDestroy()
}

以上是我在主要活动中的部分功能。

data class Album (
    var albumImages : MutableList<Uri>,
    var albumTitle : String,
    var pictureCount : Int
)

这是我的数据类“相册”

当我第一次打开应用程序时,它很好地保存了数据并且没有发生错误。
但是当我关闭应用程序并再次打开它时,在加载数据的过程中出现错误
这是我的“Log_show”日志的一部分,“data load 3”没有出现

2020-11-04 23:12:33.418 15720-15720/kr.co.ddophi.autochangingwallpaper D/log:数据加载 1
2020-11-04 23:12:33.420 15720-15720/kr.co.ddophi.autochangingwallpaper D/log: 数据加载 2

完整的日志是这样的

2020-11-05 14:48:19.319 6956-6956/kr.co.ddophi.autochangingwallpaper D/Log_show: 数据加载 1 2020-11-05 14:48:19.321 6956-6956/kr.co.ddophi.autochangingwallpaper D/Log_show: 数据加载 2 2020-11-05 14:48:19.331 6956-6956/kr.co.ddophi.autochangingwallpaper D/AndroidRuntime: 关闭虚拟机 2020-11-05 14:48:19.336 6956-6956/kr.co.ddophi.autochangingwallpaper E/AndroidRuntime: FATAL EXCEPTION: main 进程:kr.co.ddophi.autochangingwallpaper,PID:6956 java.lang.RuntimeException:无法启动活动 ComponentInfo{kr.co.ddophi.autochangingwallpaper/kr.co.ddophi.autochargingwallpaper.MainActivity}:java.lang.RuntimeException:无法调用私有 android.net.Uri() 没有参数 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) 在 android.app.ActivityThread.-wrap11(未知来源:0) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) 在 android.os.Handler.dispatchMessage(Handler.java:105) 在 android.os.Looper.loop(Looper.java:164) 在 android.app.ActivityThread.main(ActivityThread.java:6944) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 原因:java.lang.RuntimeException:无法调用没有参数的私有 android.net.Uri() 在 com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:113) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212) 在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) 在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 在 com.google.gson.Gson.fromJson(Gson.java:927) 在 com.google.gson.Gson.fromJson(Gson.java:892) 在 com.google.gson.Gson.fromJson(Gson.java:841) 在 kr.co.ddophi.autochangingwallpaper.MainActivity.loadData(MainActivity.kt:174) 在 kr.co.ddophi.autochangingwallpaper.MainActivity.onCreate(MainActivity.kt:43) 在 android.app.Activity.performCreate(Activity.java:7183) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) 在 android.app.ActivityThread.-wrap11(未知来源:0) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) 在 android.os.Handler.dispatchMessage(Handler.java:105) 在 android.os.Looper.loop(Looper.java:164) 在 android.app.ActivityThread.main(ActivityThread.java:6944) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 引起:java.lang.InstantiationException:无法实例化抽象类android.net.Uri 在 java.lang.reflect.Constructor.newInstance0(本机方法) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:334) 在 com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:110) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212) 在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) 在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) 在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 在 com.google.gson.Gson.fromJson(Gson.java:927) 在 com.google.gson.Gson.fromJson(Gson.java:892) 在 com.google.gson.Gson.fromJson(Gson.java:841) 在 kr.co.ddophi.autochangingwallpaper.MainActivity.loadData(MainActivity.kt:174) 在 kr.co.ddophi.autochangingwallpaper.MainActivity.onCreate(MainActivity.kt:43) 在 android.app.Activity.performCreate(Activity.java:7183) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) 在 android.app.ActivityThread.-wrap11(未知来源:0) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) 在 android.os.Handler.dispatchMessage(Handler.java:105) 在 android.os.Looper.loop(Looper.java:164) 在 android.app.ActivityThread.main(ActivityThread.java:6944) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

任何帮助将不胜感激
谢谢

【问题讨论】:

  • 请通常将代码 sn-ps 包含为代码块,而不是仅包含屏幕截图。另外,请您包括确切的异常消息和堆栈跟踪吗?
  • 感谢您的评论。我编辑正文并添加日志消息。
  • 类似于stackoverflow.com/q/46031104; Gson 无法创建 URI 的实例,因为它是 abstract 类。您可以切换到String 或编写一个使用URI.toString()URI.parse(...)TypeAdapter。我可以提供一个示例,但仅限于 Java(尽管它可能会有所帮助)。
  • 哦,这是个好主意。我会试试那个方法。非常感谢!

标签: json kotlin gson sharedpreferences


【解决方案1】:

您应该自定义 TypeAdapter 以对 Uri 进行序列化和反序列化。

class UriTypeAdapter : TypeAdapter<Uri>() {
    override fun write(out: JsonWriter?, value: Uri?) {
        value?.let {
            out?.value(it.toString())
        } ?: run {
            out?.nullValue()
        }
    }

    override fun read(reader: JsonReader?): Uri {
        return if (reader?.peek() == JsonToken.NULL) {
            reader.nextNull()
            Uri.EMPTY
        } else {
            val uriString = reader?.nextString()
            uriString?.let {
                Uri.parse(it)
            } ?: run {
                Uri.EMPTY
            }
        }
    }
}

并像这样设置 Gson:

val gson = GsonBuilder()
    .registerTypeHierarchyAdapter(Uri::class.java, UriTypeAdapter())
    .create()

【讨论】:

  • 感谢您的详细解释。我会有用的!
猜你喜欢
  • 2013-11-15
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 2011-04-25
相关资源
最近更新 更多