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,
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/AliRezaeiii/Contacts

我认为这可能是因为系统GC处理了您的应用程序。当设备内存不足时,可能会出现这种情况。ViewModel只能在配置更改后存活,而不能在应用程序死亡后存活。要解决此问题,需要在savedInstanceState != null时调用ContactsFragment#onCreateView中的loadContacts

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

最新更新