How to post callbacks in Android to any arbitrary thread - java

I am using the Unity game engine which also supports exporting to Android.
The engine uses multiple threads, including the UI thread and a separate scripting thread where all the user custom code is executing.
My scenario requires that i call some operation in a background thread, and i would like to marshal the result back to the main scripting thread.
I know the basics of the AsyncTask, Executor and Looper classes. Out of these, Looper seems like a good candidate since it allows setting up a queue and post back messages to a given thread (AsyncTask is "hardwired" to run the callback on the UI thread, which is not what i want here).
What is the proper way of achieving this?

There is 3 main ways to communicate with the UI thread :
Activity.runOnUiThread(Runnable)
View.post(Runnable)
Handlers
In your case, I advice you to create an Handler, as the 2 first solutions imply that you have a reference on your Activity or a View
Edit
If you want to use any thread in your app, just make sure a Looper has been set, and use an associated Handler
class YourLooperThread extends Thread
{
// make it accessible from the outside
private Handler handler;
#Override public void run()
{
Looper.prepare();
// Customize your handler, it has to be used in any thread which want to push a message in this thread's looper message Queue
handler = new Handler();
Looper.loop();
}
}
Be careful : all the other tasks you want to do in that thread must be done through the message queue, i.e posting a runnable in the handler. More information here : Handlers, MessageQueue, Looper, do they all run on the UI thread?

Related

Correct way to communicate the result of a background thread to the Ui Thread in Android

