livedata未被正确观察(获取null)

xwbd5t1u  于 2021-06-26  发布在  Java
关注(0)|答案(1)|浏览(419)

我试图更新用户界面,这取决于数据是正在加载还是已经加载,但它不能正常工作。我正在使用 enum 不同州的课程。最初错误是 Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference 然后我通过了一个空的 new MutableLiveData()<> . 现在,它不会使应用程序崩溃,但是getdatastatus()观察器工作不正常。请看一下我的实现,看看它们是否正确。
数据源

public class ArticlesDataSource extends PageKeyedDataSource<Integer, NewsItem> {

    private static final int FIRST_PAGE = 1;
    private static final String TAG = "ArticlesDataSource";
    public static final String SORT_ORDER = "publishedAt";
    public static final String LANGUAGE = "en";
    public static final String API_KEY = Utils.API_KEY;
    public static final int PAGE_SIZE = 10;

    private String mKeyword;
    private MutableLiveData<DataStatus> dataStatusMutableLiveData = new MutableLiveData<>();

    public ArticlesDataSource(String keyword) {
        mKeyword = keyword;
        dataStatusMutableLiveData = new MutableLiveData<>();
    }

    public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
        return dataStatusMutableLiveData;
    }

    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, NewsItem> callback) {
        dataStatusMutableLiveData.postValue(DataStatus.LOADING);
        NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
        Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
        call.enqueue(new Callback<RootJsonData>() {
            @Override
            public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
                if (response.body() != null) {
                    callback.onResult(response.body().getNewsItems(), null, FIRST_PAGE + 1);
                    dataStatusMutableLiveData.postValue(DataStatus.LOADED);
                }
            }

            @Override
            public void onFailure(Call<RootJsonData> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
                dataStatusMutableLiveData.postValue(DataStatus.ERROR);
            }
        });

    }

    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, NewsItem> callback) {
        NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
        Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
        call.enqueue(new Callback<RootJsonData>() {
            @Override
            public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
                // if the current page is greater than one
                // we are decrementing the page number
                // else there is no previous page
                Integer adjacentKey = (params.key > 1) ? params.key - 1 : null;
                if (response.body() != null) {
                    // passing the loaded data
                    // and the previous page key
                    callback.onResult(response.body().getNewsItems(), adjacentKey);
                }
            }

            @Override
            public void onFailure(Call<RootJsonData> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
            }
        });
    }

    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, NewsItem> callback) {
        NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
        Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, params.key, PAGE_SIZE);
        call.enqueue(new Callback<RootJsonData>() {
            @Override
            public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
                dataStatusMutableLiveData.postValue(DataStatus.LOADED);

                if (response.code() == 429) {
                    // no more results
                    List<NewsItem> emptyList = new ArrayList<>();
                    callback.onResult(emptyList, null);
                }

                if (response.body() != null) {
                    // if the response has next page
                    // incrementing the next page number
                    Integer key = params.key + 1;

                    // passing the loaded data and next page value
                    if (!response.body().getNewsItems().isEmpty()) {
                        callback.onResult(response.body().getNewsItems(), key);
                    }
                }
            }

            @Override
            public void onFailure(Call<RootJsonData> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
                dataStatusMutableLiveData.postValue(DataStatus.ERROR);
            }
        });
    }
}

数据源工厂

public class ArticlesDataSourceFactory extends DataSource.Factory {

   private final MutableLiveData<ArticlesDataSource> itemLiveDataSource;
    private String mQuery;
    private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
        return itemDataSource.getDataStatusMutableLiveData();
    });

    public ArticlesDataSourceFactory() {
        mQuery = "news";
        itemLiveDataSource = new MutableLiveData<>();
    }

    @Override
    public DataSource<Integer, NewsItem> create() {
        ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
        itemLiveDataSource.postValue(itemDataSource);
//        dataStatusMutableLiveData = itemDataSource.getDataStatusMutableLiveData();
        return itemDataSource;
    }

    public MutableLiveData<ArticlesDataSource> getArticlesLiveDataSource() {
        return itemLiveDataSource;
    }

    public void setQuery(String query) {
        mQuery = query;
    }

    public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
        return dataStatusMutableLiveData;
    }

    public void setDataStatusMutableLiveData(DataStatus dataStatus){
        dataStatusMutableLiveData.postValue(dataStatus);
    }

    public LiveData<DataStatus> getDataStatusLiveData() {
        return dataStatusLiveData;
    }
}

视图模型

public class ArticlesViewModel extends ViewModel {

    public LiveData<PagedList<NewsItem>> itemPagedList;
    private MutableLiveData<ArticlesDataSource> liveDataSource;
    private ArticlesDataSourceFactory articlesDataSourceFactory;
    private LiveData dataStatus = new MutableLiveData<>();

