Search code examples
javaandroiddatabaseandroid-sqliteandroid-room

Check if object is exists in room database android java


I am new at the room database in android and I want to insert data into the room, but before inserting I want to check if the item already exists in the database or not. I am using these codes(News and Article are the same it is just naming problem):
My Dao

package com.example.newsapp.models;

import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;

import com.example.newsapp.operations.Article;

import java.util.List;

@Dao
public interface SavedNewsDAO {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(Article article);

    @Query("DELETE FROM saved_articles")
    void deleteAll();

    @Query("DELETE FROM saved_articles where id =:id ")
    void removeNews(int id);

    @Query("SELECT * FROM saved_articles")
    LiveData<List<Article>> getAll();

    @Query("select Count() from saved_articles where title =:title and content =:content and description =:description")
    int checkArticle(String title, String content, String description);
}

I want to get number of items in the database with checkArticle method.
My Repository

package com.example.newsapp.models;

import android.app.Application;

import androidx.lifecycle.LiveData;

import com.example.newsapp.operations.Article;

import java.util.List;

public class SavedArticlesRepository {
    private final LiveData<List<Article>> allArticles;
    private final SavedNewsDAO savedNewsDAO;
    SavedArticlesRepository(Application application) {
        SavedNewsRoomDatabase db = SavedNewsRoomDatabase.getDatabase(application);
        savedNewsDAO = db.savedNewsDAO();
        allArticles = savedNewsDAO.getAll();
    }

    LiveData<List<Article>> getAllArticles() {
        return allArticles;
    }

    void insert(Article article) {
        SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> savedNewsDAO.insert(article));
    }

    void checkItem(Article article) {
        SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> {
            savedNewsDAO.checkArticle(article.title, article.content, article.description);
        });
    }
}

and this is my View Model

package com.example.newsapp.models;

import android.app.Application;

import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;

import com.example.newsapp.operations.Article;

import java.util.List;

public class SavedNewsViewModel extends AndroidViewModel {
    private final SavedArticlesRepository savedArticlesRepository;
    private final LiveData<List<Article>> allArticles;
    public SavedNewsViewModel(Application application) {
        super(application);
        savedArticlesRepository = new SavedArticlesRepository(application);
        allArticles = savedArticlesRepository.getAllArticles();
    }

    public LiveData<List<Article>> getAllArticles() {
        return allArticles;
    }
    public void insert(Article article) {
        savedArticlesRepository.insert(article);
    }

    public void checkArticle(Article article) {
        savedArticlesRepository.checkItem(article);
    }
}

The problem is that I can't imagine how can I use checkArticle method in ViewModel and Repository classes like getAll method. As I understand I must chain these methods to each-others. And I want to check in this method:

savedNewsViewModel = new ViewModelProvider(this).get(SavedNewsViewModel.class);
        saveArticleButton.setOnClickListener(v -> {
            Article article = new Article();
            article.title = intent.getStringExtra("title");
            article.description = intent.getStringExtra("description");
            article.content = intent.getStringExtra("content");
            article.urlToImage = intent.getStringExtra("image");
            savedNewsViewModel.insert(article);
            Toast.makeText(this, "Article saved successfully", Toast.LENGTH_SHORT).show();
});

I have looked other questions, but I couldn't get it


Solution

  • You need to observe the value which you get from your checkArticle method. Use MutableLiveData in the following way:

    public class SavedArticlesRepository {
    
    ....
    
        LiveData<Integer> checkItem(Article article) {
            MutableLiveData<Integer> data = MutableLiveData();
            SavedNewsRoomDatabase.databaseWriterExecutor.execute(() -> {
                int count = savedNewsDAO.checkArticle(article.title, article.content, article.description);
                data.postValue(count);
            });
            return data;
        }
    
    }
    

    Now in your viewmodel, also extend the checkArticle with LiveData

    public LiveData<Integer> checkArticle(Article article) {
        return savedArticlesRepository.checkItem(article);
    }
    

    In your fragment or activity observe this method:

     saveArticleButton.setOnClickListener(v -> {
            Article article = new Article();
            article.title = intent.getStringExtra("title");
            article.description = intent.getStringExtra("description");
            article.content = intent.getStringExtra("content");
            article.urlToImage = intent.getStringExtra("image");
    
            savedNewsViewModel.checkArticle.observe(getViewLifeCycleOwner(), new Observer{ count ->
                if(count > 0){
                    Toast.makeText(this, "Article already exists", Toast.LENGTH_SHORT).show();
                } else {
                    savedNewsViewModel.insert(article);
                    Toast.makeText(this, "Article saved successfully", Toast.LENGTH_SHORT).show();
                }
            });
    
    });
    

    I haven't tested this code, as I don't work with Java anymore. But should work fine. If I can suggest, I'd say learn Kotlin and coroutines. This stuff is so much easier when you're using Kotlin and coroutines.

    Leave a comment if you need any more help with this.