Following Android Developer page says:
By default, all queries (#Query) must be executed on a thread other than the main thread. (You work on that later.) For operations such as inserting or deleting, if you use the provided convenience annotations, Room takes care of thread management for you.
Source: https://google-developer-training.gitbooks.io/android-developer-advanced-course-practicals/unit-6-working-with-architecture-components/lesson-14-room,-livedata,-viewmodel/14-1-a-room-livedata-viewmodel/14-1-a-room-livedata-viewmodel.html#task3intro
But this is not correct, right? Room does not automatically run insert and delete operations on a background thread. So what is this sentence supposed to mean?
It means that those room operations are thread-safe (so you don't have to take care of it if you e.g. run insert/delete operations on different background threads, source)
BY default you can't run room operation on the main thread.
You can use .allowMainThreadQueries() to run them in the main thread.
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "database")
.allowMainThreadQueries()
.build();
}
return INSTANCE;
Or you have to create an AsyncTask to perform room queries.
If you are running long-running operations using room you should use AsyncTask because running long-running operation on the main UI thread may cause your UI to block.
Related
I read on post that Coroutine isn't a good practice for using on splash screen and Executors is the best for that because Coroutine takes a time to start more than Executors, but I didn't find an example of implementing that, is the Executors is the normal java Executor class which used to manage thread pool?
First, for splash best performance you must read the link mentioned in comments by William Reed here and here and also this other link here
and when you read the articles focus on these words
The measurements were made on a debuggable app differ surprisingly
from production performance
As pointed out by Jake Wharton, the difference is partly due to
ExecutorService being preloaded by the Zygote, a special part of the
Android framework that shares code between processes. Other
concurrency frameworks which, like coroutines, aren’t preloaded, will
also have a comparatively high initialization cost. That said,
coroutines have a lot of advantages over ExecutorService. They’ve got
scopes, suspending functions, they’re much more lightweight than
threads, etc. The general recommendation to use them in Android
applications is sound, but their impressive feature set has an
initialization cost at the moment. Perhaps the Kotlin and Android
teams will be able to optimize this in the future. Until then, best to
avoid using coroutines in your Application class, or in your main
Activity, if startup time is a primary concern.
Second, for your other part of the question I think that is the Executor you asked about
And here how to use it
1 - To execute code in the main thread
// Create an executor that executes tasks in the main thread.
val mainExecutor = ContextCompat.getMainExecutor(this)
// Execute a task in the main thread
mainExecutor.execute {
// You code logic goes here.
}
2 - To execute code in a background thread
// Create an executor that executes tasks in a background thread.
val backgroundExecutor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
}
// Execute a task in the background thread after 3 seconds.
backgroundExecutor.schedule({
// Your code logic goes here
}, 3, TimeUnit.SECONDS)
Remember to shut down the executor after using.
backgroundExecutor.shutdown(); // or backgroundExecutor.shutdownNow();
3 - To execute code in a background thread and update UI on the main thread.
// Create an executor that executes tasks in the main thread.
val mainExecutor: Executor = ContextCompat.getMainExecutor(this)
// Create an executor that executes tasks in a background thread.
val backgroundExecutor = Executors.newSingleThreadScheduledExecutor()
// Execute a task in the background thread.
backgroundExecutor.execute {
// Your code logic goes here.
// Update UI on the main thread
mainExecutor.execute {
// You code logic goes here.
}
}
what is the best for performance on Debug (Production May vary as mentioned before)?- Executor, and Coroutine takes much time based on trying both of them with this function
fun TestPerformance(){
val startTime = System.nanoTime()
// DEBUG in handler 3002952707
Handler(Looper.getMainLooper()).postDelayed({
val endTime = System.nanoTime()
println("DEBUG in handler ${endTime-startTime}")
}, 3000)
// DEBUG in backgroundExecutor 3001161822
val backgroundExecutor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
backgroundExecutor.schedule({
val endTime = System.nanoTime()
println("DEBUG in backgroundExecutor ${endTime-startTime}")
}, 3, TimeUnit.SECONDS)
// DEBUG in GlobalScope 3046312603
GlobalScope.launch {
delay(3000)
val endTime = System.nanoTime()
println("DEBUG in GlobalScope ${endTime-startTime}")
}
}
As you can see I add another way to the comparison with handler too, and look at the comments in the code, both handler and Executor faster than Coroutine and sometimes handler wins and sometimes Executor wins, both of them gives the same performance.
and if you want more examples for how to use handler check this answer it's a great help and I used it in my answer.
once you have an Executor instance, you can submit multiple tasks to it, and have them executed one after another. You can't do that simply with a raw Thread.
Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time.
Executors.newSingleThreadExecutor().execute {
// todo.
}
According to Docs:
Room doesn't support database access on the main thread unless you've called allowMainThreadQueries() on the builder because it might lock the UI for a long period of time. Asynchronous queries—queries that return instances of LiveData or Flowable—are exempt from this rule because they asynchronously run the query on a background thread when needed.
I want to know how the LiveData observable do works in the background and get wrapped objects asynchronously?
LiveData it is all about main thread (ui), when you are creating your dao class, some thing like this:
#Dao
public interface DaoExample {
#Query("select * from example")
LiveData<List<ExampleModel>> getAllModels();
}
Under the hood room creates all needed stuff, some thread for background processing, live data for posting the latest data from table and so on. All this logic encapsulated inside dao/database. When you will insert a new row, room will save it (worker thread) then notify all observables stream (ui thread).
I'm trying to use realm with kotlin coroutines and make queries inside a new thread using withContext()
What I observe is that threads are switching in the loop making realm throws this exception: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
withContext(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
val images = mutableListOf<String>("id1", "id2", ...)
for (imageId in images) {
println("THREAD : ${Thread.currentThread().name}")
val image = realm.where<Image>().equalTo("imageId", imageId).findFirst()
delay(1000) // Can lead to an actual switching to another thread
}
realm.close()
}
As the dispatchers.IO documentation mention here: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html
"This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
* withContext(Dispatchers.IO) { ... } does not lead to an actual switching to another thread;
* typically execution continues in the same thread."
I don't understand why thread are switching in the loop.
How to manage realm instance with coroutine properly ?
You can run Realm in another new single thread in a Coroutine. For example
val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
jobs.launch(dispatcher) {
// create new Realm instance
}
Every time a coroutine is suspended, at the time it's resuming the dispatcher will find a thread for it to run on. It's quite likely that it will be a different thread than the one it ran on previously.
I have read that one of the ways to query data in room database is to use Livedata which can be used on the main thread as it is asynchronous.
I would like to use LiveData instead of RxJava or AsyncTask.
For this in my repository class I have function getSomeData() which returns LiveData> and I call this function in my viewModel constructor:
private var mObservableSomeData: LiveData<List<SomeData>>
init {
mObservableSomeData = repository.getSomeData()
}
fun getSomeData(): LiveData<List<SomeData>> {
return mObservableSomeData
}
However it crashes saying:
Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
What should I do?
As pointed out by #LieForBananas, most probably you are getting error while doing insertion. Whenever you have #Query and you are wrapping returned data into an observable e.g. LiveData or Flowable, your query gets executed on background thread by default.
Remember that Room Database ensure that the query returning observable is run on background thread. This is why, if you are wrapping returned value in Flowable, you don't have to explicitly write .subscribeOn(Schedulers.io) while creating observer. Whereas If you are using Flowable for network call(Single might be better because usually we need to emit only once), then you have to explicitly write .subscribeOn(Scheduler.io()) to run the call on a background thread.
Room doesn't allow database operation on the Main thread unless you allow database on the main thread with allowMainThreadQueries().
MyApp.database = Room.databaseBuilder(this,AppDatabase::class.java,"MyDatabase")
.allowMainThreadQueries()
.build()
As i read in the android annotations for thread document
We have four types of thread,
#MainThread
#UiThread
#WorkerThread
#BinderThread
What is differences?
The differences is:
#MainThread, first Thread run when app started,
#UiThread, run from MainThread for UI works,
#WorkerThread, that run when programmer define a thread
#BinderThread,uses for something like query()/insert()/update()/delete() methods in ContentProvider.