Android, как Parcelable сериализуется / десериализуется, поддерживает ли он ссылку на экземпляр объекта? - PullRequest
0 голосов
/ 26 апреля 2019

Имея фрагмент, он ожидает, что IDataProvider (который является Parcelable) будет передан через аргументы фрагмента и вместе с ним получить данные из хранилища.

это DataFragment, который извлекает dataProvider из аргументов через bundle.getParcelable<Parcelable>(KEY_DATA_PROVIDER) as? IDataProvider

    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 голосов
/ 28 апреля 2019

выглядит как при использовании сгенерированного фрагмента из 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 будет новый экземпляр этого объекта, который больше не будет иметь предыдущую ссылку.

...