This is one of the most confusing topics for me. So my question is, what is the correct way of communicate the result of background thread when this finish?.
Imagine I want to update some TextView with some information I just downloaded.There is 3 things I use when I need to perform background tasks:
AsyncTask
Very easy to use, this one has the onPostExecute() method that will return the result directly to the UiThread so I can use a callback interface or do whatever I want. I liked this class but it's deprecated.
ThreadPoolExecutor
This is what I actually use when need to perform background tasks and here comes my problem, the moment when I have to give the result to the UiThread. I have informed myself about Looper and Handler classes and about the mainLooper.
So, when I need to return some results I use the method runOnUiThread() that, as I have readed, just get the Looper of the Ui thread and post my Runnable to the queue.
Well this is working and I can communicate with the main thread but, I find it really ugly, and I am sure there is a more elegant way of doing it than populate all my code of "runOnUiThread()" methods. Also, if the background task need too much time, maybe the user already change of Activity or Fragment when the code inside runOnUiThread() runs what will cause Exceptions (I know using LiveData and MVVM pattern would solve this last problem but I am working in a legacy project and I can't refactor all the code so I am working with the clasical Activity mvc pattern)
So, there is another way of doing this? Could you give an example? I really searched a lot but didn't find anything...
Coroutines
I am actually working in a legacy project and I must use Java so can't use Kotlin coroutines, but I find them easy to use and so powerfull.
Any help would be appreciated!
Background
In Android, when an application is launched, the system creates a thread of execution for the application, called main thread (also known as the UI thread). Google introduces the main thread and its responsible as below.
The main thread has a very simple design: Its only job is to take and
execute blocks of work from a thread-safe work queue until its app is
terminated. The framework generates some of these blocks of work from
a variety of places. These places include callbacks associated with
lifecycle information, user events such as input, or events coming
from other apps and processes. In addition, app can explicitly enqueue
blocks on their own, without using the framework.
Nearly any block of code your app executes is tied to an event
callback, such as input, layout inflation, or draw. When something
triggers an event, the thread where the event happened pushes the
event out of itself, and into the main thread’s message queue. The
main thread can then service the event.
While an animation or screen update is occurring, the system tries to
execute a block of work (which is responsible for drawing the screen)
every 16ms or so, in order to render smoothly at 60 frames per second.
For the system to reach this goal, the UI/View hierarchy must update
on the main thread. However, when the main thread’s messaging queue
contains tasks that are either too numerous or too long for the main
thread to complete the update fast enough, the app should move this
work to a worker thread. If the main thread cannot finish executing
blocks of work within 16ms, the user may observe hitching, lagging, or
a lack of UI responsiveness to input. If the main thread blocks for
approximately five seconds, the system displays the Application Not
Responding (ANR) dialog, allowing the user to close the app directly.
To update a View, you must do it on the main thread, if you try to update in a background thread, the system will throw CalledFromWrongThreadException.
How to update a View on the main thread from a background thread?
The main thread has a Looper and a MessageQueue assigned with it. To update a View, we need to create a task then put it to the MessageQueue. To do that Android provides
Handler API which allows us to send a task to the main thread's MessageQueue for executing later.
// Create a handler that associated with Looper of the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());
// Send a task to the MessageQueue of the main thread
mainHandler.post(new Runnable() {
#Override
public void run() {
// Code will be executed on the main thread
}
});
To help developers easy to communicate with the main thread from a background thread, Android offers several methods:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Under the hood, they use Handler API to do their jobs.
Back to your question
AsyncTask
This is a class that is designed to be a helper class around Thread and Handler. It's responsible for:
Create a thread or pool of thread to do a task in the background
Create a Handler that associated with the main thread to send a task to the main thread's MessageQueue.
It is deprecated from API level 30
ThreadPoolExecutor
Create and handle a thread in Java is sometimes hard and might lead to a lot of bugs if developers do not handle it correctly. Java offers the ThreadPoolExecutor to create and manage threads more efficiently.
This API does not provide any method to update the UI.
Kotlin Coroutines
Coroutines is a solution for asynchronous programming on Android to simplify code that executes asynchronously. But it only available for Kotlin.
So my question is, what is the correct way of communicate the result
of background thread when this finish?.
1. Using Handler or mechanism built on Handler
1.1. If a thread is bounded with Activity/Fragment:
Activity.runOnUiThread(Runnable)
1.2. If a thread has a reference to a view, such as Adapter class.
View.post(Runnable)
View.postDelayed(Runnable, long)
1.3. If a thread does not bound to any UI element, then create a Handler on your own.
Handler mainHandler = new Handler(Looper.getMainLooper);
Note: A benefit of using Handler is you can use it to do 2 ways communication between threads. It means from a background thread you can send a task to the main thread's MessageQueue and from the main thread, you can send a task to the background's MessageQueue.
2. Using BroadcastReceiver
This API is designed to allow Android apps can send and receive broadcast messages from the Android system, other apps or components (Activity, Service, etc) inside the app, similar to publish-subscribe design partern.
Because of the BroadcastReceiver.onReceive(Context, Intent) method is called within the main thread by default. So you can use it to update the UI on the main thread. For example.
Send data from a background thread.
// Send result from a background thread to the main thread
Intent intent = new Intent("ACTION_UPDATE_TEXT_VIEW");
intent.putExtra("text", "This is a test from a background thread");
getApplicationContext().sendBroadcast(intent);
Receive data from activity/fragment
// Create a broadcast to receive message from the background thread
private BroadcastReceiver updateTextViewReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String text = intent.getStringExtra("text");
myTextView.setText(text);
}
};
#Override
protected void onStart() {
super.onStart();
// Start receiving the message
registerReceiver(updateTextViewReceiver, new IntentFilter("ACTION_UPDATE_TEXT_VIEW"));
}
#Override
protected void onStop() {
// Stop receving the message
unregisterReceiver(updateTextViewReceiver);
super.onStop();
}
This method is usually used to communicate between Android apps or Android apps with the system. Actually, you can use it to communicate between components in Android app, such as (Activity, Fragment, Service, Thread, etc.), but it requires a lot of code.
If you want a similar solution but less code, easy to use, then you can use the following method.
3. Using EventBus
EventBus is a publish/subscribe event bus for Android and Java. If you want to execute a method that runs on the main thread, just mark it with #Subscribe(threadMode = ThreadMode.MAIN) annotation.
// Step 1. Define events
public class UpdateViewEvent {
private String text;
public UpdateViewEvent(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
// Step 2. Prepare subscriber, usually inside activity/fragment
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
myTextView.setText = event.getText();
};
// Step 3. Register subscriber
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
// Step 4. Unregister subscriber
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// Step 5. Post events from a background thread
UpdateViewEvent event = new UpdateViewEvent("new name");
EventBus.getDefault().post(event);
This is useful when you want to update a View when the activity/fragment is visible to users (they are interacting with your app).
Since the very beginning (API 1) the android way of communication between threads has been Handler. Actually AsyncTask is just a wrapper around a thread pool and it uses Handler also to communicate to the main thread, you can check out the source code and create you own wrapper similarly.
Handler is the very low-level primitive and I wouldn't say using Handler is ugly, but it definitely requires some knowledge of multithreading programming and makes the code more verbose. As you also mentioned there are a lot of issues arises, like your UI can be gone by the time the task is completed and you have to handle this on your side. That's always the case with the low-level primitives.
As you are looking for reputable sources, here is the official documentation on exactly this problem - communicating a result from background thread to the main thread in plain java.
So unfortunately there is no other - better and officially recommended - way of doing that. Of course there are plenty of java libraries like rxJava that are build on top of the same primitives but provides higher level abstractions.
I personally use AsyncTask like this:
Setup a broadcastReceiver in my Activity or Fragment
Call the asyncTask with any needed arguments in an Object[] using the Executor of your choice.
Once the AsyncTask has completed I Bundle with the data or result, send a LocalBroadcast containing this bundle.
In my Fragment or activity receive the broadcast and handle the result.
I have never had any issues with this method, I do understand some people are shying away from AsyncTask, but for most purposes and all I have come across this is a simple and reliable method.

Post a Runnable to another thread in plain java

In Android we have Handler#post(Runnable) method to post some code to the main thread from another
Is it possible to make same thing in plain java (for instance while using swing)?
Explaining the question:
Assume we have two threads: ThreadA and ThreadB. Both are started already and running side-by-side. And ThreadB wants ThreadA to invoke some method (again, ThreadA is already running).
Addition optional question (you may not answer it):
And if it's possible, someone explain me how does exactly Handler do in Android. How it's able to post some code to MainThread? What is a purpose of the Looper?
Addressing your additional question:
You said "In Android we have Handler#post(Runnable) method to post some code to the main thread from another"
It is not exactly correct. You can 'post some code' from any thread A to any thread B provided that thread B is initialized as a Looper and the thread A has a reference to a Handler for the target thread B.
It is very convenient when you need to do something on the UI thread because the UI thread already has a Looper and you can retrieve it from nearly everywhere. The static method Looper.getMainLooper is a way to get a Looper for the main thread. If you initialize a Handler with this Looper you can post a Runnable or send a Message to it (though if you post Runnable it also gets wrapped into a Message) and it will be executed on the UI thread.
Looper, as the name hints, is basically running a non-terminating loop for a thread. The Looper has an associated MessageQueue which it constantly checks for new Messages. Via the Handler initialized with a Looper you can enqueue Messages on this thread. The Messages are processed in a sequential order, depending on the when field of a Message.
Here's a basic implementation of a Looper thread:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
I suggest you read the Chapter 5 of Meike G.B. Android Concurrency. It will give you a comprehensive insight into the Looper/Handler framework. It is also great to browse the source code while you are reading, it is rather simple and self-explanatory.
Within Swing you would use
https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingUtilities.html#invokeLater-java.lang.Runnable-
to run something on the main thread.
In general Java, an ExecutorService is like a thread pool and allows you to submit Runnable or Callable instances
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
However, if you aren't using an ExecutorService or Swing, there is no standard Java API to tell another thread to do something.

RxJava single background thread scheduler

I'm fairly new to RxJava so this is probably a dumb question. I am going to describe my scenario.
I have some code running on the UI thread which will update some images but those images are not very important and they consume a bit of resources while generating them so I want to generate them on a single thread (not the UI thread of course) and generate them one by one. I'm guessing the trampoline scheduler is what I want but my problem is that if I use it then it does the work on the UI thread and I want it to do it on another thread.
Obviously I can write my own thread in which I can queue items and then it processes those one by one but I thought maybe RxJava would have a simple solution for me?
My current code looks like this:
Observable<Bitmap> getImage = Observable.create(new Observable.OnSubscribe<Bitmap>() {
#Override public void call(Subscriber<? super Bitmap> subscriber) {
Log.w(TAG,"On ui thread? "+ UIUtils.isRunningOnUIThread());
subscriber.onNext(doComplexTaskToGetImage());
subscriber.onCompleted();
}
});
getImage.subscribeOn(Schedulers.trampoline()).subscribe(new Action1<Bitmap>() {
#Override public void call(Bitmap bitmap) {
codeToSetTheBitmap(bitmap);
}
});
My log that says "On ui thread?" always has true. So how do I make that code and all subsequent attempts to do the same thing run on a single thread (not the ui thread) in order without writing a bunch of code to queue that work?
Edit:
I believe that this can now be accomplished using Schedulers.single() or if you want your own you can use new SingleScheduler(). I'm still testing but I think it does what I wanted back when I posted this.
You can create a single reusable thread to create a Scheduler for the Observable in one of the following ways:
Create a ThreadPoolExecuter with a pool size of 1 (Executors.newSingleThreadExecutor() is a convenient static factory method for doing that), then use it to generate the schedulers via the Schedulers.from() method.
RxAndroid provides a custom Scheduler implementation that uses a Handler to schedule the actions, and thus can be used with any Thread that has a Looper running by passing it's Handler to the AndroidSchedulers.handlerThread() factory method.
Note that you will need to observe on a main thread Scheduler if you're interacting with the UI at the conclusion of these tasks.
In RxJava 2 you can use Schedulers.single() which:
Returns a default, shared, single-thread-backed Scheduler instance for
work requiring strongly-sequential execution on the same background
thread.
Please see the documentation for more details.
I don't see it available in RxJava 1 Schedulers documentation.
You are using trampoline scheduler, so it means your source observable will be run on the current thread (here is main thread).
And the subscribeOn will work for both upstream and downstream. That why your log shows your are running on the main thread
To fix this, you can use Schedulers.single() in the subscribeOn, and then observeOn the main thread.

