For my software engineering class, we have to incorporate an SQLite database into our application project.
For our application this database class has to be accessible from multiple activities. I have turned the Database class into a singleton and then call
DBInterface database = Database.getInstance(this)
to set a variable to reference the database in order to access its methods in each necessary class and it works. However, we are supposed to utilize dependency injections into our code and my professor has specifically told us that it should be possible to switch from our database class to a stub database we used in a previous iteration by only changing one line of code.
Obviously this means changing the above to
DBInterface database = StubDB.getInstance(this)
However in doing this I still have to make this change in each of the activities that uses the database methods.
So my question is this: is there a way to initialize my database in our init activity and then pass a reference to each necessary activity without the assignment code above?
Relevant Code
Singleton Database Class
public class RecipeDatabase extends Activity implements DBInterface {
private dbHelper Helper;
private static RecipeDatabase sInstance;
private static Context sContext;
public static synchronized RecipeDatabase getInstance(Context context){
if(sInstance == null){
sInstance = new RecipeDatabase(context.getApplicationContext());
}
return sInstance;
}
private RecipeDatabase(Context context){
Helper = new dbHelper(context);
sContext = context;
}
@Override
public void addRecipe(Recipe recipe)
{
String ingredients = recipe.ingredientString();
String directions = recipe.directionString();
SQLiteDatabase db = Helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Recipe.KEY_rID, recipe.getrID());
values.put(Recipe.KEY_mealtype, recipe.getMealType());
values.put(Recipe.KEY_mainingredient, recipe.getMainIngredient());
values.put(Recipe.KEY_description, recipe.getDescription());
values.put(Recipe.KEY_ingredients, ingredients);
values.put(Recipe.KEY_directions, directions);
values.put(Recipe.KEY_notes, recipe.getNotes());
values.put(Recipe.KEY_rating, recipe.getRating());
values.put(Recipe.KEY_cooktime, recipe.getCooktime());
db.insert(Recipe.TABLE, null, values);
db.close();
}
@Override
public void editRecipe(Recipe recipe)
{
SQLiteDatabase db = Helper.getWritableDatabase();
ContentValues values = new ContentValues();
String ingredients = recipe.ingredientString();
String directions = recipe.directionString();
values.put(Recipe.KEY_rID, recipe.getrID());
values.put(Recipe.KEY_mealtype, recipe.getMealType());
values.put(Recipe.KEY_mainingredient, recipe.getMainIngredient());
values.put(Recipe.KEY_description, recipe.getDescription());
values.put(Recipe.KEY_ingredients, ingredients);
values.put(Recipe.KEY_directions, directions);
values.put(Recipe.KEY_notes, recipe.getNotes());
values.put(Recipe.KEY_rating, recipe.getRating());
values.put(Recipe.KEY_cooktime, recipe.getCooktime());
db.update(Recipe.TABLE, values, Recipe.KEY_rID + " = ?", new String[]{String.valueOf(recipe.getrID())});
db.close();
}
@Override
public void deleteRecipe(Recipe recipe)
{
SQLiteDatabase db = Helper.getWritableDatabase();
db.delete(Recipe.TABLE, Recipe.KEY_rID + " = ", new String[]{String.valueOf(recipe.getrID())});
db.close();
}
public ArrayList<Recipe> getList()
{
ArrayList<Recipe> result = new ArrayList<>();
SQLiteDatabase db = Helper.getReadableDatabase();
String selectQuery = "SELECT " + Recipe.KEY_rID + ", " +
Recipe.KEY_name + ", " +
Recipe.KEY_mealtype + ", " +
Recipe.KEY_mainingredient + ", " +
Recipe.KEY_description + ", " +
Recipe.KEY_ingredients + ", " +
Recipe.KEY_directions + ", " +
Recipe.KEY_notes + ", " +
Recipe.KEY_rating + ", " +
Recipe.KEY_cooktime + " FROM " + Recipe.TABLE;
Cursor cursor = db.rawQuery(selectQuery, null);
if(cursor.moveToFirst()) {
do {
ArrayList<String> ingredients = new ArrayList<>(); // Temp Storage
ArrayList<String> directions = new ArrayList<>(); // Temp Storage
String tempIngredient = cursor.getString(cursor.getColumnIndex(Recipe.KEY_ingredients));
String[] temp = tempIngredient.split("- "); //Split up ingredients to individual strings
for(int x=0; x < temp.length; x++) {
ingredients.add(temp[x]);
}
String tempDirection = cursor.getString(cursor.getColumnIndex(Recipe.KEY_ingredients));
temp = tempDirection.split("- ");//split up directions into individual strings
for(int x=0; x < temp.length; x++) {
directions.add(temp[x]);
}
//Get Values for Recipe Object
int rID = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_rID));
String name = cursor.getString(cursor.getColumnIndex(Recipe.KEY_name));
String mealType = cursor.getString(cursor.getColumnIndex(Recipe.KEY_mealtype));
String mainIngredient = cursor.getString(cursor.getColumnIndex(Recipe.KEY_mainingredient));
int rating = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_rating));
String description = cursor.getString(cursor.getColumnIndex(Recipe.KEY_description));
int cooktime = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_cooktime));
String notes = cursor.getString(cursor.getColumnIndex(Recipe.KEY_notes));
//Create new Recipe from Row
Recipe tempRecipe = new Recipe(rID, name, description, mealType, mainIngredient,
rating, cooktime, notes, ingredients, directions);
//Add the recipe to the ArrayList
result.add(tempRecipe);
}while (cursor.moveToNext());
}
//Return the populated ArrayList for use
return result;
}
}
Init Class
public class init extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_init);
//The code to change to switch from stub to database
DBInterface repository = RecipeDatabase.getInstance(this);
//DBInterface repository = new StubDB(this);
ArrayList<Recipe> recipes = repository.getList();
ArrayList<String> recipeDisplay = new ArrayList<>();
for(int i=0; i<recipes.size(); i++) {
recipeDisplay.add(recipes.get(i).getName());
}
ArrayAdapter<String> myArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, recipeDisplay);
ListView lv = this.getListView();
lv.setAdapter(myArrayAdapter);
}
@Override
protected void onListItemClick(ListView l, View v, int pos, long id){
super.onListItemClick(l, v, pos, id);
Intent myIntent = new Intent(this, Details.class);
myIntent.putExtra("recipePosition", pos);
startActivity(myIntent);
}
public void shoppingListButton(View view){
startActivity(new Intent(this, ShoppingList.class));
}
public void addRecipeButton(View view){
Intent myIntent = new Intent(this, Edit.class);
myIntent.putExtra("editType", 1); // 1 corresponds to add recipe
startActivity(myIntent);
}
}
One of the Activity Classes that needs the DB methods
public class Details extends ListActivity {
int recipePosition = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
//want to avoid this call
DBInterface repository = RecipeDatabase.getInstance(this);
recipePosition = getIntent().getIntExtra("recipePosition", 0);
Recipe clickedRecipe = repository.getList().get(recipePosition);
ArrayList<String> recipeDetails = new ArrayList<>();
recipeDetails.add(clickedRecipe.getName());
recipeDetails.add(clickedRecipe.getDescription());
recipeDetails.add("Ingredients:");
for(int i=0; i<clickedRecipe.getIngredients().size(); i++){
recipeDetails.add(clickedRecipe.getIngredients().get(i));
}
recipeDetails.add("Instructions:");
for(int i=0; i<clickedRecipe.getDirections().size(); i++){
recipeDetails.add(clickedRecipe.getDirections().get(i));
}
ArrayAdapter<String> myArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, recipeDetails);
ListView lv = this.getListView();
lv.setAdapter(myArrayAdapter);
}
public void editButton(View view){
Intent myIntent = new Intent(this, Edit.class);
myIntent.putExtra("recipePosition", recipePosition);
myIntent.putExtra("editType", 2); // 2 corresponds to modify recipe
startActivity(myIntent);
}
}
Database Helper Class
public class dbHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "ROSE.db";
public dbHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db){
//Creates the Recipe Table which stores recipes
String CREATE_TABLE_RECIPES = "CREATE TABLE " + Recipe.TABLE +
"(" + Recipe.KEY_rID + " INTEGER PRIMARY KEY, " +
Recipe.KEY_name + " TEXT, " +
Recipe.KEY_mealtype + " TEXT, " +
Recipe.KEY_mainingredient + " TEXT, " +
Recipe.KEY_description + " TEXT, " +
Recipe.KEY_ingredients + " TEXT, " +
Recipe.KEY_directions + " TEXT, " +
Recipe.KEY_notes + " TEXT, " +
Recipe.KEY_rating + " INTEGER, " +
Recipe.KEY_cooktime + " INTEGER )";
db.execSQL(CREATE_TABLE_RECIPES);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS recipes" );
onCreate(db);
}
}
Dagger2 is the perfect thing for you. It's really easy to use, just follow the instructions they provide in the docs and you'll love it once you figure it out.
Basically you're going to use
@Inject
DBInterface database;
In every activity, fragment, service, or anywhere you wanna use the database. Then you will create a DatabaseModule which will have a method that provides the database for injection.
@Singleton
@Provides static DBInterface provideDatabase() {
return new WhateverDatabaseImplementsDBInterface();
}
As you can see, just adding @Singleton will make it a singleton. And now changing the database you use is truly a one line change.
Dagger2 is the greatest thing you will encounter for dependency injection for sure, just setup it correctly, write if you have any trouble (but you shouldn't, with their thorough instructions).
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments