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.

\$\endgroup\$
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();
            }
        }
    }
    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.