So I’m trying to use Executor execute the Dao’s in my android app, but when I created the Executor, it said it required the method being run to have a Runnable return type?
So I made them all return Runnable, but now Android Studio gives me the error:
/database/TripDao.java:28: error: Not sure how to handle insert method's return type. Runnable insertTrip(Trip trip); ^
Dao:
import androidx.lifecycle.LiveData; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; import androidx.room.Update; import java.util.List; import java.util.UUID; @Dao public interface TripDao { @Query("DELETE FROM trip") public void deleteTrips(); @Query("SELECT * FROM trip") LiveData<List<Trip>> getAll(); @Query("SELECT * FROM trip WHERE uuid=:id") public LiveData<Trip> getTrip(UUID id); @Delete Runnable delete(Trip trip); @Insert Runnable insertTrip(Trip trip); @Update Runnable updateTrip(Trip trip); }
Repository:
package com.example.csc202assignment.database; import android.content.Context; import androidx.lifecycle.LiveData; import androidx.room.Room; import java.util.List; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class TripRepository { private static TripRepository INSTANCE = null; private final String DATABASE_NAME = "trip-database"; private Context context; TripDatabase database; static TripDao tripDao; Executor executor = Executors.newSingleThreadExecutor(); private TripRepository(Context context) { this.context = context; this.database = Room.databaseBuilder( context.getApplicationContext(), TripDatabase.class,DATABASE_NAME).build(); tripDao = database.tripDao(); } void deleteTrips(){ tripDao.deleteTrips(); } void delete(Trip trip){ executor.execute(tripDao.delete(trip)); } void insertTrip(Trip trip){ executor.execute(tripDao.insertTrip(trip)); } void updateTrip(Trip trip){ executor.execute(tripDao.updateTrip(trip)); } public LiveData<List<Trip>> getAll(){ return tripDao.getAll(); } public static LiveData<Trip> getTrip(UUID id){ return tripDao.getTrip(id); } public static void initialise(Context context){ if(INSTANCE==null){ INSTANCE = new TripRepository(context); } } public static TripRepository get() throws IllegalStateException { try { return INSTANCE; } catch (IllegalStateException e) { System.out.println("TripRepository must be initialised"); } return INSTANCE; } }
Dao_Impl
package com.example.csc202assignment.database; import android.database.Cursor; import androidx.lifecycle.LiveData; import androidx.room.EntityDeletionOrUpdateAdapter; import androidx.room.EntityInsertionAdapter; import androidx.room.RoomDatabase; import androidx.room.RoomSQLiteQuery; import androidx.room.SharedSQLiteStatement; import androidx.room.util.CursorUtil; import androidx.room.util.DBUtil; import androidx.sqlite.db.SupportSQLiteStatement; import java.lang.Class; import java.lang.Exception; import java.lang.Override; import java.lang.Runnable; import java.lang.String; import java.lang.SuppressWarnings; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.Callable; @SuppressWarnings({"unchecked", "deprecation"}) public final class TripDao_Impl implements TripDao { private final RoomDatabase __db; private final EntityInsertionAdapter<Trip> __insertionAdapterOfTrip; private final TripTypeConverter __tripTypeConverter = new TripTypeConverter(); private final EntityDeletionOrUpdateAdapter<Trip> __deletionAdapterOfTrip; private final EntityDeletionOrUpdateAdapter<Trip> __updateAdapterOfTrip; private final SharedSQLiteStatement __preparedStmtOfDeleteTrips; public TripDao_Impl(RoomDatabase __db) { this.__db = __db; this.__insertionAdapterOfTrip = new EntityInsertionAdapter<Trip>(__db) { @Override public String createQuery() { return "INSERT OR ABORT INTO `Trip` (`uuid`,`title`,`destination`,`date`,`duration`) VALUES (?,?,?,?,?)"; } @Override public void bind(SupportSQLiteStatement stmt, Trip value) { final String _tmp; _tmp = __tripTypeConverter.fromUUID(value.uuid); if (_tmp == null) { stmt.bindNull(1); } else { stmt.bindString(1, _tmp); } if (value.title == null) { stmt.bindNull(2); } else { stmt.bindString(2, value.title); } if (value.destination == null) { stmt.bindNull(3); } else { stmt.bindString(3, value.destination); } if (value.date == null) { stmt.bindNull(4); } else { stmt.bindString(4, value.date); } if (value.duration == null) { stmt.bindNull(5); } else { stmt.bindString(5, value.duration); } } }; this.__deletionAdapterOfTrip = new EntityDeletionOrUpdateAdapter<Trip>(__db) { @Override public String createQuery() { return "DELETE FROM `Trip` WHERE `uuid` = ?"; } @Override public void bind(SupportSQLiteStatement stmt, Trip value) { final String _tmp; _tmp = __tripTypeConverter.fromUUID(value.uuid); if (_tmp == null) { stmt.bindNull(1); } else { stmt.bindString(1, _tmp); } } }; this.__updateAdapterOfTrip = new EntityDeletionOrUpdateAdapter<Trip>(__db) { @Override public String createQuery() { return "UPDATE OR ABORT `Trip` SET `uuid` = ?,`title` = ?,`destination` = ?,`date` = ?,`duration` = ? WHERE `uuid` = ?"; } @Override public void bind(SupportSQLiteStatement stmt, Trip value) { final String _tmp; _tmp = __tripTypeConverter.fromUUID(value.uuid); if (_tmp == null) { stmt.bindNull(1); } else { stmt.bindString(1, _tmp); } if (value.title == null) { stmt.bindNull(2); } else { stmt.bindString(2, value.title); } if (value.destination == null) { stmt.bindNull(3); } else { stmt.bindString(3, value.destination); } if (value.date == null) { stmt.bindNull(4); } else { stmt.bindString(4, value.date); } if (value.duration == null) { stmt.bindNull(5); } else { stmt.bindString(5, value.duration); } final String _tmp_1; _tmp_1 = __tripTypeConverter.fromUUID(value.uuid); if (_tmp_1 == null) { stmt.bindNull(6); } else { stmt.bindString(6, _tmp_1); } } }; this.__preparedStmtOfDeleteTrips = new SharedSQLiteStatement(__db) { @Override public String createQuery() { final String _query = "DELETE FROM trip"; return _query; } }; } @Override public Runnable insertTrip(final Trip trip) { __db.assertNotSuspendingTransaction(); } @Override public Runnable delete(final Trip trip) { __db.assertNotSuspendingTransaction(); } @Override public Runnable updateTrip(final Trip trip) { __db.assertNotSuspendingTransaction(); } @Override public void deleteTrips() { __db.assertNotSuspendingTransaction(); final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteTrips.acquire(); __db.beginTransaction(); try { _stmt.executeUpdateDelete(); __db.setTransactionSuccessful(); } finally { __db.endTransaction(); __preparedStmtOfDeleteTrips.release(_stmt); } } @Override public LiveData<List<Trip>> getAll() { final String _sql = "SELECT * FROM trip"; final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0); return __db.getInvalidationTracker().createLiveData(new String[]{"trip"}, false, new Callable<List<Trip>>() { @Override public List<Trip> call() throws Exception { final Cursor _cursor = DBUtil.query(__db, _statement, false, null); try { final int _cursorIndexOfUuid = CursorUtil.getColumnIndexOrThrow(_cursor, "uuid"); final int _cursorIndexOfTitle = CursorUtil.getColumnIndexOrThrow(_cursor, "title"); final int _cursorIndexOfDestination = CursorUtil.getColumnIndexOrThrow(_cursor, "destination"); final int _cursorIndexOfDate = CursorUtil.getColumnIndexOrThrow(_cursor, "date"); final int _cursorIndexOfDuration = CursorUtil.getColumnIndexOrThrow(_cursor, "duration"); final List<Trip> _result = new ArrayList<Trip>(_cursor.getCount()); while(_cursor.moveToNext()) { final Trip _item; _item = new Trip(); final String _tmp; if (_cursor.isNull(_cursorIndexOfUuid)) { _tmp = null; } else { _tmp = _cursor.getString(_cursorIndexOfUuid); } _item.uuid = __tripTypeConverter.toUUID(_tmp); if (_cursor.isNull(_cursorIndexOfTitle)) { _item.title = null; } else { _item.title = _cursor.getString(_cursorIndexOfTitle); } if (_cursor.isNull(_cursorIndexOfDestination)) { _item.destination = null; } else { _item.destination = _cursor.getString(_cursorIndexOfDestination); } if (_cursor.isNull(_cursorIndexOfDate)) { _item.date = null; } else { _item.date = _cursor.getString(_cursorIndexOfDate); } if (_cursor.isNull(_cursorIndexOfDuration)) { _item.duration = null; } else { _item.duration = _cursor.getString(_cursorIndexOfDuration); } _result.add(_item); } return _result; } finally { _cursor.close(); } } @Override protected void finalize() { _statement.release(); } }); } @Override public LiveData<Trip> getTrip(final UUID id) { final String _sql = "SELECT * FROM trip WHERE uuid=?"; final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1); int _argIndex = 1; final String _tmp; _tmp = __tripTypeConverter.fromUUID(id); if (_tmp == null) { _statement.bindNull(_argIndex); } else { _statement.bindString(_argIndex, _tmp); } return __db.getInvalidationTracker().createLiveData(new String[]{"trip"}, false, new Callable<Trip>() { @Override public Trip call() throws Exception { final Cursor _cursor = DBUtil.query(__db, _statement, false, null); try { final int _cursorIndexOfUuid = CursorUtil.getColumnIndexOrThrow(_cursor, "uuid"); final int _cursorIndexOfTitle = CursorUtil.getColumnIndexOrThrow(_cursor, "title"); final int _cursorIndexOfDestination = CursorUtil.getColumnIndexOrThrow(_cursor, "destination"); final int _cursorIndexOfDate = CursorUtil.getColumnIndexOrThrow(_cursor, "date"); final int _cursorIndexOfDuration = CursorUtil.getColumnIndexOrThrow(_cursor, "duration"); final Trip _result; if(_cursor.moveToFirst()) { _result = new Trip(); final String _tmp_1; if (_cursor.isNull(_cursorIndexOfUuid)) { _tmp_1 = null; } else { _tmp_1 = _cursor.getString(_cursorIndexOfUuid); } _result.uuid = __tripTypeConverter.toUUID(_tmp_1); if (_cursor.isNull(_cursorIndexOfTitle)) { _result.title = null; } else { _result.title = _cursor.getString(_cursorIndexOfTitle); } if (_cursor.isNull(_cursorIndexOfDestination)) { _result.destination = null; } else { _result.destination = _cursor.getString(_cursorIndexOfDestination); } if (_cursor.isNull(_cursorIndexOfDate)) { _result.date = null; } else { _result.date = _cursor.getString(_cursorIndexOfDate); } if (_cursor.isNull(_cursorIndexOfDuration)) { _result.duration = null; } else { _result.duration = _cursor.getString(_cursorIndexOfDuration); } } else { _result = null; } return _result; } finally { _cursor.close(); } } @Override protected void finalize() { _statement.release(); } }); } public static List<Class<?>> getRequiredConverters() { return Collections.emptyList(); } }
I’ve been told I need to use Executor for INSERT, UPDATE and DELETE so they don’t get block the main thread, so I’m not sure how to fix this without just removing the executors.
As far as I can figure, there’s no actual Runnable object to return, so it doesn’t know what to do? If I’ve got that wrong please correct me.
But yeah, I just can’t figure out how to get around the executor wanting a Runnable return type, but there being no Runnable to return. Any help would be appreciated
Advertisement
Answer
You are trying to tell room to return a Runnable
from the insert
. Room knows that an @Insert
can only return void or Long/long (the rowid
of the inserted row).
- if the
@Insert
inserts multiple rows then it can return void, long[] or Long[]. - if you were look at the Build log, then the
You can’t have :-
@Insert Runnable insertTrip(Trip trip);
It must be one of the following:-
@Insert void insertTrip(Trip trip);
or
@Insert long insertTrip(Trip trip);
or
@Insert Long insertTrip(Trip trip);
Similar for @Update and @Delete except they return int (the number or affected rows)
To get/use the Runnable you could use :-
void insertTrip(Trip trip){ executor.execute(new Runnable() { @Override public void run() { tripDao.insertTrip(trip); } }); }
- obviously likewise for the others.
Working example
Using (note with a simple Trip class but all other classes as per your question bar the changes above) :-
TripRepository.initialise(this); Trip atrip = new Trip(); atrip.tripName = "My Trip"; TripRepository.get().insertTrip(atrip);
Results in :-