I have some code which uses single HandlerThread with Handler to send messages to it. Is there any way to do this with coroutines? I don't want to create new coroutine every time, I just want to execute blocks of code on the HandlerThread. Please help
If you are looking to execute a block of code in the main Android thread, then you can use UI context from kotlinx-coroutines-android module like this:
launch(UI) {
... // this block of code will be executed in main thread
}
The above snippet sends a message to the main handler to execute your code.
If you looking for a custom handler thread for background work, then you can create a single-threaded context in one of two ways.
Generic approach: Use newSingleThreadedContext() like this:
val ctx = newSingleThreadedContext() // define your context
launch(ctx) { ... } // use it to submit your code there
Android-specific approach: Create new Android Handler, use Handler.asCoroutineDispatcher() extension to convert it to the coroutines context extension. Then you'll be able to use launch to send your blocks of code for execution.
Related
In an Android project, written in Kotlin, I have a data structure I want to perform some operations on on a single thread, because neither is designed to be thread safe, and the order of operations performed on it is important. I don't want that thread to be the main thread, because the operations are slow.
I've tried creating my threadContext multiple ways:
val threadContext = newFixedThreadPoolContext(1, "Background")
val threadContext = newSingleThreadContext("BioStackContext")
val threadContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
and every time, when I call run on it, I get isCurrent == true:
threadContext.run {
val isCurrent = Looper.getMainLooper().isCurrentThread()
However, if I call runBlocking on it, I get isCurrent == false:
runBlocking(threadContext) {
val isCurrent = Looper.getMainLooper().isCurrentThread()
How can I run it non-blocking in the background?
The run function you are calling is the Kotlin scope function, which has nothing to do with coroutines. It's a function that can be called on anything to create a lambda with it as the receiver, and the code is inline so it is run immediately on the current thread.
To use your dispatcher properly, you need a CoroutineScope that you use to launch a coroutine, and in that coroutine, you can use withContext(threadContext) to do your background work. On Android you should rarely need to create your own CoroutineScope, since Activities, Fragments, and ViewModels all provide you with one that is already scoped to their lifecycles.
If you were doing this task in an Activity or Fragment, it would look like this:
lifecycleScope.launch {
val result = withContext(threadContext) { // we are in the single thread context in this block
calculateSomethingTimeConsumingWithObjectOnlyWorkedWithOnMySingleThreadContext()
}
// Back on main thread:
updateUI(result)
}
In a ViewModel, you'd use viewModelScope instead of lifecycleScope.
I have an android linear search algorithm for finding duplicate files and packed it in the function
public void startSearch()
I was able to run it in a separate thread like this
class ThreadTest extends Thread {
public void run() {
startSearch()
}
}
but when i try to update the progressbar in that thread,it throws a exeption and says i the ui thread can only touch it's views
is there any other way to do this?
There are so many ways to do it, some of them are deprecated, some add unnecessary complexitiy to you app. I'm gonna give you few simple options that i like the most:
Build a new thread or thread pool, execute the heavy work and update the UI with a handler for the main looper:
Executors.newSingleThreadExecutor().execute(() -> {
//Long running operation
new Handler(Looper.getMainLooper()).post(() -> {
//Update ui on the main thread
});
});
Post the result to a MutableLiveData and observe it on the main thread:
MutableLiveData<Double> progressLiveData = new MutableLiveData<>();
progressLiveData.observe(this, progress -> {
//update ui with result
});
Executors.newSingleThreadExecutor().execute(() -> {
//Long running operation
progressLiveData.postValue(progress);
});
Import the WorkManager library build a worker for your process and observe the live data result on the main thread: https://developer.android.com/topic/libraries/architecture/workmanager/how-to/intermediate-progress#java
Complex can have different interpretations. The best way is to have Kotlin Courtines, RxJava with dispatchers.What you have mentioned is a way but if you have multiple threads dependent on each other, then thread management becomes trickier. On professional apps, you would want to avoid the method that you have mentioned because of scalability in future.
In one part of my application I post runnable to a Handler, then the code inside run() executes and posts the same runnable to Handler with postDelayed(). This creates something like loop. Is this behaviour achievable with coroutines? I tried to use channel, but I couldn't get it to work.
Is this behaviour achievable with coroutines?
Yes, and in an almost embarrassingly straightforward way:
launch(UI) {
while (!done()) {
// loop body
delay(loopDelayMillis)
}
}
I was learning about Looper and Handler and most time I read about it that it use to Communicate with UI thread. But then I saw the code which was child class of Handler with handleMessage(msg : Message) method then I got confused, because we can interact with GUI thread without extending Handler class.
As example in kotlin android.
val handler = Handler();
handler.post({
// update GUI here
});
So I can easily interact with GUI thread without implementing child class or handleMessage().
Let me explain little more about my quesiton. Sometime I see this example.
class HandlerSub : Handler(){
override fun handleMessage(msg : Message){
// update GUI here.
}
}
val handler = HandlerSub();
handler.send({
// send something..
});
So in the above example both code are being used for updating/interacting with GUI thread. but the 1st code is more simple easy and less code to interact with GUI.
Then what is real purpose of handleMessage() method and when we should implement it?
The sendMessage(...) call is used when you want message.obj to be some custom class, to send it to potentially another thread for processing. This is normally done by having message.what be an ID, and knowing the object type for that particular id's message.obj, then casting to that object type. This is used in many places throughout the Android framework, for example check the BluetoothStateMachine and how they handle processMessage(Message msg) in each one of their state classes. Each one of these states is delegated to by Handler.
I have a small Android application in which I need to do some FTP stuff every couple of seconds.
After learning the hard way that running network stuff on the UI thread is something Android does not really like, I've come to this solution:
// This class gets declared inside my Activity
private class CheckFtpTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... dummy) {
Thread.currentThread().setName("CheckFtpTask");
// Here I'll do the FTP stuff
ftpStuff();
return null;
}
}
// Member variables inside my activity
private Handler checkFtpHandler;
private Runnable checkFtpRunnable;
// I set up the task later in some of my Activitiy's method:
checkFtpHandler = new Handler();
checkFtpRunnable = new Runnable() {
#Override
public void run() {
new CheckFtpTask().execute((Void[])null);
checkFtpHandler.postDelayed(checkFtpRunnable, 5000);
}
};
checkFtpRunnable.run();
Is this good practice to perform a recurring task that cannot run on the UI thread directly?
Furthermore, instead of creating a new AsyncTask object all the time by calling
new CheckFtpTask().execute((Void[])null);
would it be an option to create the CheckFtpTask object once and then reuse it?
Or will that give me side effects?
Thanks in advance,
Jens.
would it be an option to create the CheckFtpTask object once and then reuse it? Or will that give me side effects?
No, there will be side-effects. Quoting the docs Threading Rules:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You will just need to create a separate instance of the task each time you want to run it.
And I'm not sure why you need the Runnable or Handler. AsyncTask has methods that run on the UI Thread (all but doInBackground(), actually) if you need to update the UI.
Check this answer if you need a callback to update the UI when the task has finished.
You should create a new Async task for every call.
See the Android Documentation: AsyncTask. According to this documentation:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Specifically check out the threading rules section. There is a similar answer here, https://stackoverflow.com/a/18547396/2728623
Java ThreadPools and the ExecutorFramework allows you to execute threads as needed and reduces thread creation overhead. Check out the singleThreadExecutor. The thread pool usage is pretty easy too!