Android multithreading and services

I am little bit confused with multithreading in Android. I am aware we can achieve using AsyncTask and Handler. Generally when should we implement by extending Thread Class in Android? Can anyone give an example that we need to do it only by extending thread class but not with AsyncTask or Handler.
Consider a example app, we have a bouncing ball in an activity(forget the animation part), I need to change the color of the ball every 20 minutes, and I need to get the color code from the server and update the ball UI. Now how can I achieve this ? Can someone explain using AsyncTask or Handler and also only using Thread Class(without Asynctask or Handler)?
How should I handle downloading large payloads from server using services.
Thread
Long task in general
Invoke by thread.start() method
Triggered from any thread
Runs on its own thread
Manual thread management/code may become difficult to read
AsyncTask
Small task having to communicate with main thread
Invoke by execute() method
Triggered from main thread
Runs on worker thread
Must be executed and created from the main Thread
Service
Task with no UI,but should not use for long Task. Use Thread within service for long Task
Invoke by onStartService()
Triggered from any Thread
Runs On Main Thread
May block main(UI) thread
IntentService
Long task usually no communication with main thread if communication is needed then it is done by Handler or broadcast
Invoke via Intent
Triggered from Main Thread (Intent is received on main Thread and worker thread is spawned)
Runs on separate thread
Can't run task in parallel and multiple intents are Queued on the same worker thread.
Thread: Use it to separate long running computation from Main Thread ( UI Thread). If you don't need to update UI or send messages back to UI Thread, use it for long running tasks. But you don't really need to extend Thread and write your logic by overriding Thread methods. But still HandlerThread is effective compared to java Thread.
AsyncTask : it is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few milli seconds at the most). Recommended for 5 milli seconds task execution.
Service: Use it to handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
HandlerThread/Handler: A HandlerThread is effectively a long-running thread that grabs work from a queue, and operates on it. You can use it even to send results back to UI Thread via Handler of UI Thread.
Have a look at below posts for more details:
Asynctask vs Thread vs Services vs Loader
Handler vs AsyncTask vs Thread
Creating Background Service in Android
Android: Toast in a thread
An AsyncTask is basically a thread. It has 3 callBack methods(main) and the are executed in this order top to bottom:
1. onPreExecute()
2. doInBackground()
3. onPostExecute()
4. onProgressUpdate()
The onPreExecute() and onPostExecute() are running on the UI thread and doInBackground() is a separate thread as such. If you spawn a thread(not a AsyncTask), and try to set a property of a UI element from it, this will raise an exception saying: the original thread(the UI thread) which created the view can only modify it. So only the UI thread has these two properties:
Only it can add/modify the UI of the App
It cannot be blocked for more than 5 secs(ANR exception)
So to over come both these limitations in one go, we have AsyncTask, it can run resource consuming operations(network access, implementing gaming logic etc) in doInBackground(), and still provide ability to alter the UI from onPreExecute() and onPreExecute().

