3
\$\begingroup\$

I'm writing a simple Android app with a database and am trying to make the right architecture for accessing a database.

MainActivity.java

public class MainActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 }
 public void onSubmitClick(View view) {
 EditText editTextTitle = (EditText) findViewById(R.id.task_title);
 EditText editTextDescription = (EditText) findViewById(R.id.task_description);
 TaskHelper taskHelper = new TaskHelper(getApplicationContext());
 long taskId = taskHelper.insertTask(
 new Task(editTextTitle.getText().toString(), editTextDescription.getText().toString())
 );
 if (taskId > 0) {
 Toast.makeText(getApplicationContext(), "Task added.", Toast.LENGTH_SHORT).show();
 } else {
 Toast.makeText(getApplicationContext(), "Something went wrong.", Toast.LENGTH_SHORT).show();
 }
 }
}

TaskHelper.java

public class TaskHelper {
 private DatabaseHelper databaseHelper;
 private SQLiteDatabase sqLiteDatabase;
 public TaskHelper(Context context) {
 this.databaseHelper = new DatabaseHelper(context);
 this.sqLiteDatabase = databaseHelper.getWritableDatabase();
 }
 public long insertTask(Task task) {
 ContentValues contentValues = new ContentValues();
 contentValues.put(DatabaseContract.TaskTable.COLUMN_NAME_TITLE, task.getTaskTitle());
 contentValues.put(DatabaseContract.TaskTable.COLUMN_NAME_DESCRIPTION, task.getTaskDescription());
 return this.sqLiteDatabase.insert(
 DatabaseContract.TaskTable.TABLE_NAME,
 null,
 contentValues);
 }
}

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {
 private static final String DATABASE_NAME = "Notes.db";
 private static final int DATABASE_VERSION = 1;
 public DatabaseHelper(Context context) {
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }
 @Override
 public void onCreate(SQLiteDatabase db) {
 db.execSQL(DatabaseContract.TaskTable.CREATE_DATABASE);
 }
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 db.execSQL(DatabaseContract.TaskTable.DELETE_DATABASE);
 }
}

DatabaseContract.java

public final class DatabaseContract {
 // To prevent someone from accidentally instantiating the contract class,
 // give it an empty constructor.
 private DatabaseContract() {}
 // Inner class that defines table schema
 public static abstract class TaskTable implements BaseColumns {
 public static final String TABLE_NAME = "task";
 public static final String COLUMN_NAME_TASK_ID = "_id";
 public static final String COLUMN_NAME_TITLE = "title";
 public static final String COLUMN_NAME_DESCRIPTION = "description";
 public static final String CREATE_DATABASE =
 "CREATE TABLE " + TABLE_NAME + " ("
 + TaskTable.COLUMN_NAME_TASK_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
 + TaskTable.COLUMN_NAME_TITLE + " TEXT,"
 + TaskTable.COLUMN_NAME_DESCRIPTION + " TEXT);";
 public static final String DELETE_DATABASE =
 "DROP TABLE IF EXIST " + TaskTable.TABLE_NAME;
 }
}

Task.java

public class Task {
 private int taskId;
 private String taskTitle;
 private String taskDescription;
 public Task(String title, String description) {
 this.taskTitle = title;
 this.taskDescription = description;
 }
 public Task(int id, String title, String description) {
 this.taskId = id;
 this.taskTitle = title;
 this.taskDescription = description;
 }
 public int getTaskId() {
 return taskId;
 }
 public String getTaskTitle() {
 return taskTitle;
 }
 public String getTaskDescription() {
 return taskDescription;
 }
}

My vision is to have helper classes for every table in the database. With that approach I want to reduce code in activity methods and separate UI from logic. Primary, I'm looking for architecture improvements but any other is also welcome.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Mar 23, 2016 at 0:25
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I don't have any comments on the architecture, but here are 2 suggestions:

  1. To keep database access thread-safe, I would suggest you make your DatabaseHelper class a singleton and only access the SQLiteDatabase object through that (using getReadableDatabase() and getWritableDatabase()), as outlined here: https://codereview.stackexchange.com/a/36230

  2. No database operations should be performed on the main thread. When I need to perform a database operation initiated by a user operation, such as onSubmitClick, I call a method in my DatabaseHelper class which executes an AsyncTask which performs the actual DB operations, and then calls a callback method when it's finished. For example:

    public void fetchModels(DatabaseQueryListener listener) {
     new FetchModelsTask(listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
    class FetchModelsTask extends AsyncTask<Void, Void, Cursor> {
     private DatabaseQueryListener listener;
     public FetchModelsTask(DatabaseQueryListener listener) {
     this.listener = listener;
     }
     @Override
     protected Cursor doInBackground(Void... params) {
     return query(getReadableDatabase().rawQuery(...);
     }
     @Override
     protected void onPostExecute(Cursor cursor) {
     if(listener != null) {
     listener.onQueryExecuted(cursor);
     cursor.close();
     }
     }
    }
    
answered Mar 29, 2016 at 16:50
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.