I have written a simple app which detects photoplethysmogram (PPG) signals from a sensor on a smartwatch running Android Wear OS. I am currently attempting to record that data using Room so that I can access the data and perform analysis on it. I run into an issue when I attempt to insert data into the Database, giving me the following error:
2022-01-08 14:15:13.435 5482-5482/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.ppg_extraction_final, PID: 5482
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:469)
at androidx.room.RoomDatabase.beginTransaction(RoomDatabase.java:553)
at com.example.ppg_extraction_final.db.PpgDao_Impl.add(PpgDao_Impl.java:58)
at com.example.ppg_extraction_final.ui.MainActivity.writePpgData(MainActivity.java:98)
at com.example.ppg_extraction_final.ui.MainActivity.onSensorChanged(MainActivity.java:72)
at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:833)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:326)
at android.os.Looper.loop(Looper.java:160)
at android.app.ActivityThread.main(ActivityThread.java:6680)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I know that I am receiving this error because I am attempting to operate the database on the main thread, which will cause slowdowns with my UI. I also know that Kotlin coroutines provide a nice solution to this issue with relatively little boilerplate. However, having written my program in Java, I am a bit lost on the best method for correcting this error. Is it possible for me to implement the kotlin coroutines somehow in my current app structure? Is it worth migrating the entire app to kotlin? Is there another method to perform this action in java?
Here are the relevant parts of my MainActivity. PpgDatabase, PpgData, and PpgDao refer to my Database, Entity, and DAO classes, respectively. These are all in their own files. Please let me know if any of this code is needed!
public class MainActivity extends Activity implements SensorEventListener {
private TextView textView;
private SensorManager sensorManager;
PpgDatabase ppgDatabase;
PpgDao ppgDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
com.example.ppg_extraction_final.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
textView = findViewById(R.id.dataText);
// Instantiate sensor manager
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// Obtain db instance
ppgDatabase = DatabaseClient.getInstance(getApplicationContext()).getPpgDatabase();
// Instantiate ppg dao
ppgDao = ppgDatabase.getPpgDao();
}
public void onStartClick(View view) {
// Begin listening for sensor events on start click
// 65572 = PPG sensor type
sensorManager.registerListener(this, sensorManager.getDefaultSensor(65572),
sensorManager.SENSOR_DELAY_NORMAL);
}
public void onStopClick(View view) {
// Stop listening for sensor events on stop click
sensorManager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
// 65572 = PPG sensor type
if (event.sensor.getType() == 65572)
writePpgData(ppgDao, event);
}
public void writePpgData(PpgDao ppgDao, SensorEvent event) {
// Function for adding sensor event to db
PpgData ppgData = new PpgData();
ppgData.setCh0(event.values[0]);
ppgData.setCh1(event.values[1]);
ppgDao.add(ppgData);
}
}
I would appreciate any advice. Thanks!
I think Kotlin is preferred.
But since this issue alone shouldn't block you for so long, I think you should be able to use Executors.
See the Room Basic Sample by Google:
Specially the Database initialization
Here executors.diskIO()
is used to interact with the DataBase on a background thread
The executors are defined here.