【问题标题】:LiveData not triggering twice in case of network request failing如果网络请求失败,LiveData 不会触发两次
【发布时间】:2018-09-07 13:45:05
【问题描述】:

当我的 httprequest 成功时,我的 LiveData 对象被调用了两次,但如果出现错误,它只被调用一次,导致 UI 显示一个空列表,因为我的 Error 验证被跳过,因为没有警报被解雇了。

我的仓库代码

private LiveData<List<Card>> getCards() {
    return cardsDao.getCards();
}

// Network request, that deals with the success or error of the request

public LiveData<DataWrapper<List<Card>>> loadCards() {
    AtomicReference<LiveData<DataWrapper<List<Card>>>> atomicWrapper = new AtomicReference<>();
    if (getCards().getValue() == null) {
        webService.getCards(result -> {
            CardResponse res = (CardResponse) result;
            List<Card> cardList = res.getCardsList();
            getInsertAsyncTask.execute(cardList.toArray(new Card[cardList.size()]));
        }, error -> {
            atomicWrapper.set(asLiveData(null, error.getMessage()));
        }, TAG);
    }
    atomicWrapper.set(asLiveData(getCards(),null));
    return atomicWrapper.get();
}

我的 BaseRepository 代码

LiveData<DataWrapper<List<T>>> asLiveData(LiveData<List<T>> dataSource, String error) {
    MediatorLiveData<DataWrapper<List<T>>> mediatorLiveData = new MediatorLiveData<>();
    mediatorLiveData.addSource(dataSource, data -> mediatorLiveData.setValue(new DataWrapper<>(data, error)));
    return mediatorLiveData;
}

我的片段代码

private void subscribeToCards() {
    mViewModel.getCards().observe(this, listDataWrapper -> {
        if( listDataWrapper == null ) {
            return;
        }

        if( listDataWrapper.error != null) {
            // Show error on UI
            dismissProgress();
            Log.e(TAG, "Error - " + listDataWrapper.error);
            showError(getString(R.string.cards_error_get_list_message));
            EventBus.getDefault().post(new DialogMessageEvent(getString(R.string.cards_error_get_list_title),
                getString(R.string.cards_error_get_list_message), getString(R.string.cards_error_get_list_button)));
        }

        if( listDataWrapper.data != null ) {
            // Update Ui
            refreshCardsList(listDataWrapper.data);
            cardsViewVisibility(true);
        }
    });
}

最后,我的 ViewModel 代码

public LiveData<DataWrapper<List<Card>>> getCards(){
    return repository.loadCards();
}

总而言之,在失败的情况下,为什么observer callback 只被调用一次?因为我已经调试了它,并且在两种情况下(成功和失败),方法asLiveData被称为TWICE,但只有在成功的尝试中回调也被称为TWICE,失败时observer callback它只被调用一次。

编辑:添加异步任务代码

@SuppressLint("StaticFieldLeak")
AsyncTask<T,Void,Void> getInsertAsyncTask = new AsyncTask<T, Void, Void>() {
    @Override
    protected Void doInBackground(T... ts) {
        daoObject.insertObjects(Arrays.asList(ts));
        return null;
    }
};

【问题讨论】:

  • getInsertAsyncTask 是什么样的?
  • @Chris 添加到帖子中。正如我所说,它似乎工作正常,当我获得卡片列表时,我的成功案例效果很好

标签: android android-livedata mutablelivedata


【解决方案1】:

您在成功案例中获得 2 次回调,而在错误场景中只有 1 次调用的原因看起来与您的存储库设置有关。

调用 loadCards 时,您首先通过此调用发出数据库的状态:

atomicWrapper.set(asLiveData(getCards(),null));

此时将查询您的数据库,当前值将触发 mediatorLiveData.setValue。这将是第一个发射。

mediatorLiveData.addSource(dataSource, data -> mediatorLiveData.setValue(new DataWrapper<>(data, error)));

同时你触发了对你的webservice的调用,如果成功将触发你的asynctask更新数据库。

webService.getCards(result -> {
    CardResponse res = (CardResponse) result;
    List<Card> cardList = res.getCardsList();
    getInsertAsyncTask.execute(cardList.toArray(new Card[cardList.size()]));
}, error -> {
    atomicWrapper.set(asLiveData(null, error.getMessage()));
}, TAG);

一旦插入命令完成,MediatorLiveData 将再次触发它的 setValue 调用 - 它正在侦听数据库中的更改,因此在插入时它将收到回调。这是成功案例中的第二次发射。

在错误场景中,您通过 null 作为数据源。令人惊讶的是,由于 addSource 方法将源参数标记为 Non Null,因此它不会崩溃。由于它为 null,因此您不会收到回调,并且不会调用 mediatorLiveData.setValue。这意味着对于错误场景,您只会收到第一个发射。

如果您执行以下操作可能会更简单:

  • 在数据库上设置一个监听器,并在数据库更新发生时发出您的数据值而不会出现错误。

  • 收到错误后,您可以发出带有错误的 DataWrapper

例如类似:

    private final AtomicBoolean isLoading = new AtomicBoolean(false);
    private final MediatorLiveData<DataWrapper<List<Card>>> mediatorLiveData = new MediatorLiveData<>();

    private MyRepository() {
        // requires a cardsDao
        // listen for DB changes and emit on callback
        mediatorLiveData.addSource(cardsDao.getCards(), data -> mediatorLiveData.setValue(new DataWrapper<>(data, null)));
    }

    public LiveData<DataWrapper<List<Card>>> cardsData() {
        return mediatorLiveData;
    }

    public void loadCards() {
        if (!isLoading.get()) {
            isLoading.set(true);
            webService.getCards(result -> {
                CardResponse res = (CardResponse) result;
                List<Card> cardList = res.getCardsList();
                // Trigger update in db
                getInsertAsyncTask.execute(cardList.toArray(new Card[cardList.size()]));
                isLoading.set(false);
            }, error -> {
                // Emit the error
                mediatorLiveData.setValue(new DataWrapper<>(null, error.getMessage()));
                isLoading.set(false);
            }, TAG);
        }
    }

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 2020-04-09
  • 2019-01-06
  • 2018-06-11
相关资源
最近更新 更多