It's not recommended but you can access to database on main thread with allowMainThreadQueries()
MyApp.database = Room.databaseBuilder(this, AppDatabase::class.java, "MyDatabase").allowMainThreadQueries().build()
AsyncTask is really clunky. Coroutines are a cleaner alternative (just sprinkle a couple of keywords and your sync code becomes async).
// Step 1: add `suspend` to your fun
suspend fun roomFun(...): Int
suspend fun notRoomFun(...) = withContext(Dispatchers.IO) { ... }
// Step 2: launch from coroutine scope
private fun myFun() {
lifecycleScope.launch { // coroutine on Main
val queryResult = roomFun(...) // coroutine on IO
doStuff() // ...back on Main
}
}
Dependencies (adds coroutine scopes for arch components):
// lifecycleScope:
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha04'
// viewModelScope:
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha04'
-- Updates:
08-May-2019: Room 2.1 now supports suspend
13-Sep-2019: Updated to use Architecture components scope
Database access on main thread locking the UI is the error, like Dale said.
--EDIT 2--
Since many people may come across this answer... The best option nowadays, generally speaking, is Kotlin Coroutines. Room now supports it directly (currently in beta). https://kotlinlang.org/docs/reference/coroutines-overview.html https://developer.android.com/jetpack/androidx/releases/room#2.1.0-beta01
--EDIT 1--
For people wondering... You have other options. I recommend taking a look into the new ViewModel and LiveData components. LiveData works great with Room. https://developer.android.com/topic/libraries/architecture/livedata.html
Another option is the RxJava/RxAndroid. More powerful but more complex than LiveData. https://github.com/ReactiveX/RxJava
--Original answer--
Create a static nested class (to prevent memory leak) in your Activity extending AsyncTask.
private static class AgentAsyncTask extends AsyncTask<Void, Void, Integer> {
//Prevent leak
private WeakReference<Activity> weakActivity;
private String email;
private String phone;
private String license;
public AgentAsyncTask(Activity activity, String email, String phone, String license) {
weakActivity = new WeakReference<>(activity);
this.email = email;
this.phone = phone;
this.license = license;
}
@Override
protected Integer doInBackground(Void... params) {
AgentDao agentDao = MyApp.DatabaseSetup.getDatabase().agentDao();
return agentDao.agentsCount(email, phone, license);
}
@Override
protected void onPostExecute(Integer agentsCount) {
Activity activity = weakActivity.get();
if(activity == null) {
return;
}
if (agentsCount > 0) {
//2: If it already exists then prompt user
Toast.makeText(activity, "Agent already exists!", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(activity, "Agent does not exist! Hurray :)", Toast.LENGTH_LONG).show();
activity.onBackPressed();
}
}
}
Or you can create a final class on its own file.
Then execute it in the signUpAction(View view) method:
new AgentAsyncTask(this, email, phone, license).execute();
In some cases you might also want to hold a reference to the AgentAsyncTask in your activity so you can cancel it when the Activity is destroyed. But you would have to interrupt any transactions yourself.
Also, your question about the Google's test example... They state in that web page:
The recommended approach for testing your database implementation is writing a JUnit test that runs on an Android device. Because these tests don't require creating an activity, they should be faster to execute than your UI tests.
No Activity, no UI.
For all the RxJava or RxAndroid or RxKotlin lovers out there
Observable.just(db)
.subscribeOn(Schedulers.io())
.subscribe { db -> // database operation }
You cannot run it on main thread instead use handlers, async or working threads . A sample code is available here and read article over room library here : Android's Room Library
/**
* Insert and get data using Database Async way
*/
AsyncTask.execute(new Runnable() {
@Override
public void run() {
// Insert Data
AppDatabase.getInstance(context).userDao().insert(new User(1,"James","Mathew"));
// Get Data
AppDatabase.getInstance(context).userDao().getAllUsers();
}
});
If you want to run it on main thread which is not preferred way .
You can use this method to achieve on main thread Room.inMemoryDatabaseBuilder()
With lambda its easy to run with AsyncTask
AsyncTask.execute(() -> //run your query here );
Just do the database operations in a separate Thread. Like this (Kotlin):
Thread {
//Do your database´s operations here
}.start()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With