有时过后恢复应用程序时,repository.liveData.value返回null

问题描述

我正在SplashActivity的“存储库”层中加载联系人:

@Inject
lateinit var repository: ContactsRepository

private fun startMainActivity() {
        repository.loadContacts()
        handler.postDelayed({
            val intent =Intent(this,MainActivity::class.java)
            startActivity(intent)
            finish()
        },SPLASH_DELAY.toLong())
    }

这是我的存储库:

@Singleton
class ContactsRepository @Inject constructor(
        private val context: Context,private val schedulerProvider: BaseSchedulerProvider) {

    private val compositedisposable = Compositedisposable()

    private val _liveData = mutablelivedata<Resource<List<Contact>>>()
    val liveData: LiveData<Resource<List<Contact>>>
        get() = _liveData

    fun loadContacts() {
        _liveData.value = Resource.Loading()
        val cursor = context.contentResolver.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,PROJECTION,null,ContactsContract.CommonDataKinds.Phone.disPLAY_NAME + " COLLATE UNICODE ASC")
        Observable.create(ObservableOnSubscribe<List<Contact>>
        { emitter -> emitter.onNext(ContactUtil.getContacts(cursor,context)) })
                .subscribeOn(schedulerProvider.io())
                .doOnComplete { cursor?.close() }
                .doFinally { compositedisposable.clear() }
                .subscribe {
                    _liveData.postValue(Resource.Success(it))
                }.also { compositedisposable.add(it) }
    }
}

在我的ContactsFragment中,我初始化了viewmodel:

    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
        Log.d(TAG,"onCreateView()");
        View root = inflater.inflate(R.layout.fragment_contacts,container,false);
        Contactsviewmodel viewmodel = new viewmodelProvider(this,mFactory).get(Contactsviewmodel.class);
        FragmentContactsBinding binding = FragmentContactsBinding.bind(root);
        binding.setvariable(BR.vm,viewmodel);
        binding.setLifecycleOwner(getViewLifecycleOwner());

            // Create the observer which updates the UI.
            final Observer<Resource<List<Contact>>> contactsObserver = resource -> {
                if (resource instanceof Resource.Success) {
                    mContacts = ((Resource.Success<List<Contact>>) resource).getData();
                    mAdapter.setItems(mContacts,true);
                }
            };
            // Observe the LiveData,passing in this fragment as the LifecycleOwner and the observer.
            viewmodel.getLiveData().observe(this,contactsObserver);
}

这是我的viewmodel:

class Contactsviewmodel(repository: ContactsRepository) : viewmodel() {

    private val _liveData = repository.liveData
    val liveData: LiveData<Resource<List<Contact>>>
        get() = _liveData

    init {
        if(repository.liveData.value == null) {
            repository.loadContacts()
        }
    }

    /**
     * Factory for constructing Contactsviewmodel with parameter
     */
    class Factory @Inject constructor(
            private val repository: ContactsRepository
    ) : viewmodelProvider.Factory {
        override fun <T : viewmodel?> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(Contactsviewmodel::class.java)) {
                @Suppress("UNCHECKED_CAST")
                return Contactsviewmodel(repository) as T
            }
            throw IllegalArgumentException("Unable to construct viewmodel")
        }
    }
}

如您所见,有时我在很长一段时间后恢复应用程序时,“ repository.liveData.value”返回null,结果我在viewmodel中具有以下逻辑:

init {
        if(repository.liveData.value == null) {
            repository.loadContacts()
        }
    }

有更好的解决方案吗?

可以找到完整的源代码https://github.com/Ali-Rezaei/Contacts

解决方法

我认为这可能会发生,因为系统对您的应用程序进行了GC。当设备内存不足时,可能会发生这种情况。 ViewModel将仅在配置更改后幸存,而不会在应用程序终止后幸存。要解决此问题,您需要在loadContacts时在ContactsFragment#onCreateView中调用savedInstanceState != null

,

ViewModels无法幸免于系统启动的进程死亡。要解决此问题,您需要使用SavedStateHandle:

https://developer.android.com/reference/androidx/lifecycle/SavedStateHandle

例如,在下面链接的FilterViewModel中,我使用SavedStateHandle存储一组索引,并在SavedStateHandle不为null的情况下检索它们(仅在系统启动的情况下才为非null)死亡):

https://github.com/gavingt/upcoming-games/blob/master/app/src/main/java/com/gavinsappcreations/upcominggames/ui/filter/FilterViewModel.kt