MutableLiveData 的观察者未被触发
Observer for MutableLiveData not being triggered
我正在开发 activity 使用 MutableLiveData 使我的片段与从搜索中检索到的结果保持同步,但在更新结果列表后不会触发观察者。
在主要 activity 上,我有一个 EditText,我可以在其中键入要搜索的内容,在它的正下方,有一个具有三个选项的 ViewPager 小部件,结果被细分为三个类别(在三个不同的片段上)。当我第一次输入 activity 时,我会进行 运行 的初始搜索以检索数据并填充三个片段。这非常有效。
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()
,从中检索结果,并更新我的变量的值(到目前为止工作完美)时,观察者不会被触发。
额外信息:
- 我尝试在
查看寻呼机。两者均无效。
有什么想法吗?
问题是您要返回 MutableLiveData
的不同实例,但您的片段仅观察它在您的 InitFragment()
方法中获得的第一个实例。
您还将 listProducts
设置为 MutableLiveData
的多个实例(首先在其声明站点,然后在 searchText()
方法中再次设置),而不仅仅是更新它持有的值.
具体来说,您不需要在 getProductsList()
方法中进行空值检查,因为在创建视图模型时 listProducts
被初始化为 MutableLiveData
的新实例。
现在,MutableLiveData
的那个实例持有的值可能为 null.. 而您应该通过 setValue()
更新的只是那个值。 MutableLiveData
的值的任何空检查都可以在您在片段中创建的 Observer
中完成。
我正在开发 activity 使用 MutableLiveData 使我的片段与从搜索中检索到的结果保持同步,但在更新结果列表后不会触发观察者。
在主要 activity 上,我有一个 EditText,我可以在其中键入要搜索的内容,在它的正下方,有一个具有三个选项的 ViewPager 小部件,结果被细分为三个类别(在三个不同的片段上)。当我第一次输入 activity 时,我会进行 运行 的初始搜索以检索数据并填充三个片段。这非常有效。
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()
,从中检索结果,并更新我的变量的值(到目前为止工作完美)时,观察者不会被触发。
额外信息:
- 我尝试在 查看寻呼机。两者均无效。
有什么想法吗?
问题是您要返回 MutableLiveData
的不同实例,但您的片段仅观察它在您的 InitFragment()
方法中获得的第一个实例。
您还将 listProducts
设置为 MutableLiveData
的多个实例(首先在其声明站点,然后在 searchText()
方法中再次设置),而不仅仅是更新它持有的值.
具体来说,您不需要在 getProductsList()
方法中进行空值检查,因为在创建视图模型时 listProducts
被初始化为 MutableLiveData
的新实例。
现在,MutableLiveData
的那个实例持有的值可能为 null.. 而您应该通过 setValue()
更新的只是那个值。 MutableLiveData
的值的任何空检查都可以在您在片段中创建的 Observer
中完成。