I am developing an activity using MutableLiveData to keep my fragments up-to-date with the results retrieved from a search, but the Observer is not being triggered after the list of results is updated.
I have, on the main activity, an EditText where I type what I want to search and, right below it, a ViewPager widget with three options, to where the results are subdivided into three categories (on three different fragments). When I first enter the activity, I run an initial search to retrieve data and populate the three fragments. This works perfectly.
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);
}
Already tried to move the method InitFragment()
inside the fragment to the OnActivityCreated
, but it didn't worked either.
I know for a fact that what is not working is the observer not being triggered. I've made tests with breakpoints.
As you guys can see, when the fragment is initialized the method SearchProducts()
is called and the result is sent perfectly to the MutableLiveData and the observer is triggered. But whenever I run a search calling the function searchText()
, retrieve the results from it, and update the value of my variable (works perfect till this point), the observer is not triggered.
Extra info:
- I tried making the search on and off the fragment being active on the ViewPager. Both didn't work.
Any ideas?