linasster
linasster

Reputation: 149

How to use Dagger2 in Room Database android application in java

I have a very difficult time trying to implement Dagger2 to my android app. In my app I use RoomDB. In the beginning, I used one MainActivity class and I have successfully implemented RoomDB. It worked as aspected. I could set and get values from my database. However, later I decided to expand my app by moving my logic from MainActivity class to fragments where each fragment is identical just it writes data or gets data from a database based on a different type of product. I have tried to make this work by implementing dependency injection Dagger2. I have watched plenty of videos and read a bunch of articles on how to do this however no luck so far.

I tried to implement one example based on the article Integrate Dagger 2 with Room Persistence Library in few lines In order not to destroy my existing application I have created a new project with the same structure as in the article. in the new project, I have used the same data structure as I have in my application. The application builds successfully. However, I can't retrieve my data from the database and I don't know why.

Here is what I did:

Product.class

@Entity(tableName = "product_table")
public class Product implements Serializable {

    @PrimaryKey(autoGenerate = true)
    private int ID;

    @ColumnInfo(name = "product_count")
    private String count;
    @ColumnInfo(name = "time")
    private String time;
    @ColumnInfo(name = "p_type")
    private String product_type;

    public String getProduct_type() {
        return product_type;
    }

    public void setProduct_type(String product_type) {
        this.product_type = product_type;
    }

    public int getID() {
        return ID;
    }

    public void setID(int ID) {
        this.ID = ID;
    }

    public String getCount() {
        return count;
    }

    public void setCount(String count) {
        this.count = count;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

ProductDao

@Dao
public interface ProductDao {

    @Insert(onConflict = REPLACE)
    void insert(Product product);
    @Delete
    void delete (Product product);
    @Delete
    void reset(List<Product> product);
    @Query("UPDATE product_table SET product_count=:sCount WHERE ID = :sID")
    void update(int sID, String sCount);
    @Query("SELECT * FROM product_table")
    List<Product> getAll();
    @Query("SELECT SUM(product_count)FROM product_table WHERE p_type = 'used' ")
    String getProductTotalCount();
    
}

AppComponent

@Singleton
@Component(dependencies = {}, modules = {AppModule.class, RoomModule.class})
public interface AppComponent {

    void inject(MainActivity mainActivity);

    ProductDao productDao();

    DemoDatabase2 demoDatabase2();

    ProductRepository productRepository();

    Application application();

}

AppModule

@Module
public class AppModule {

    Application mApplication;

    public AppModule(Application application) {
        mApplication = application;
    }

    @Provides
    @Singleton
    Application providesApplication() {
        return mApplication;
    }
}

RoomModule

@Module
public class RoomModule {

    private DemoDatabase2 demoDatabase2;

    public RoomModule(Application mApplication) {
        demoDatabase2 = Room.databaseBuilder(mApplication, DemoDatabase2.class, "demo-db").build();
    }

    @Singleton
    @Provides
    DemoDatabase2 providesRoomDatabase() {
        return demoDatabase2;
    }

    @Singleton
    @Provides
    ProductDao providesProductDao(DemoDatabase2 demoDatabase2) {
        return demoDatabase2.getProductDao();
    }

    @Singleton
    @Provides
    ProductRepository productRepository(ProductDao productDao) {
        return new ProductDataSource(productDao);
    }

}

DemoDatabase2

@Database(entities = {Product.class}, version = DemoDatabase2.VERSION, exportSchema = false)
public abstract class DemoDatabase2 extends RoomDatabase {

    static final int VERSION = 2;

    public abstract ProductDao getProductDao();

}

ProductDataSource

public class ProductDataSource implements ProductRepository {

    private ProductDao productDao;

    @Inject
    public ProductDataSource(ProductDao productDao) {
        this.productDao = productDao;
    }


    @Override
    public void insert(Product product) {

    }

    @Override
    public void delete(Product product) {

    }

    public String provideProductCount() {
        return productDao.getProductTotalCount();
    }

    @Override
    public List<Product> getAll() {
        return productDao.getAll();
    }
}

ProductRepository

public interface ProductRepository {

    void insert(Product product);

    void delete(Product product);


    List<Product> getAll();

    String provideProductCount();
}

MainActivity

public class MainActivity extends AppCompatActivity {

    @Inject
    public ProductRepository productRepository;


    TextView mTextView;
    EditText mEditText, mEditTextType;
    Button mButton;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DaggerAppComponent.builder()
                .appModule(new AppModule(getApplication()))
                .roomModule(new RoomModule(getApplication()))
                .build()
                .inject(this);


        mTextView = findViewById(R.id.text);

        mEditTextType = findViewById(R.id.product_type); 
        mEditText = findViewById(R.id.productCount);

        mButton = findViewById(R.id.button);    


    }

    public void addValue(View view) {

       Product product = new Product();

       String count = mEditText.getText().toString();
       product.setCount(count);

       String type = mEditTextType.getText().toString();
       product.setProduct_type(type);    


        mTextView.setText(String.valueOf(product.getCount()));    


    }
}

How can I get or set data as provideProductCount() from my DB? As if I try to use something like

String producCount = productRepository.provideProductCount();

It gives error as:

Caused by: java.lang.IllegalStateException: A migration from 1 to 2 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
        at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:117)

How to fix this?

Upvotes: 0

Views: 1495

Answers (2)

NhatVM
NhatVM

Reputation: 2124

First of all, As I can see your error doesn't relate to the Dagger. For migrating the database check this link: https://developer.android.com/training/data-storage/room/migrating-db-versions

And the way you provided the context for creating the database is wrong.

I built a demo project with Dagger, RoomDB, but It was written by Kotlin.

https://github.com/frank-nhatvm/expensestracker

I hope that can help you. Check in the di/AppComponent.kt to know to provide a context using Dagger.

Upvotes: 1

Uuu Uuu
Uuu Uuu

Reputation: 1282

You have to use fallbackToDestructiveMigration() to allow Room recreate database when you change db

public RoomModule(Application mApplication) {
      demoDatabase2 = Room.databaseBuilder(mApplication, DemoDatabase2.class, "demo-db")
          .fallbackToDestructiveMigration()
          .build();
    }

Visit here for more detail

Upvotes: 1

Related Questions