AsyncTask, Handler, Thread... Which one to choose [duplicate]

This question already has answers here:
Handler vs AsyncTask vs Thread [closed]
(13 answers)
Closed 8 years ago.
I know this Question has been asked many times but all answers I got wasn't clear for Me.
I want to implement a File deletion process. I discovered that to do this kind of work it's recommended to run all the process in a separated thread.
For that, I can use AsyncTask, Handler and Thread. AsyncTask seems to be a good solution. However, AsyncTask is designed for small task. (When i try to delete a file whose length is more than 1G, AsyncTask crashes or doesn't execute onPostExecute.
Others thread handlers (Thread, Runnable...) can't manage UI (Update UI or show progress).
My Question is What is the good thread handler for Long tasks and How to manage UI with it.
First of all, if you need to perform work outside your main thread, but only while the user is interacting with your app, then you should create a new thread, otherwise use a Service.
Now, everything you can do with AsyncTask, you can also do it with a Thread(+ Handler). But the AsyncTask makes the developer job easier, because it is designed to communicate a worker thread with the main thread(caller thread). Now, if you use a Hanlder you can also communicate a worker thread with a caller thread(Note that the caller thread is not necessarily the main thread, it could be communication between two worker threads), if the caller thread is the main thread, you better use AsyncTask.
As far as i know, it goes something like this:
Use AsyncTask if you need to run a short task communicating with the UI thread
Use a Thread and Handler to run longer tasks that requires communication between the worker thread and the main thread(caller thread)
Use Thread, Handler and Looper (or HandlerThread, which is class for starting a thread that already has a Looper) for longer tasks that require communication between the worker thread and the caller thread(not the main thread).
Use IntentService for longer task that does not requires user interaction and needs only one worker thread.
The best for me, is the Asynctask, because the structure is well defined, you can know when is running the thread and when show the result.
http://masl.cis.gvsu.edu/2010/04/05/android-code-sample-asynchronous-http-connections/
Good article on using handlers above.
To delete using handler:
Create a runnable that does three things:
Delete file
Obtain msg and send on success
Obtain msg and send on failure
Using some framework to manage threads or using concurrency package, post the runnable and it will do the file Del off main thread. Handler callback will be msg success or msg fail that will process on main thread wherview controller.
Check out Needle and you can forget Handlers and AsyncTasks. Needle is an open-source, simple but powerful multithreading library for Android. With it you can say things like:
Needle.onMainThread().execute(new Runnable() {
#Override
public void run() {
// e.g. change one of the views
}
});
or
Needle.onBackgroundThread().execute(new UiRelatedTask<Integer>() {
#Override
protected Integer doWork() {
int result = 1+2;
return result;
}
#Override
protected void thenDoUiRelatedWork(Integer result) {
mSomeTextView.setText("result: " + result);
}
});
very simple API
fixed thread pool size
customizable thread pool size
supports UI interaction ("do work and then use result on UI thread")
android 1.5+
behaves the same on all platform versions
Check it out on GitHub: https://github.com/ZsoltSafrany/needle

Categories

Resources