Reputation: 9994
I am loading contacts in SplashActivity :
private fun startMainActivity() {
repository.loadContacts()
handler.postDelayed({
val intent =Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}, SPLASH_DELAY.toLong())
Here is my Repository class :
@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) }
}
}
In my MainFragment onCreateView I observe LiveData in viewModel :
// 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);
}
Here is my ViewModel class :
class ContactsViewModel(repository: ContactsRepository) : ViewModel() {
private val _liveData = repository.liveData
val liveData: LiveData<Resource<List<Contact>>>
get() = _liveData
/**
* 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")
}
}
}
Sometimes when I resume MainFragment after a long time, I face with an empty screen without no data in RecyclerView (Maybe Container Activity is killed by OS for instance). My guess is repository.liveData.value
returns null. It could be any other issue. I appreciate for your suggestions.
Addenda :
@Inject
ContactsViewModel.Factory mFactory;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ContactsViewModel viewModel = new ViewModelProvider(this, mFactory).get(ContactsViewModel.class);
ViewDataBinding binding = FragmentContactsBinding.bind(root);
binding.setVariable(BR.vm, viewModel);
binding.setLifecycleOwner(getViewLifecycleOwner());
}
Full source code is available at : https://github.com/AliRezaeiii/Contacts/blob/master/app/src/main/java/com/sample/android/contact/ui/ContactsFragment.java
Upvotes: 1
Views: 212
Reputation: 9994
I realized that it is due to system initiated process death. As a result I add following line in init method of ViewModel to resolve this issue :
class ContactsViewModel(repository: ContactsRepository) : ViewModel() {
private val _liveData = repository.liveData
val liveData: LiveData<Resource<List<Contact>>>
get() = _liveData
init {
// Reload contacts in case of system initiated process death
if(liveData.value == null) {
repository.loadContacts()
}
}
}
Upvotes: 0