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

Retrofit+MVVM架构下SearchView实时搜索返回null问题解决

问题根因

核心问题是LiveData实例不唯一+同步取值时机错误:

  • Repository层每次调用queryTextChange都会新建一个局部MutableLiveData对象,网络请求是异步执行的,方法return的时候接口还没返回,此时局部LiveData的值就是null
  • ViewModel层调用gifRepo.queryTextChange(text,key).getValue()是同步立刻取值,拿到的就是上面说的null,直接塞给了Fragment观察的全局gifList
  • 等网络请求成功后,Repository更新的是自己内部新建的那个局部LiveData,这个实例根本没有被任何上层组件观察,所以Fragment的观察回调永远不会被触发。
修复步骤

1. 调整Repository层实现

去掉每次新建局部LiveData的逻辑,直接接收上层传入的、正在被观察的LiveData实例,请求完成后直接更新该实例:

public void queryTextChange(String text, String api_key, MutableLiveData<SearchGifs> resultLiveData) {
    Call<SearchGifs> gifSearch = service.search(api_key, text);
    gifSearch.enqueue(new Callback<SearchGifs>() {
        @Override
        public void onResponse(Call<SearchGifs> call, Response<SearchGifs> response) {
            if (response.isSuccessful() && response.body() != null) {
                resultLiveData.postValue(response.body());
            }
        }

        @Override
        public void onFailure(Call<SearchGifs> call, Throwable t) {
            // 可按需处理错误逻辑,比如post null标记请求失败
        }
    });
}

2. 调整ViewModel层实现

不要同步获取Repository返回的LiveData值,直接把自身持有的全局gifList传入Repository,保证整个观察链路用的是同一个LiveData实例:

private String API_KEY = "";
// 全局唯一、供Fragment观察的LiveData实例
public MutableLiveData<SearchGifs> gifList = new MutableLiveData<>();
private GifRepo gifRepo = new GifRepo();

public HomeViewModel(String api_key) {
    this.API_KEY = api_key;
}

public void queryTextChange(String text, String key){
    gifRepo.queryTextChange(text, key, gifList);
}

3. 修正Fragment观察的LifecycleOwner

不要用requireActivity()作为观察的生命周期持有者,替换为getViewLifecycleOwner(),避免Fragment销毁后仍收到回调造成内存泄漏:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    
    model.gifList.observe(getViewLifecycleOwner(), new Observer<SearchGifs>() {
        @Override
        public void onChanged(SearchGifs gifs) {
            // 此处更新RecyclerView数据即可,回调会正常触发
        }
    });
}

可选优化:增加搜索防抖

当前逻辑每输入一个字符就会触发一次API请求,容易出现请求顺序错乱、流量浪费的问题,可以加300ms防抖,等用户停止输入后再发请求:

private final Handler searchHandler = new Handler(Looper.getMainLooper());
private Runnable searchRunnable;

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        searchHandler.removeCallbacks(searchRunnable);
        model.queryTextChange(query, getString(R.string.api_key));
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        searchHandler.removeCallbacks(searchRunnable);
        searchRunnable = () -> model.queryTextChange(newText, getString(R.string.api_key));
        searchHandler.postDelayed(searchRunnable, 300);
        return false;
    }
});

内容的提问来源于stack exchange,提问作者any_123332

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 13:01:21