Android Java ViewModel with Dagger 2

2019-08-19 07:00发布

问题:

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..