1

I have an application that takes a lot of user input across various fragments and activities. Right now I have all the variables in one class lets call it "Report" and I pass around the primary key to know exactly what "Report" I am in. (there is a ListView at the start where the user selects what Report they want to make changes to) Since all the user input eventually has to be written to the database I had an idea - why not remove all the variables from the Report and replace them with static final column names, leaving only the primary key variable, then use the getters and setters to read from and write directly to the database? Would this be a good design to use or are there any drawbacks I am missing? As a relatively inexperienced android developer I am asking for any advice I can get.

Example (sorry if there are any mistakes I am writing this from a phone):

public class Report {
    private int primaryKey;
    private SQLiteDBHelper db;

    private static final String ColumnA = "columnA";
    private static final String ColumnB = "columnB";
    private static final String ColumnC = "columnC";
    // lets say columns A and B are Strings and C is an int

    public Report(int primaryKey, Context ctx) {
        this.primaryKey = primaryKey;
        this.db = new SQLiteDBHelper(ctx);
    }
    public String getColumnA() {
        return db.getString(primaryKey, ColumnA)
    }
    public boolean setColumnA(String value) {
        return db.setString(primaryKey, ColumnA, value);
    }
    public String getColumnB() {
        return db.getString(primaryKey, ColumnB)
    }
    public boolean setColumnB(String value) {
        return db.setString(primaryKey, ColumnB, value);
    }
    public String getColumnC() {
        return String.valueOf(db.getInt(primaryKey, ColumnC));
    }
    public boolean setColumnC(String value) {
        return db.setInt(primaryKey, ColumnC, Helper.tryParseInt(value));
    }
}

I could then extend TextWatcher like this:

public MyTextWatcher extends TextWatcher  {
    private View view;
    private Report report;
    public MyTextWatcher(View view, Report report) {
        this.view = view;
        this.report = report;
    }
    public void afterTextChanged(Editable editable) {
        String input = editable.toString();
        switch(view.getId()) {
            case R.id.columnA:
                if (!report.setColumnA(input)) {
                    // something went wrong
                }
            ... etc.
    }
}

And in the activity/fragment I would do this

int primaryKey = get from shared pref;
Report report = new Report(primaryKey, getApplication());
EditText columnA = (EditText) v.findViewById(R.id.columnA);
EditText columnB = (EditText) v.findViewById(R.id.columnB);
columnA.setText(report.getColumnA());
columnB.setText(report.getColumnB());
columnA.addTextChangedListener(new MyTextWatcher(columnA, report));
columnB.addTextChangedListener(new MyTextWatcher(columnB, report));

Why I think this is a good idea:

  • I can save the current primaryKey (the one user selected from ListView) in the SharedPreferences and then make a new Report from it in every activity/fragment I need to use it, without using up much memory

  • I can make sure there is never any discrepency between what the user entered and what is in the DB - for example on EditTexts i could call the corresponding setter for every column in the OnTextChanged listener

  • for every activity/fragment only the fields that are actually displayed on the screen would be retrieved from the database in onCreate

  • less code? ( for eg. I only need get/setInt and get/setString methods in my DB helper, I dont need to pass anything around between activities/fragments, only need one TextWatcher class)

Why I think this approach might be bad:

  • constant reading and writing to db - battery usage and speed might be problems?

  • ???

HomeIsWhereThePcIs
  • 1,273
  • 1
  • 19
  • 37

1 Answers1

1

Currently you are:

  • Writing to the database every time the text changes - as the user is typing each character or deleting characters, the record is being saved. This is overkill to not even wait for the user to finish to save the text. A better option would be to wait till the user moves to another widget - implying he is done with input on your EditText. You can use OnFocusChangeListener for this (More info at: How can i know when a edittext lost focus)

  • Making a lot of write calls to the database on the UI thread. You
    should delegate this if possible to the background.

  • Android will not kill the foreground process when the user is actively interacting with the app. You do not have to worry about data loss. If needed, you can wait for the app to be paused.

Community
  • 1
  • 1
ucsunil
  • 7,378
  • 1
  • 27
  • 32
  • Is the onFocusChanged called when user presses the hw back button or toolbar back button immediately after input? Or if the user kills the app immediately after input? What if the activity has only one control and it has nothing to lose focus to? Or if there are multiple tabs made using fragments and the user changes tabs by swiping? – HomeIsWhereThePcIs Oct 02 '16 at 11:29
  • Since navigation makes the EditText lose focus, yes it will be called. – ucsunil Oct 03 '16 at 07:13
  • Maybe I could extend the EditText and add the column name and type as a variable, then override onFocusChanged on the edittexts themselves. I have to mull this over then I will update my code. I don't have much experience with threading. Do you think AsyncTask would be a good pick for handling db calls? – HomeIsWhereThePcIs Oct 04 '16 at 18:58
  • AsyncTask is perfect as it is meant for short lived operations. There's no harm in using plain old threads either since you anyway do not need the callbacks from AsyncTask in your case – ucsunil Oct 04 '16 at 19:14