为什么为新连接的观察者两次触发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.
演示项目可以从 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 .我还打开了一个拉回请求到您的仓库.
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:
复制步骤:
Steps to reproduce:
- 确保在MainFragment中将REPRODUCE_BUG设置为true
- 安装应用
- 单击添加垃圾便笺"按钮
- 切换到TrashFragment
- 请注意,只有一个LiveData通知表单具有正确的值
- 切换到MainFragment
- 单击添加垃圾便笺"按钮
- 切换到TrashFragment
- 请注意,LiveData有两个通知,第一个通知的值不正确
- Ensure that REPRODUCE_BUG is set to true in MainFragment
- Install the app
- Click on "add trashed note" button
- Switch to TrashFragment
- Note that there was just one notification form LiveData with correct value
- Switch to MainFragment
- Click on "add trashed note" button
- Switch to TrashFragment
- Note that there were two notifications from LiveData, the first one with incorrect value
请注意,如果将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屋!