Reputation: 149
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
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
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