I'm dealing with something that I don't understand at all.
If I delete the observer before updating my Room database and then put the observer back on, I have notifications for each update, and the recyclerview is updated as many times.
My partial code:
public class ArticlesListFragment extends Fragment {
private LiveData<List<Article>> mLDgetAllArticle;
private long mClistId;
private ArrayList<Article> mArticles;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.mLDgetAllArticle = this.articleViewModel.getAllArticle(mclistId);
this.setArticlesObserver();
...
}
private void setArticlesObserver() {
if (this.mLDgetAllArticle != null && !this.mLDgetAllArticle.hasObservers())
this.mLDgetAllArticle.observe(getViewLifecycleOwner(), this::updateArticlesList);
}
private void updateArticlesList(List<Article> articles) {
this.mArticles = new ArrayList<>(articles);
this.mArticlesRecyclerViewAdapter.setAdapterDatas(this.mArticles);
}
private void removeArticlesObserver() {
if (this.mLDgetAllArticle != null && this.mLDgetAllArticle.hasObservers())
this.mLDgetAllArticle.removeObservers(getViewLifecycleOwner());
}
private void updateArticle(Article article) {
this.articleViewModel.updateArticle(article);
}
...
}
Everything is fine so far.
But, elsewhere, I have to update all my Articles, like:
for (int i = 0; i < this.mArticles.size(); i++) {
this.mArticles.get(i).setOrd(i);
this.updateArticle(this.mArticles.get(i));
}
Also, I thought I should delete the observer before, and put it back later:
this.removeArticlesObserver();
for (int i = 0; i < this.mArticles.size(); i++) {
this.mArticles.get(i).setOrd(i);
this.updateArticle(this.mArticles.get(i));
}
this.setArticlesObserver();
but I still get after all the updates notifications. updateArticlesList
is called as many times as there were updateArticles
, after setArticlesObserver
.
What am I missing?
Is there any way to flush all that waiting results before setting observer again?
ViewModelFactory.java:
public class ViewModelFactory implements ViewModelProvider.Factory {
private final ArticleDataRepository articleDataSource;
private final Executor executor;
private static volatile ViewModelFactory factory;
public static ViewModelFactory getInstance(Context context) {
if (factory == null) {
synchronized (ViewModelFactory.class) {
if (factory == null) {
factory = new ViewModelFactory(context);
}
}
}
return factory;
}
private ViewModelFactory(Context context) {
getDB database = getDB.getInstance(context);
this.articleDataSource = new ArticleDataRepository(database.articleDao());
this.executor = Executors.newSingleThreadExecutor();
}
@Override
@NotNull
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass.isAssignableFrom(ArticleViewModel.class)) {
return (T) new ArticleViewModel(articleDataSource, executor);
}
throw new IllegalArgumentException("Unknown ViewModel class");
}
}
ArticleViewModel.java:
public class ArticleViewModel extends ViewModel {
private final ArticleDataRepository articleDataSource;
private final Executor executor;
public ArticleViewModel(
ArticleDataRepository articleDataSource,
Executor executor
) {
this.articleDataSource = articleDataSource;
this.executor = executor;
}
public LiveData<List<Article>> getAllArticle(long clistId) {
return articleDataSource.getAll(clistId);
}
}
ArticleDataRepository:
public class ArticleDataRepository {
private final ArticleDao articleDao;
public ArticleDataRepository(ArticleDao articleDao) {
this.articleDao = articleDao;
}
public LiveData<List<Article>> getAll(long clistId) {
return this.articleDao.getAll(clistId);
}
}
I took two steps to solve my problem:
I'm updating all the articles instead of doing a part one I didn't know I could do
@Update(onConflict = OnConflictStrategy.REPLACE) void updateAll(ArrayList articles);
for (int i = 0; i < this.mArticles.size(); i++) { this.mArticles.get(i).setOrd(i); this.updateArticle(this.mArticles.get(i)); }
becomes:
for (int i = 0; i < this.mArticles.size(); i++) {
this.mArticles.get(i).setOrd(i);
}
this.updateAllArticles(this.mArticles);
notifyDataSetChanged()
only during specific events and not each time the data is updated.