Ali
Ali

Reputation: 9994

Empty screen when Activity recreated

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

Answers (1)

Ali
Ali

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

Related Questions