Search code examples
androidmultithreadingsqlitehandler

How to insert a row into SQLite on a different thread and return the result using handler?


I have this SQLite DatabaseHelper operation that inserts a row into the local database. I want to do this on a different thread and use handler to take the result back to the UI Thread. How can I do this? Here is the operation:

public void insertEmployee(String employeeType, String employeeName, Double employeeConvRate, String employeeDesc) {

    new Thread(() -> {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(EXPENSE_C_TYPE, employeeType);
        values.put(EXPENSE_C_NAME, employeeName);
        values.put(EXPENSE_C_CR, employeeConvRate);
        values.put(EXPENSE_C_DESC, employeeDesc);

        long id = db.insert(EXPENSE_TABLE_NAME, null, values);
        db.close();

    }).start();
}

Usually this function is a public long that returns the id variable.

EDIT - HOW I DID IT:

I created this interface with generic parameter:

public interface OnDatabaseResult<T> {
    void onResult(T result);
}

Then I aded the handler inside the database operation:

public void insertEmployee(String employeeType, String employeeName, Double employeeConvRate, String employeeDesc) {

    new Thread(() -> {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(EXPENSE_C_TYPE, employeeType);
        values.put(EXPENSE_C_NAME, employeeName);
        values.put(EXPENSE_C_CR, employeeConvRate);
        values.put(EXPENSE_C_DESC, employeeDesc);

        long id = db.insert(EXPENSE_TABLE_NAME, null, values);
        db.close();

    handler.post(()) -> onDatabaseResult.onResult(id)

    }).start();
}

Then in main activity I added the function that creates the row:

public void createEmploye(String employeeType, String employeeName, Double employeeConvRate, String employeeDesc){

     DatabaseHelper databaseHelper = new DatabaseHelper(this);

     databaseHelper.insertEmployee(type, name, rate, desc, new OnDatabaseResult<Long>(){

     @Override
     public void onResult(Long result){
            Employee employee = databaseHelper.getEmployee(result);
            if(employee!=null){
                  employeeList.add(o, employee);
                  employeeAdapter.notifyDataSetChanged();
            }
     }
     });
}

And now it works flawlessly.


Solution

  • You can use an Interface.

    The following is an example based upon your code, that inserts an Expense row (albeit the same row but with a different id) on another thread and displays the inserted id.

    The interface MyInterface.java is simply :-

    public interface MyInterface {
        void changeID(long newid);
    }
    

    The Database Helper DatabaseHelper.java is :-

    public class DatabaseHelper extends SQLiteOpenHelper {
    
        public static final String DBNAME = "mydb";
        public static final int DBVERSION = 1;
    
        public static final String EXPENSE_TABLE_NAME = "expense";
        public static final String EXPENSE_C_ID = BaseColumns._ID;
        public static final String EXPENSE_C_TYPE = "type";
        public static final String EXPENSE_C_NAME = "name";
        public static final String EXPENSE_C_CR = "cr";
        public static final String EXPENSE_C_DESC = "description";
    
    
        public DatabaseHelper(Context context) {
            super(context, DBNAME, null, DBVERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE IF NOT EXISTS " + EXPENSE_TABLE_NAME + "(" +
                    EXPENSE_C_ID + " INTEGER PRIMARY KEY, " +
                    EXPENSE_C_TYPE + " TEXT, " +
                    EXPENSE_C_NAME + " TEXT," +
                    EXPENSE_C_CR + " REAL, " +
                    EXPENSE_C_DESC + " TEXT" +
                    ")");
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
        }
    
        public long insertEmployee(String employeeType, String employeeName, Double employeeConvRate, String employeeDesc) {
    
                SQLiteDatabase db = this.getWritableDatabase();
                ContentValues values = new ContentValues();
    
                values.put(EXPENSE_C_TYPE, employeeType);
                values.put(EXPENSE_C_NAME, employeeName);
                values.put(EXPENSE_C_CR, employeeConvRate);
                values.put(EXPENSE_C_DESC, employeeDesc);
    
                long id = db.insert(EXPENSE_TABLE_NAME, null, values);
                db.close();
                return id;
        }
    }
    
    • Note that the insertEmployee method is not specifically run in another thread (it is thus more flexible).

    The layout for the activity, activity_main.xml is very simple a TextView for displaying the id (initially set to Hello World) and has a button that when clicked inserts the new row:-

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/result"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />
    
        <Button
            android:id="@+id/doit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="DO IT"/>
    
    </LinearLayout>
    

    Finally MainActivity.java :-

    public class MainActivity extends AppCompatActivity implements MyInterface {
    
        TextView mShowResult;       // TextView to display the latest id (initially Hello World)
        Button mDoIt;               // The Button, when clicked inserts a new row
        DatabaseHelper mDBHlpr;     // The Database Helper
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mShowResult = this.findViewById(R.id.result); // Get the TextView for the dispaly
            mDoIt = this.findViewById(R.id.doit); // Get the Button
            
            mDBHlpr = new DatabaseHelper(this); // Instantiate the Database Helper
            // Set the Buttons onClick Listener
            mDoIt.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    doItInAnotherThread("Full time", "Fred",32.897,"Worker"); //<<<<<<<<<<<
                }
            });
        }
    
        /**
         * As MainActivity implements MyInterface which has the changeID template
         * the changeID method must be implemented. This will be called when the doItInAnotherThread calls
         * changeID(?).
         *
         * As this is updating a view then it must be run on the UI thread
         */
        public void changeID(final long newid) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mShowResult.setText(String.valueOf(newid));
                }
            });
        }
    
        /**
         * Do the work in another thread returning changed id via the interface MyInterface
         */
        private void doItInAnotherThread(final String employeeType, final String employeeName, final Double employeeConvRate, final String employeeDesc) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    long id = mDBHlpr.insertEmployee(employeeType, employeeName, employeeConvRate, employeeDesc);
                    changeID(id);
                }
            }).start();
        }
    }
    

    Results

    1. When first run :-

    enter image description here

    2. When the DO IT button is clicked (instead of Hello World the display shows 1)

    enter image description here