    public ArticlesViewModel() {

        articlesDataSourceFactory = new ArticlesDataSourceFactory();
        liveDataSource = articlesDataSourceFactory.getArticlesLiveDataSource();
        dataStatus = articlesDataSourceFactory.getDataStatusMutableLiveData();

        PagedList.Config pagedListConfig =
                (new PagedList.Config.Builder())
                        .setEnablePlaceholders(false)
                        .setPageSize(10).build();

        itemPagedList = (new LivePagedListBuilder(articlesDataSourceFactory, pagedListConfig)).build();
    }

    public void setKeyword(String query) {
        if (query.equals("") || query.length() == 0)
            articlesDataSourceFactory.setDataStatusMutableLiveData(DataStatus.EMPTY);
        else {
            articlesDataSourceFactory.setQuery(query);
            refreshData();
        }
    }

    void refreshData() {
        if (itemPagedList.getValue() != null) {
            itemPagedList.getValue().getDataSource().invalidate();
        }
    }

    public LiveData<DataStatus> getDataStatus() {
        return dataStatus;
    }
}

片段

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_articles, container, false);

        mContext = getActivity();
        progressBar = rootView.findViewById(R.id.progress_circular);
        emptyStateTextView = rootView.findViewById(R.id.empty_view);
        swipeRefreshLayout = rootView.findViewById(R.id.swipe_refresh);
        textViewTitle = rootView.findViewById(R.id.text_view_top_headlines);
        recyclerView = rootView.findViewById(R.id.recycler_view);

        if (savedInstanceState != null) {
            keyword = savedInstanceState.getString("keyword");
        }

        initEmptyRecyclerView();

        articlesViewModel = ViewModelProviders.of(this).get(ArticlesViewModel.class);
        articlesViewModel.itemPagedList.observe(getViewLifecycleOwner(), new Observer<PagedList<NewsItem>>() {
            @Override
            public void onChanged(PagedList<NewsItem> newsItems) {
                adapter.submitList(newsItems);
                // TODO: Handle UI changes
                //  handleUIChanges(newsItems);
            }
        });
        articlesViewModel.getDataStatus().observe(getViewLifecycleOwner(), new Observer<DataStatus>() {
            @Override
            public void onChanged(DataStatus dataStatus) {
                switch (dataStatus) {
                    case LOADED:
                        progressBar.setVisibility(View.GONE);
                        emptyStateTextView.setVisibility(View.INVISIBLE);
                        swipeRefreshLayout.setRefreshing(false);
                        textViewTitle.setVisibility(View.VISIBLE);
                        break;
                    case LOADING:
                        progressBar.setVisibility(View.VISIBLE);
                        swipeRefreshLayout.setRefreshing(true);
                        textViewTitle.setVisibility(View.INVISIBLE);
                        emptyStateTextView.setVisibility(View.INVISIBLE);
                        break;
                    case EMPTY:
                        progressBar.setVisibility(View.GONE);
                        swipeRefreshLayout.setRefreshing(false);
                        textViewTitle.setVisibility(View.INVISIBLE);
                        emptyStateTextView.setVisibility(View.VISIBLE);
                        emptyStateTextView.setText(R.string.no_news_found);
                        break;
                    case ERROR:
                        progressBar.setVisibility(View.GONE);
                        swipeRefreshLayout.setRefreshing(false);
                        textViewTitle.setVisibility(View.INVISIBLE);
                        emptyStateTextView.setVisibility(View.VISIBLE);
                        emptyStateTextView.setText(R.string.no_internet_connection);
                        break;
                }
            }
        });

        swipeRefreshLayout.setOnRefreshListener(() -> {
            articlesViewModel.setKeyword(keyword);
        });

        setHasOptionsMenu(true);
        return rootView;
    }

数据状态

public enum DataStatus {

    ERROR,
    LOADING,
    LOADED,
    EMPTY

}
ne5o7dgx

ne5o7dgx1#

当你打电话的时候 invalidate() ,工厂将创建一个新的数据源。但是,您将直接公开“当前”创建的数据源的数据状态livedata,而不考虑将来将创建更多的数据源。
解决方案是将工厂中的当前数据源存储在mutablelivedata中,并使用 switchMap .

public class ArticlesDataSourceFactory extends DataSource.Factory {

    private final MutableLiveData<ArticlesDataSource> itemLiveDataSource = new MutableLiveData<>();
    private String mQuery = "news";
    private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
        return itemDataSource.getDataStatusMutableLiveData();
    });

    public ArticlesDataSourceFactory() {
    }

    @Override
    public DataSource<Integer, NewsItem> create() {
        ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
        itemLiveDataSource.postValue(itemDataSource);
    ...

    public LiveData<DataStatus> getDataStatusLiveData() {
        return dataStatusLiveData;
    }

相关问题