【发布时间】:2018-10-18 14:12:56
【问题描述】:
我对@987654325@的理解是,它会触发数据当前状态变化的观察者,而不是数据的一系列历史状态变化。
目前,我有一个MainFragment,它执行Room 写操作,将非垃圾数据更改为垃圾数据。
我还有另一个TrashFragment,它会观察到垃圾数据。
考虑以下场景。
- 目前有 0 个垃圾数据。
-
MainFragment是当前活动片段。TrashFragment尚未创建。 -
MainFragment添加了 1 个垃圾数据。 - 现在,有 1 个垃圾数据
- 我们使用导航抽屉,将
MainFragment替换为TrashFragment。 -
TrashFragment的观察者将首先收到onChanged,其中包含 0 个已丢弃数据 - 同样,
TrashFragment的观察者将第二次收到onChanged,其中包含 1 个已丢弃数据
出乎我意料的是,第 (6) 项不应该发生。 TrashFragment 应该只接收最新的垃圾数据,即 1。
这是我的代码
TrashFragment.java
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 两次,对于相同的数据?
演示
我创建了一个演示项目来演示这个问题。
如您所见,在我在MainFragment 中执行写入操作(单击添加已删除注释 按钮)后,当我切换到TrashFragment 时,我希望TrashFragment 中的onChanged只会被调用一次。但是,它被调用了两次。
【问题讨论】:
-
LiveData立即提供最后一个值(如果之前已发布过值)以及未来的更改。getTrashedNotesLiveData()的实现是什么?您要从 Room 中返回LiveData吗?你在使用 RxJava 和LiveDataReactiveStreams吗?这是自定义的LiveData实现吗?还有什么? -
只是来自 Room 的简单 LiveData。我更新了我的问题以提供更多信息。因为在我们切换到
TrashFragment之前,数据库应该写入了 11 个废弃数据。我不确定为什么 TrashFragment 中的观察者会首先收到 10 个已丢弃数据(旧快照),然后是 11 个已丢弃数据(最新快照) -
我们可以通过将
ViewModel修改为 gist.github.com/yccheok/4bb6539c93fa39cf7dc7f08f0752d232 来“防止”这种情况发生。每当在TrashFragment和MainFragment之间切换之前,我们都会在ViewModel中调用init。但是,在我们了解问题之前,我们还不想走那条路。 -
嗨@CommonsWare,我创建了一个演示项目来演示这个问题。不确定您是否愿意指出,代码的哪一部分出错了?谢谢。
-
您可能会将此示例应用程序提出问题作为可能存在问题的证据。我会摆脱
removeObservers()调用,因为它们在现实世界中不应该是必需的,并且绝对不是重现问题所必需的。 IOW,将演示削减到最低限度以说明问题。感觉就像您最初获得的是缓存值,然后是实际值,尽管我不知道为什么。
标签: android android-architecture-components android-livedata