Android,如何将Parcelable序列化/反序列化,它是否维护对对象实例的引用?

时间:2019-04-26 13:11:00

标签: android parcelable

有一个片段,它期望通过该片段的参数传递一个IDataProvider(可打包),并与之一起从存储库中获取数据。

这是DataFragment,它通过bundle.getParcelable<Parcelable>(KEY_DATA_PROVIDER) as? IDataProvider从参数中检索dataProvider

    class DataFragment: Fragment() {

        interface IDataProvider : Parcelable {
            fun getDataByUUID(uuid: String): IData?
        }

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            //retainInstance = true

            var bundle = arguments
            var dataProvider: IDataProvider = bundle.getParcelable<Parcelable>(KEY_DATA_PROVIDER) as? IDataProvider

            // the provider is got from bundle.getParcelable
            // and would expect the `IDataRepository` reference kept 
            // in the dataProvider should be lost in the 
            // serialize/deserialize of the Parcelable
            // but it does not, and it is still working to be able to make the call and return the data from the repository

            val data: Data = dataProvider?.getDataByUUID("xxx-yyy-zzz")

            // the data is returned fine (???)
                    ......

        }

        ... ...
    }

这是活动,它将IDataProvider放在DataFragment实例的参数中 通过Bundle().putParcelable(KEY_DATA_PROVIDER, dataProvider)

    class DataActivity: Activity {

        var dataProvider: DataProvider? = null

        val viewModel = getViewModel()  //get the viewModel which has the dataRepository

        fun createFragment(): Fragment? {

            dataProvider = DataProvider()
            dataProvider?.let {
                dataProvider.repository = viewModel?.getDataRepository()

                val args = Bundle()
                args.putParcelable(KEY_DATA_PROVIDER, dataProvider)  //put the dataProvider in the Bundle with putParcelable

                var dataFragment = DataFragment()
                dataFragment.arguments = args  // set to its arguments
                return contentFragment
            }
            return null
        }

        override fun onDestroy() {
            super.onDestroy()

            dataProvider?.repository = null
        }


        // DataProvider implementation, 
        // it has a reference to a IDataRepository
        // but is not serialized/deserialized when it is parceling

        private var dataProvider: DataProvider? = null
        class DataProvider() : DataFragment.IDataProvider {

            var repository: IDataRepository? = null
            override fun getDataByUUID(uuid: String): IData? {
                return repository?.getData(uuid)
            }

            constructor(parcel: Parcel) : this() {}
            override fun writeToParcel(parcel: Parcel, flags: Int) {}
            override fun describeContents(): Int {
                return 0
            }

            companion object CREATOR : Parcelable.Creator<DataProvider> {
                override fun createFromParcel(parcel: Parcel): DataProvider {
                    return ContentProvider(parcel)
                }

                override fun newArray(size: Int): Array<DataProvider?> {
                    return arrayOfNulls(size)
                }
            }
        }
    }

如果采用上述实现,则可以预期repository中的成员变量class DataProvider() : DataFragment.IDataProvider 应该丢失,因为writeToParcel()/ readFromParcel()中没有要序列化/反序列化的代码。

但是运行时,似乎在片段中将其从包中打包回来时,成员变量repository仍然有效。

有人知道为什么,或者如何对Parcelable进行序列化/反序列化吗?

1 个答案:

答案 0 :(得分:0)

看起来是否使用从createFragment()生成的片段

fun createFragment(): Fragment? {

        dataProvider = DataProvider()
        dataProvider?.let {
            dataProvider.repository = viewModel?.getDataRepository()

            val args = Bundle()
            args.putParcelable(KEY_DATA_PROVIDER, dataProvider)  //put the dataProvider in the Bundle with putParcelable

            var dataFragment = DataFragment()
            dataFragment.arguments = args  // set to its arguments
            return contentFragment
        }
        return null
    }

然后做

var bundle = createFragment().arguments
var dataProvider: IDataProvider = bundle.getParcelable<Parcelable>(KEY_DATA_PROVIDER) as? IDataProvider

该捆绑包仍然具有包含的可包裹物品的相同实例,因此它仍然有效。

但是在像os杀死并恢复该片段的情况下,来自新片段arguments的可打包文件将具有该可打包文件的新实例,并且将不再具有先前的引用。