为什么新附加的观察者会触发两次 LiveData 观察者 [英] Why LiveData observer is being triggered twice for a newly attached observer
问题描述
我对LiveData
的理解是,它会在数据的当前状态变化上触发观察者,而不是数据的一系列历史状态变化.
My understanding on LiveData
is that, it will trigger observer on the current state change of data, and not a series of history state change of data.
目前,我有一个MainFragment
,它执行Room
写操作,将非垃圾数据更改为垃圾数据.
Currently, I have a MainFragment
, which perform Room
write operation, to change non-trashed data, to trashed data.
我还有另一个TrashFragment
,它观察垃圾数据.
I also another TrashFragment
, which observes to trashed data.
考虑以下场景.
- 目前有 0 个已删除的数据.
MainFragment
是当前的活动片段.TrashFragment
尚未创建.MainFragment
添加了 1 个垃圾数据.- 现在,有 1 个垃圾数据
- 我们使用导航抽屉,将
MainFragment
替换为TrashFragment
. TrashFragment
的观察者将首先收到onChanged
,有 0 个 垃圾数据- 同样,
TrashFragment
的观察者将第二次收到onChanged
,带有 1 个 垃圾数据
- There are currently 0 trashed data.
MainFragment
is the current active fragment.TrashFragment
is not created yet.MainFragment
added 1 trashed data.- Now, there are 1 trashed data
- We use navigation drawer, to replace
MainFragment
withTrashFragment
. TrashFragment
's observer will first receiveonChanged
, with 0 trashed data- Again,
TrashFragment
's observer will secondly receiveonChanged
, with 1 trashed data
出乎我的意料的是,第 (6) 项不应该发生.TrashFragment
应该只接收最新的垃圾数据,即 1.
What is out of my expectation is that, item (6) shouldn't happen. TrashFragment
should only receive latest trashed data, which is 1.
这是我的代码
public class TrashFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
noteViewModel = ViewModelProviders.of(getActivity()).get(NoteViewModel.class);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
noteViewModel.getTrashedNotesLiveData().removeObservers(this);
noteViewModel.getTrashedNotesLiveData().observe(this, notesObserver);
MainFragment.java
public class MainFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
noteViewModel = ViewModelProviders.of(getActivity()).get(NoteViewModel.class);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
noteViewModel.getNotesLiveData().removeObservers(this);
noteViewModel.getNotesLiveData().observe(this, notesObserver);
NoteViewModel .java
public class NoteViewModel extends ViewModel {
private final LiveData<List<Note>> notesLiveData;
private final LiveData<List<Note>> trashedNotesLiveData;
public LiveData<List<Note>> getNotesLiveData() {
return notesLiveData;
}
public LiveData<List<Note>> getTrashedNotesLiveData() {
return trashedNotesLiveData;
}
public NoteViewModel() {
notesLiveData = NoteplusRoomDatabase.instance().noteDao().getNotes();
trashedNotesLiveData = NoteplusRoomDatabase.instance().noteDao().getTrashedNotes();
}
}
<小时>
处理房间的代码
public enum NoteRepository {
INSTANCE;
public LiveData<List<Note>> getTrashedNotes() {
NoteDao noteDao = NoteplusRoomDatabase.instance().noteDao();
return noteDao.getTrashedNotes();
}
public LiveData<List<Note>> getNotes() {
NoteDao noteDao = NoteplusRoomDatabase.instance().noteDao();
return noteDao.getNotes();
}
}
@Dao
public abstract class NoteDao {
@Transaction
@Query("SELECT * FROM note where trashed = 0")
public abstract LiveData<List<Note>> getNotes();
@Transaction
@Query("SELECT * FROM note where trashed = 1")
public abstract LiveData<List<Note>> getTrashedNotes();
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract long insert(Note note);
}
@Database(
entities = {Note.class},
version = 1
)
public abstract class NoteplusRoomDatabase extends RoomDatabase {
private volatile static NoteplusRoomDatabase INSTANCE;
private static final String NAME = "noteplus";
public abstract NoteDao noteDao();
public static NoteplusRoomDatabase instance() {
if (INSTANCE == null) {
synchronized (NoteplusRoomDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
NoteplusApplication.instance(),
NoteplusRoomDatabase.class,
NAME
).build();
}
}
}
return INSTANCE;
}
}
知道如何防止针对相同数据接收两次 onChanged
吗?
Any idea how I can prevent from receiving onChanged
twice, for a same data?
我创建了一个演示项目来演示这个问题.
I created a demo project to demonstrate this problem.
如你所见,当我在MainFragment
中执行写操作(点击ADD TRASHED NOTE按钮)后,当我切换到TrashFragment
,我希望 TrashFragment
中的 onChanged
只会被调用一次.但是,它被调用了两次.
As you can see, after I perform write operation (Click on ADD TRASHED NOTE button) in MainFragment
, when I switch to TrashFragment
, I expect onChanged
in TrashFragment
will only be called once. However, it is being called twice.
Demo项目可以从https://github.com/yccheok/live-data-下载问题
推荐答案
我分叉了您的项目并对其进行了一些测试.据我所知,你发现了一个严重的错误.
I forked your project and tested it a bit. From all I can tell you discovered a serious bug.
为了使复制和调查更容易,我对您的项目进行了一些编辑.你可以在这里找到更新的项目:https://github.com/techyourchance/live-data-problem .我还向您的 repo 发起了拉取请求.
To make the reproduction and the investigation easier, I edited your project a bit. You can find updated project here: https://github.com/techyourchance/live-data-problem . I also opened a pull request back to your repo.
为了确保不会被忽视,我还在 Google 的打开了一个问题问题跟踪器:
To make sure that this doesn't go unnoticed, I also opened an issue in Google's issue tracker:
重现步骤:
- 确保在 MainFragment 中将 REPRODUCE_BUG 设置为 true
- 安装应用
- 点击添加垃圾笔记"按钮
- 切换到 TrashFragment
- 请注意,只有一个通知表单 LiveData 具有正确的值
- 切换到 MainFragment
- 点击添加垃圾笔记"按钮
- 切换到 TrashFragment
- 请注意,LiveData 有两个通知,第一个通知的值不正确
请注意,如果您将 REPRODUCE_BUG 设置为 false,则该错误不会复制.它表明订阅 LiveData 在MainFragment 改变了 TrashFragment 中的行为.
Note that if you set REPRODUCE_BUG to false then the bug doesn't reproduce. It demonstrates that subscription to LiveData in MainFragment changed the behavior in TrashFragment.
预期结果:在任何情况下都只有一个具有正确值的通知.由于以前的订阅,行为没有变化.
Expected result: Just one notification with correct value in any case. No change in behavior due to previous subscriptions.
更多信息:我查看了一些来源,看起来像由于 LiveData 激活和新的激活而触发的通知观察员订阅.可能与 ComputableLiveData 的方式有关将 onActive() 计算卸载到 Executor.
More info: I looked at the sources a bit, and it looks like notifications being triggered due to both LiveData activation and new Observer subscription. Might be related to the way ComputableLiveData offloads onActive() computation to Executor.
这篇关于为什么新附加的观察者会触发两次 LiveData 观察者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!