I'm trying to use viewmodel with dagger 2.
However, on orientation change, ViewModel
is being recreated. I get SwipeRefreshLayout
NullPointerException
on featuredViewModel.getLoading.observe()
.
Where is my fail?
Dagger 2 Fragment Module (ContributesAndroidInjector)
@Module(includes = {ApplicationModule.class, PicassoModule.class})
public class FeaturedProjectsModule {
@Provides
FeaturedViewModel provideMainViewModel(FeaturedProjectsFragment fragment, ViewModelProvider.Factory factory) {
return ViewModelProviders.of(fragment, factory).get(FeaturedViewModel.class);
}
@Provides
ViewModelProvider.Factory featuredProjectsViewModelProvider() {
return new ViewModelFactory<>(new FeaturedViewModel());
}
@Provides
FeaturedProjectsAdapter provideFeaturedProjectsAdapter(Picasso picasso) {
return new FeaturedProjectsAdapter(picasso);
}
}
ViewModel Fragment
public class FeaturedViewModel extends ViewModel {
private CompositeDisposable disposable;
private final MutableLiveData<ProjectResponse> featuredProjects = new MutableLiveData<>();
private final MutableLiveData<Boolean> loading = new MutableLiveData<>();
private int pages = 1;
private int page = 1;
LiveData<ProjectResponse> getFeaturedProjects() {
return featuredProjects;
}
LiveData<Boolean> getLoading() {
return loading;
}
FeaturedViewModel() {
disposable = new CompositeDisposable();
}
public void loadFeaturedProjects(PrefUtils prefUtils, RestRepository restRepository) {
if(page <= pages) {
disposable.add(restRepository.getFeaturedProjects(prefUtils.getSavedAuthData().getAccessToken(), page).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribeWith(new DisposableSingleObserver<ProjectResponse>() {
@Override
public void onSuccess(ProjectResponse value) {
page++;
pages = value.getMeta().getTotalPages();
featuredProjects.setValue(value);
loading.setValue(false);
}
@Override
public void onError(Throwable e) {
loading.setValue(false);
}
}));
}
}
public void resetPage() {
page = 1;
}
@Override
protected void onCleared() {
super.onCleared();
if (disposable != null) {
disposable.clear();
disposable = null;
}
}
}
Fragment
public class FeaturedProjectsFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener {
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@Inject PrefUtils prefUtils;
@Inject RestRepository restRepository;
@Inject FeaturedProjectsAdapter adapter;
@Inject FeaturedViewModel featuredViewModel;
@Override
protected int layoutRes() {
return R.layout.fragment_featured_projects;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
swipeRefreshLayout.setColorSchemeColors(getBaseActivity().getResources().getColor(R.color.colorPrimaryText));
swipeRefreshLayout.setOnRefreshListener(this);
setupRecyclerView();
featuredViewModel.getLoading().observe(getBaseActivity(), loading -> {
Log.d(Constants.TAG, "REFRESH");
swipeRefreshLayout.setRefreshing(loading == null ? false : loading);
});
featuredViewModel.getFeaturedProjects().observe(getBaseActivity(), response -> {
if (response != null) {
if(response.getMeta().getCurrentPage() == 1)
adapter.clearData();
adapter.addAllData(response.getRecords());
}
});
loadFeaturedProjects();
}
private void loadFeaturedProjects() {
featuredViewModel.loadFeaturedProjects(prefUtils, restRepository);
}
@Override
public void onRefresh() {
featuredViewModel.resetPage();
loadFeaturedProjects();
}
private void setupRecyclerView() {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if(!recyclerView.canScrollVertically(1)) {
loadFeaturedProjects();
}
}
});
recyclerView.setAdapter(adapter);
}
}
Edit: I'm injecting like that
@Module
public abstract class MainFragmentBindingModule {
@ContributesAndroidInjector(modules = {ApplicationModule.class, UtilsModule.class,
RestServiceModule.class, PicassoModule.class, FeaturedProjectsModule.class})
abstract FeaturedProjectsFragment provideFeaturedProjectsFragmentFactory();
}
Thank you..