0

I'm trying to use SharedPreference and error occur when i load data. I think the problem is that my data class include MutableList, but i don't know how to handle it.

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()
}

Above is part of my functions in main activity.

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

This is my data class "Album"

When i first open the app, it save data well and no error occur.
But when i close the app and open it again, the error occur in process of loading data
This is part of my log of "Log_show" and "data load 3" didn't appear

2020-11-04 23:12:33.418 15720-15720/kr.co.ddophi.autochangingwallpaper D/log: data load 1
2020-11-04 23:12:33.420 15720-15720/kr.co.ddophi.autochangingwallpaper D/log: data load 2

the full log is like this

2020-11-05 14:48:19.319 6956-6956/kr.co.ddophi.autochangingwallpaper D/Log_show: data load 1 2020-11-05 14:48:19.321 6956-6956/kr.co.ddophi.autochangingwallpaper D/Log_show: data load 2 2020-11-05 14:48:19.331 6956-6956/kr.co.ddophi.autochangingwallpaper D/AndroidRuntime: Shutting down VM 2020-11-05 14:48:19.336 6956-6956/kr.co.ddophi.autochangingwallpaper E/AndroidRuntime: FATAL EXCEPTION: main Process: kr.co.ddophi.autochangingwallpaper, PID: 6956 java.lang.RuntimeException: Unable to start activity ComponentInfo{kr.co.ddophi.autochangingwallpaper/kr.co.ddophi.autochangingwallpaper.MainActivity}: java.lang.RuntimeException: Failed to invoke private android.net.Uri() with no args at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6944) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) Caused by: java.lang.RuntimeException: Failed to invoke private android.net.Uri() with no args at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:113) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at com.google.gson.Gson.fromJson(Gson.java:927) at com.google.gson.Gson.fromJson(Gson.java:892) at com.google.gson.Gson.fromJson(Gson.java:841) at kr.co.ddophi.autochangingwallpaper.MainActivity.loadData(MainActivity.kt:174) at kr.co.ddophi.autochangingwallpaper.MainActivity.onCreate(MainActivity.kt:43) at android.app.Activity.performCreate(Activity.java:7183) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6944)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)  Caused by: java.lang.InstantiationException: Can't instantiate abstract class android.net.Uri at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:334) at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:110) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)  at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)  at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)  at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)  at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)  at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)  at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)  at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)  at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)  at com.google.gson.Gson.fromJson(Gson.java:927)  at com.google.gson.Gson.fromJson(Gson.java:892)  at com.google.gson.Gson.fromJson(Gson.java:841)  at kr.co.ddophi.autochangingwallpaper.MainActivity.loadData(MainActivity.kt:174)  at kr.co.ddophi.autochangingwallpaper.MainActivity.onCreate(MainActivity.kt:43)  at android.app.Activity.performCreate(Activity.java:7183)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6944)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 

Any help would be appreciated
Thank you

Ddophi
  • 1
  • 1
  • Please in general include code snippets as code blocks instead of including only screenshots. Additionally could you please include the exact exception message and stack trace please? – Marcono1234 Nov 04 '20 at 21:02
  • Thanks for comment. I edit main text and add log message. – Ddophi Nov 05 '20 at 06:14
  • Similar to https://stackoverflow.com/q/46031104; Gson cannot create an instance of URI because it is an `abstract` class. You could either switch to `String` or write a [`TypeAdapter`](https://www.javadoc.io/doc/com.google.code.gson/gson/2.8.6/com.google.gson/com/google/gson/TypeAdapter.html) which uses `URI.toString()` and `URI.parse(...)`. I can provide an example, but only in Java (maybe it is helpful nonetheless). – Marcono1234 Nov 05 '20 at 13:59
  • Oh, that's nice idea. I'll try that method. Thank you very much! – Ddophi Nov 06 '20 at 14:37

1 Answers1

1

You should custom TypeAdapter for serialize and deserialize 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
            }
        }
    }
}

and setup Gson like this:

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