我正在使用MutableLiveData开发一项活动,以使片段保持最新状态,并保留从搜索中检索到的结果,但是更新结果列表后不会触发观察器。
在主活动上,我有一个EditText,在其中键入要搜索的内容,在其正下方,是一个具有三个选项的ViewPager小部件,将结果分为三类(在三个不同的片段上)。首次进入活动时,我会进行初始搜索以检索数据并填充这三个片段。效果很好。
SearchActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
mViewModel = ViewModelProviders.of(this).get(SearchViewModel.class);
/* Init TabMenu */
TabLayout tabSearchMenu = findViewById(R.id.tabSearchMenu);
ViewPager vpSearch = findViewById(R.id.vpSearchResult);
TabSearchPageAdapter tabSearchPageAdapter = new TabSearchPageAdapter(getSupportFragmentManager(), tabSearchMenu.getTabCount());
vpSearch.setAdapter(tabSearchPageAdapter);
vpSearch.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabSearchMenu));
/* Init Search */
etxtSearch = findViewById(R.id.etxtSearch);
etxtSearch.setOnEditorActionListener((textView, actionId, keyEvent) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE
|| keyEvent.getAction() == KeyEvent.ACTION_DOWN || keyEvent.getAction() == KeyEvent.KEYCODE_ENTER) {
mViewModel.searchText(etxtSearch.getText().toString());
}
return false;
});
}
SearchViewModel.java
public class SearchViewModel extends ViewModel {
private MutableLiveData<List<ProductItemModel>> listProducts = new MutableLiveData<>(new ArrayList<>());
private List<ProductItemModel> mProducts = new ArrayList<>();
[...]
public void searchText(String text) {
// make search...
// ...
// ...
// Process Json result.
CompletionHandler completionHandler = (content, error) -> {
if (content != null && content.length() > 0) {
Log.d(TAG, content.toString());
Log.d(TAG, "searchText: found result.");
listProducts = new MutableLiveData<>(new ArrayList<>());
mProducts = new ArrayList<>();
try {
JSONArray products = content.getJSONArray("hits");
for (int i = 0; i < products.length(); i++) {
JSONObject prodObject = products.getJSONObject(i);
ProductItemModel prodItem = new ProductItemModel(prodObject);
mProducts.add(prodItem);
Log.d(TAG, "searchText: " + prodObject.toString());
}
listProducts.setValue(mProducts);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.d(TAG, "searchText: no hits");
}
};
}
[...]
MutableLiveData<List<ProductItemModel>> getProductList() {
if (listProducts == null)
return new MutableLiveData<>(new ArrayList<>());
return listProducts;
}
}
SearchProductFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InitFragment();
}
[...]
private void InitFragment() {
mViewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity())).get(SearchViewModel.class);
mViewModel.SearchProducts();
final Observer<List<ProductItemModel>> listObserver = result -> {
Log.d(TAG, "listObserver: observer modified.");
if (result.size() > 0) {
InitProductList(result);
}
};
mViewModel.getProductList().observe(getActivity(), listObserver);
}
已经尝试将片段内的方法InitFragment()
移动到OnActivityCreated
,但是也没有用。
我知道一个不起作用的事实是观察者未被触发。我已经用断点进行了测试。
正如你们所看到的,当片段被初始化时,方法SearchProducts()
被调用,并且结果被完美地发送到MutableLiveData并触发了观察者。但是,每当我运行一个调用函数searchText()
的搜索,从中检索结果并更新变量的值(到现在为止都可以正常工作)时,观察器就不会触发。
其他信息:
有什么想法吗?
答案 0 :(得分:1)
问题是您要返回MutableLiveData
的不同实例,但是您的片段仅观察到它在InitFragment()
方法中获得的第一个实例。
您还将listProducts
设置为MutableLiveData
的多个实例(首先在其声明站点,然后在searchText()
方法中),而不仅仅是更新其拥有的值。 / p>
为了详细说明,您不需要在getProductsList()
方法中进行空检查,因为在创建视图模型时,listProducts
被初始化为MutableLiveData
的新实例。
现在,该MutableLiveData
实例所拥有的值可能为null ..并且只有该值您应该通过setValue()
进行更新。对MutableLiveData
的值进行任何空检查都可以在您在片段中创建的Observer
中进行。