You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:35:27