Android中removeObserver()无法移除Observer问题求助
问题:带参数查询场景下LiveData Observer无法移除,仍触发回调
我有一个ViewModel和Observer,原本运行正常,但Observer始终无法被移除。我试了以下代码:
MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class); final Observer<List<String>> my_observer = new Observer<List<String>>() { @Override public void onChanged(List<String> firstNames) { ... some code ... } }; viewModel.getFirstNames(lastName).observe(this,my_observer); viewModel.getFirstNames(lastName).removeObserver(my_observer);
我也试过removeObservers(this,my_observer),但当firstNames发生增删改且lastName不变时,my_observer里的代码还是会执行。我查了很多相关问题,但都没涉及带lastName参数的场景,解决不了我的问题。
以下是相关代码:
MyViewModel
public class MyViewModel extends AndroidViewModel { public static MyRepository myRepository; public MyViewModel(@NonNull Application application) { super(application); myRepository = new MyRepository(application); } public LiveData<List<String>> getFirstNames(String lastName){ return myRepository.getFirstNames(lastName); } }
MyRepository
public class MyRepository { private final MyDao myDao; public MyRepository(Application application) { MyRoomDatabase db = MyRoomDatabase.getDatabase(application); myDao = db.myDao(); } public LiveData<List<String>> getFirstNames(String lastName){ return myDao.getFirstNames(lastName); } }
MyDao
@Dao public interface MyDao { @Query("SELECT * FROM table_names AS tn " + "WHERE tn.lastname LIKE :lastName " + "ORDER BY tn.firstname ASC") LiveData<List<String>> getFirstNames(String lastName); }
问题原因
每次调用getFirstNames(lastName)时,Room都会返回全新的LiveData实例。你第一次调用observe时绑定的是一个LiveData对象,第二次调用removeObserver时拿到的是另一个完全不同的LiveData对象,自然无法移除之前绑定的Observer。
解决办法
需要对相同lastName的LiveData进行缓存,确保同一个lastName返回的是同一个LiveData实例。可以在ViewModel或Repository层添加缓存逻辑:
方案1:在ViewModel中缓存LiveData
修改MyViewModel,用Map存储已创建的LiveData实例:
public class MyViewModel extends AndroidViewModel { public static MyRepository myRepository; // 缓存相同lastName对应的LiveData private final Map<String, LiveData<List<String>>> firstNameLiveDataCache = new HashMap<>(); public MyViewModel(@NonNull Application application) { super(application); myRepository = new MyRepository(application); } public LiveData<List<String>> getFirstNames(String lastName){ // 先从缓存取,没有的话再创建并存入缓存 if (!firstNameLiveDataCache.containsKey(lastName)) { firstNameLiveDataCache.put(lastName, myRepository.getFirstNames(lastName)); } return firstNameLiveDataCache.get(lastName); } }
方案2:在Repository中缓存LiveData
也可以把缓存逻辑放在Repository层,ViewModel直接复用:
public class MyRepository { private final MyDao myDao; private final Map<String, LiveData<List<String>>> firstNameLiveDataCache = new HashMap<>(); public MyRepository(Application application) { MyRoomDatabase db = MyRoomDatabase.getDatabase(application); myDao = db.myDao(); } public LiveData<List<String>> getFirstNames(String lastName){ if (!firstNameLiveDataCache.containsKey(lastName)) { firstNameLiveDataCache.put(lastName, myDao.getFirstNames(lastName)); } return firstNameLiveDataCache.get(lastName); } }
后续操作
修改缓存逻辑后,再调用observe和removeObserver时,操作的就是同一个LiveData实例,Observer就能被正确移除了:
// 现在两次调用getFirstNames返回的是同一个LiveData LiveData<List<String>> liveData = viewModel.getFirstNames(lastName); liveData.observe(this, my_observer); liveData.removeObserver(my_observer);
内容的提问来源于stack exchange,提问作者Karina
相关产品推荐
相关产品推荐

