Communication between worker threads - android

I am programming in Android environment, and I have in my project a Main Activity, in which there is an AsynkTask class, and separately a Thread object, realized extending Runnable interface. Now, AsynkTask and the Thread can be seen as two worker threads managed by the main thread, that is the Main Activity. How can I do if I want to make possible the communication between the two worker threads, not involving the main thread? How can I use handlers to realize this? I know how to use handlers between main and worker threads. I want to know how use them only between the worker threads, because in this case I can't pass in constructors handlers, because in this case I can not directly instantiate a thread, passing it as a parameter the handler created by the main thread. The main thread must create two worker threads, and they must communicate without the involvement of the main thread.
I hope I have been clear enough.

If you want to use a Handler with a worker thread you have to create a Looper on that Thread as explained in http://developer.android.com/reference/android/os/Looper.html.
Like this:
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();
}
}
And then you can send messages to mHandler from any other Thread.

Related

Posting to Handler tied to current thread

I have a Handler, mHandler, tied to the main thread. mHandler resides in a Service. Say I now post a Runnable to mHandler from the main thread like so:
public class SomeService extends Service {
// Handler is created on the main thread
// (and hence it is tied to the main thread)
private Handler mHandler = new Handler();
#Override
public void onDestroy() {
// onDestroy runs on the main thread
// Is the code in this Runnable processed right away?
mHandler.post(new Runnable() {
// (Some code statements that are to be run on the main thread)
...
});
super.onDestroy();
}
}
I know the example is a little silly as the Handler is unnecessary. However, it is a good example for this question.
Now my questions are:
Will the code statements in the Runnable be processed right away as the thread that posts the Runnable is also the thread that is to process the Runnable? Or does it work differently as the Handler internally uses a MessageQueue and hence there might be Runnables posted to the Handler elsewhere (which arrive before my Runnable)?
Moreover, is it possible that the statements will never run as the post(Runnable r) is an async call and hence onDestroy() will finish and the Service will be killed by the system before the Handler gets to run the code.
Thank you in advance.
Since a Service does not imply a separate thread, your runnable will be posted at the end of the main Looper's queue, so yes, there may be messages/runnables scheduled before yours.
Again, since Service does not imply a distinct thread, a call to onDestroy does not mean that the Handler's thread has been terminated. In this example, you are posting to the main looper, and that thread is active until the application process terminates.

Android handler association

Android doc says: "Each Handler instance is associated with a single thread.."
So, if I define the following handler inside onCreate() method:
myHandler= new Handler();
then myHandler will be associated with the main (UI) thread?
I would like to see an example where a handler is "associated" with a worker thread. If you have any, I would appreciate.
Thanks.
There are two questions here.
The answer to the first is "yes". If that line of code is in onCreate, then myHandler is associated with the UI thread
A Handler is cannot be associated with just any thread. It must be associated with a Looper. The very first paragraph of the documentation of the Looper gives an example.
This much is true: If you use the default constructor for Handler, then your Handler object will be associated with the current thread - whatever it is.
However, you will note that the Handler class has several other constructors. If you provide the Looper argument to the Handler constructor, then your handler will be associated with the thread that is associated with the Looper. (Note that Looper detects and holds onto the thread that it is constructed in.)
You can create a Thread with a Looper by instantiating a Looper in the thread's run() method. But Android has already done this for you in the HandlerThread class: HandlerThread class is a subclass of Thread and has a Looper - perhaps a better name for HandlerThread would have been LooperThread. In any case, HandlerThread class also has a method called getLooper(). So, you first create an instance of HandlerThread, and then use its getLooper() as an argument to your Handler constructor:
HandlerThread myLooperThread=new HandlerThread("LooperThread");
myLooperThread.start();
Handler myLooperHandler=new Handler (myLooperThread.getLooper(),
new MyLooperHandlerCallback());
myLooperHandler.sendEmptyMessage(50);
The above snippet can be executed in your UI thread, but will still associate myLooperHandler with the HandlerThread's thread. You can verify this, by logging thread id, as in:
//runs in HandlerThread's thread
public class MyHandlerCallback implements Callback {
#Override
public boolean handleMessage(Message msg) {
Log.i("CALLBACK", "Thread ID:"+android.os.Process.myTid());
Log.i("CALLBACK", "msg.what:"+msg.what);
return true;
}
}
Note that it is best to instantiate threads in retained worker fragments, so that they are accessible across Activity boundaries.

Understanding what Looper is about in Android

I had to add Looper to the following code:
public class MyRunnable implements Runnable
{
#Override
public void run()
{
Looper.prepare();
final Looper looper = Looper.myLooper();
new Handler().postDelayed(
new Runnable()
{
#Override
public void run()
{
try
{
}
catch (Exception ex)
{
}
finally
{
looper.quit();
}
}
}, 100);
Looper.loop();
}
}
Notice that I have a runnable inside a runnable. The nested runnable gets executed through a Handler. Initially I didn't have Looper but Android complained that I needed to call Looper.prepare before executing another thread.
I read up on Looper but it still seems kind of cryptic. It seems to act like some kind of internal messaging pipeline. It isn't clear to me why this is necessary since there are no messages going from my outer runnable to my inner runnable. Even though that is true, it seems that Android just makes the hard rule that if you call a thread from a thread, you MUST also call Looper.prepare. Even if I accept that as-is, it still doesn't help to understand why I need to call looper.loop and looper.quit. If I omit Looper.loop, my Handler never runs and that is what isn't clear. What does Looper.loop do that allows my Handler to run?
Here is a great article about that.
Looper and Handler in Android
It comes along with a simple schema that leads to straight understanding of relationship between Loopers and Handler.
On this schema, we see that, within the same thread (depicted by the big rectangle), no matter how many handler you create, they will all be using the same Looper, i.e., the unique looper of this thread.
Note:
Looper have to be prepared to allow associated handler to process posted messages.
Android application, more precisely, android app UI thread(the main thread), already comes with a prepared looper (the mainLooper).
Here is how to Communicating with the UI Thread.
A simple concept of the looper:
Every worker thread you create and run ends once it performs its last operation.
To prevent your thread termination you can start a loop by calling Looper.loop(), think of it as while(true){} statement. Before calling Looper.loop() you have to prepare the loop with Looper.prepare(), if it is not prepared yet.
To terminate the loop and end your thread you will need to call looper.quit() on the looper.
Now for the notification you got from Android:
When you create a Handler in a thread, it will be bound to the thread it is created in and when you post runnable using this Handler, the code runs on the thread of the Handler.
So when the system saw that you want to run some code (especially 100ms in future) on a Handler that is bound to a thread that is going to die as soon as it finishes calling the post method it proposed to use Looper.loop() to prevent this thread from terminating and thus enabling you properly run the second Runnable in a still existing thread.
I find the following tutorial very helpful in understanding the concept of looper .
Intro to looper and handler

Threads And Handlers

My question Is that What is the difference between Thread and Handler
Q1) What are their effects When they are used in 1) Activity 2) Service
Q2) What is difference between them in context with their life span
I am using following codes for them.
1) ---------------------------
final Handler handler = new Handler();
Runnable runnable = new Runnable()
{
public void run()
{
// do somthing
handler.postDelayed(this, 1000);
}
};
runnable.run();
2) ---------------------------
handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
}
};
new Thread(new Runnable()
{
public void run()
{
while(true)
{
try
{
Thread.sleep(1000);
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {}
}
}
}).start();
Handler:
handler is used to do looper thing.that is to perform same task number of time.
handler can be executed on main thread.
about Handler if its used in service it may get stop if phone state change to sleep.
u can update the UI through handler if it used in activity.
Thread:
Thread is used to things on separate than the main thread of an activity.
thread always runs in background even if phone state changes to sleep mode.
u cant update the UI of as its not running on main thread.it can be done using asynctask not using simple java thread.
Q0) What is the difference between a thread and a handler?
A Thread is the same as it always is in programming. Each thread executes a single call to a method and then terminates. Each thread runs in parallel with every other thread. Threads are in short the way you have more than one thing happening at once.
Passing information between threads is notoriously difficult...
A Handler is Android's way of passing a message from one thread to another. Specifically it allows you to pass a set of instructions as a Runnable into a thread for that thread to execute. Typically they are used as a way for a thread to report its result back to the main thread when it's complete.
Q1) What are their effects When they are used in 1) Activity 2) Service
There is no difference between the way these two items behave in a service or an activity in general except that a service can exist in its own process if android is instructed to do so. Threads in different processes can not directly talk to one another. Services are there to share data,functionality and in some cases threads between activities. There is no requirement for them to have their own thread.
The one major point to note is that only the main thread can update the UI (activity).
Also networking specifically can not be done on the main thread. Networking is usually done from within a service so that the results can be shared but this is not necessary.
The limitations around what must and must not be done in the main thread make threading a little tricky, but these limitations are there to help you avoid freezing the UI unexpectedly.
Q2) What is difference between them in context with their life span I am using following codes for them.
Difficult to answer as I don't understand the purpose of your code.
As an example. Android no longer allows you to do any networking on the main thread as this could freeze the UI while it's waiting for the server to respond over a poor wifi connection. To change something on the UI based on something retrieved from the network you must use a thread to do the networking and pass the data back to the main thread to update the UI.
A (doctored) snippet from my code looks like this:
private final Handler handler = new Handler();
#Override
protected void onCreate( Bundle savedInstanceState ) {
// irreverent to the example
super.onCreate(savedInstanceState);
super.setContentView(R.layout.abstract_main_view);
// Here's the example
Thread networkThread = new Thread() {
#Override
public void run() {
// This could take several seconds
final Collection<Player> players = service.lookupAllPlayers();
Runnable uiUpdate = new Runnable() {
#Override
public void run() {
// This is quick, just adding some text on the screen
showPlayers(players);
}
};
handler.post(uiUpdate);
}
};
networkThread.start();
}
In this example:
The handler is created and exists for the duration of this activity. Because this class is constructed by the main thread, the Handler is also. This means that all messages posted to this handler will be executed by main.
networkThread is created and started by the main thread in onCreate. This lives until it has retrieved the data from the network and posted a response back to the main thread. Then it's done.
The Runnable uiUpdate is created by networkThread once all data is retrieved. It does not have a thread associated and so does not execute right away. Instead it is posted back to main using the handler. It is then executed on the main thread and discarded once complete.
One can use a Handler to inform one thread of events from another thread.
Typical usage would be to inform the UI Thread from other threads.
We can not modify UI elements from other threads directly. So we can define a Handler as a member of an Activity instead.
Activities are created on the UI Thread so this handler also is on UI Thread.
So then from another thread we send a message to the Handler. And on receiving the message the Handler modifies some UI elements.

What is the purpose of Looper and how to use it?

I am new to Android. I want to know what the Looper class does and also how to use it. I have read the Android Looper class documentation but I am unable to completely understand it.
I have seen it in a lot of places but unable to understand its purpose. Can anyone help me by defining the purpose of Looper and also by giving a simple example if possible?
What is Looper?
Looper is a class which is used to execute the Messages(Runnables) in a queue. Normal threads have no such queue, e.g. simple thread does not have any queue. It executes once and after method execution finishes, the thread will not run another Message(Runnable).
Where we can use Looper class?
If someone wants to execute multiple messages(Runnables) then he should use the Looper class which is responsible for creating a queue in the thread.
For example, while writing an application that downloads files from the internet, we can use Looper class to put files to be downloaded in the queue.
How it works?
There is prepare() method to prepare the Looper. Then you can use loop() method to create a message loop in the current thread and now your Looper is ready to execute the requests in the queue until you quit the loop.
Here is the code by which you can prepare the Looper.
class LooperThread extends Thread {
public Handler mHandler;
#Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
You can better understand what Looper is in the context of the GUI framework. Looper is made to do 2 things.
Looper transforms a normal thread into something run continuously until Android app is running.
Looper provides a queue where jobs to be done are enqueued.
As you may know, when an application is launched, the system creates a thread of execution for the application, called “main”, and Android applications normally run entirely on a single thread by default the “main thread”. But main thread is not a secret, special thread. It's just a normal thread similar to one you can create with new Thread(), which means it terminates when its run() method returns! Think of below example.
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
Now, let's apply this simple principle to Android apps. What would happen if an Android app runs on a normal thread? A thread called "main" or "UI" or whatever starts your application and draws all UI. So the first screen is displayed to users. What now? The main thread terminates? No, it shouldn’t. It should wait until users do something, right? But how can we achieve this behavior? Well, we can try with Object.wait() or Thread.sleep(). For example, main thread finishes its initial job to display first screen, and sleeps. It awakes, which means interrupted, when a new job to do is fetched. So far so good, but at this moment we need a queue-like data structure to hold multiple jobs. Think about a case when a user touches screen serially, and a task takes longer time to finish. So, we need to have a data structure to hold jobs to be done in first-in-first-out manner. Also, you may imagine, implementing ever-running-and-process-job-when-arrived thread using interrupt is not easy, and leads to complex and often unmaintainable code. We'd rather create a new mechanism for such purpose, and that is what Looper is all about. The official document of Looper class says, "Threads by default do not have a message loop associated with them", and Looper is a class "used to run a message loop for a thread". Now you can understand what it means.
To make things more clear, let's check the code where the main thread is transformed. It all happens in ActivityThread class. In its main() method, you can find below code, which turns a normal thread into something that we need.
public final class ActivityThread {
...
public static void main(String[] args) {
...
Looper.prepareMainLooper();
Looper.loop();
...
}
}
and Looper.loop() method loop infinitely and dequeue a message and process one at a time:
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
}
}
So, basically, Looper is a class that is made to address a problem that occurs in the GUI framework. But this kind of need can also happen in other situations as well. Actually, it is a pretty famous pattern for multi-thread applications, and you can learn more about it in "Concurrent Programming in Java" by Doug Lea(Especially, chapter 4.1.4 "Worker Threads" would be helpful). Also, you can imagine this kind of mechanism is not unique in Android framework, but all GUI framework may need somewhat similar. You can find almost same mechanism in Java Swing framework too.
Looper allows tasks to be executed sequentially on a single thread. And handler defines those tasks that we need to be executed. It is a typical scenario that I am trying to illustrate in this example:
class SampleLooper extends Thread {
#Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
} catch (Throwable t) {
Log.e(TAG, "halted due to an error", t);
}
}
}
Now we can use the handler in some other threads(say ui thread) to post the task on Looper to execute.
handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
}
});
On UI thread we have an implicit Looper that allow us to handle the messages on ui thread.
Android Looper is a wrapper to attach MessageQueue to Thread and it manages Queue processing. It looks very cryptic in Android documentation and many times we may face Looper related UI access issues. If we don't understand the basics it becomes very tough to handle.
Here is an article which explains Looper life cycle, how to use it and usage of Looper in Handler
Looper = Thread + MessageQueue
Simplest Definition of Looper & Handler:
Looper is a class that turns a thread into a Pipeline Thread and Handler gives you a mechanism to push tasks into this pipe from any other threads.
Details in general wording:
So a PipeLine Thread is a thread which can accept more tasks from other threads through a Handler.
The Looper is named so because it implements the loop – takes the next task, executes it, then takes the next one and so on. The Handler is called a handler because it is used to handle or accept that next task each time from any other thread and pass to Looper (Thread or PipeLine Thread).
Example:
A Looper and Handler or PipeLine Thread's very perfect example is to download more than one images or upload them to a server (Http) one by one in a single thread instead of starting a new Thread for each network call in the background.
Read more here about Looper and Handler and the definition of Pipeline Thread:
Android Guts: Intro to Loopers and Handlers
Understanding Looper Threads
A java Thread a unit of execution which was designed to perform a task in its run() method & terminate after that:
But in Android there are many use cases where we need to keep a Thread alive and wait for user inputs/events for eg. UI thread aka Main Thread.
Main thread in Android is a Java thread which is first started by JVM at the launch of an app and keeps on running till the user choose to close it or encounters unhandled exception.
When an application is launched, the system creates a thread of
execution for the application, called "main." This thread is very
important because it is in charge of dispatching events to the
appropriate user interface widgets, including drawing events.
Now point to note here is although main thread is Java thread yet it keeps on listening to user events and draw 60 fps frames on screen and still it wont die after each cycle. how is it so?
The answer is Looper Class: Looper is a class which is used to keep a thread alive and manage a message queue to execute tasks on
that thread.
Threads by default do not have a message loop associated with them but you can assign one by calling Looper.prepare() in the run method and then call the Looper.loop().
Purpose of Looper is to keep a Thread alive and wait for next cycle of
input Message object to perform computation which otherwise will get
destroyed after first cycle of execution.
If you want to dig deeper how Looper manage Message object queue then you can have a look at source code of Looperclass:
https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/os/Looper.java
Below is an example of how you can create a Looper Thread and communicate with Activity class using LocalBroadcast
class LooperThread : Thread() {
// sendMessage success result on UI
private fun sendServerResult(result: String) {
val resultIntent = Intent(ServerService.ACTION)
resultIntent.putExtra(ServerService.RESULT_CODE, Activity.RESULT_OK)
resultIntent.putExtra(ServerService.RESULT_VALUE, result)
LocalBroadcastManager.getInstance(AppController.getAppController()).sendBroadcast(resultIntent)
}
override fun run() {
val looperIsNotPreparedInCurrentThread = Looper.myLooper() == null
// Prepare Looper if not already prepared
if (looperIsNotPreparedInCurrentThread) {
Looper.prepare()
}
// Create a handler to handle messaged from Activity
handler = Handler(Handler.Callback { message ->
// Messages sent to Looper thread will be visible here
Log.e(TAG, "Received Message" + message.data.toString())
//message from Activity
val result = message.data.getString(MainActivity.BUNDLE_KEY)
// Send Result Back to activity
sendServerResult(result)
true
})
// Keep on looping till new messages arrive
if (looperIsNotPreparedInCurrentThread) {
Looper.loop()
}
}
//Create and send a new message to looper
fun sendMessage(messageToSend: String) {
//Create and post a new message to handler
handler!!.sendMessage(createMessage(messageToSend))
}
// Bundle Data in message object
private fun createMessage(messageToSend: String): Message {
val message = Message()
val bundle = Bundle()
bundle.putString(MainActivity.BUNDLE_KEY, messageToSend)
message.data = bundle
return message
}
companion object {
var handler: Handler? = null // in Android Handler should be static or leaks might occur
private val TAG = javaClass.simpleName
}
}
Usage:
class MainActivity : AppCompatActivity() {
private var looperThread: LooperThread? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start looper thread
startLooperThread()
// Send messages to Looper Thread
sendMessage.setOnClickListener {
// send random messages to looper thread
val messageToSend = "" + Math.random()
// post message
looperThread!!.sendMessage(messageToSend)
}
}
override fun onResume() {
super.onResume()
//Register to Server Service callback
val filterServer = IntentFilter(ServerService.ACTION)
LocalBroadcastManager.getInstance(this).registerReceiver(serverReceiver, filterServer)
}
override fun onPause() {
super.onPause()
//Stop Server service callbacks
LocalBroadcastManager.getInstance(this).unregisterReceiver(serverReceiver)
}
// Define the callback for what to do when data is received
private val serverReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val resultCode = intent.getIntExtra(ServerService.RESULT_CODE, Activity.RESULT_CANCELED)
if (resultCode == Activity.RESULT_OK) {
val resultValue = intent.getStringExtra(ServerService.RESULT_VALUE)
Log.e(MainActivity.TAG, "Server result : $resultValue")
serverOutput.text =
(serverOutput.text.toString()
+ "\n"
+ "Received : " + resultValue)
serverScrollView.post( { serverScrollView.fullScroll(View.FOCUS_DOWN) })
}
}
}
private fun startLooperThread() {
// create and start a new LooperThread
looperThread = LooperThread()
looperThread!!.name = "Main Looper Thread"
looperThread!!.start()
}
companion object {
val BUNDLE_KEY = "handlerMsgBundle"
private val TAG = javaClass.simpleName
}
}
Can we use Async task or Intent Services instead?
Async tasks are designed to perform a short operation in background and give progres & results on UI thread. Async tasks have limits like you cant create more than 128 Async tasks and ThreadPoolExecutor will allow only upto 5 Async tasks.
IntentServices are also designed to do background task for a little longer duration and you can use LocalBroadcast to communicate with Activity. But services get destroyed after task execution. If you want to keep it running for a long time than you need to do hecks like while(true){...}.
Other meaningful use cases for Looper Thread:
Used for 2 way socket communication where server keep on listening to Client socket and write back acknowledgment
Bitmap processing in background. Pass the image url to Looper thread and it will apply filter effects and store it in tempe rory location and then broadcast temp path of image.
Life span of java Thread is over after completion of run() method. Same thread can't be started again.
Looper transforms normal Thread into a message loop. Key methods of Looper are :
void prepare ()
Initialize the current thread as a looper. This gives you a chance to create handlers that then reference this looper, before actually starting the loop. Be sure to call loop() after calling this method, and end it by calling quit().
void loop ()
Run the message queue in this thread. Be sure to call quit() to end the loop.
void quit()
Quits the looper.
Causes the loop() method to terminate without processing any more messages in the message queue.
This mindorks article by Janishar explains the core concepts in nice way.
Looper is associated with a Thread. If you need Looper on UI thread, Looper.getMainLooper() will return associated thread.
You need Looper to be associated with a Handler.
Looper, Handler, and HandlerThread are the Android’s way of solving the problems of asynchronous programming.
Once you have Handler, you can call below APIs.
post (Runnable r)
Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
boolean sendMessage (Message msg)
Pushes a message onto the end of the message queue after all pending messages before the current time. It will be received in handleMessage(Message), in the thread attached to this handler.
HandlerThread is handy class for starting a new thread that has a looper. The looper can then be used to create handler classes
In some scenarios, you can't run Runnable tasks on UI Thread.
e.g. Network operations : Send message on a socket, open an URL and get content by reading InputStream
In these cases, HandlerThread is useful. You can get Looper object from HandlerThread and create a Handler on HandlerThread instead of main thread.
The HandlerThread code will be like this:
#Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Refer to below post for example code:
Android: Toast in a thread
A Looper has a synchronized MessageQueue that's used to process Messages placed on the queue.
It implements a Thread Specific Storage Pattern.
Only one Looper per Thread. Key methods include prepare(),loop() and quit().
prepare() initializes the current Thread as a Looper. prepare() is static method that uses the ThreadLocal class as shown below.
public static void prepare(){
...
sThreadLocal.set
(new Looper());
}
prepare() must be called explicitly before running the event loop.
loop() runs the event loop which waits for Messages to arrive on a specific Thread's messagequeue. Once the next Message is received,the loop() method dispatches the Message to its target handler
quit() shuts down the event loop. It doesn't terminate the loop,but instead it enqueues a special message
Looper can be programmed in a Thread via several steps
Extend Thread
Call Looper.prepare() to initialize Thread as a Looper
Create one or more Handler(s) to process the incoming messages
Call Looper.loop() to process messages until the loop is told to quit().
This answer has nothing to do with the question, but the use of looper and the way people created the handler and looper in ALL the answers here are plain bad practice (some explanations are correct though), I have to post this:
HandlerThread thread = new HandlerThread(threadName);
thread.start();
Looper looper = thread.getLooper();
Handler myHandler = new Handler(looper);
and for a full implementation
What is Looper?
FROM DOCS
Looper
Looper Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
A Looper is a message handling loop:
An important character of Looper is that it's associated with the thread within which the Looper is created
The Looper class maintains a MessageQueue, which contains a list messages. An important character of Looper is that it's associated with the thread within which the Looper is created.
The Looper is named so because it implements the loop – takes the next task, executes it, then takes the next one and so on. The Handler is called a handler because someone could not invent a better name
Android Looper is a Java class within the Android user interface that together with the Handler class to process UI events such as button clicks, screen redraws and orientation switches.
How it works?
Creating Looper
A thread gets a Looper and MessageQueue by calling Looper.prepare() after its running. Looper.prepare() identifies the calling thread, creates a Looper and MessageQueue object and associate the thread
SAMPLE CODE
class MyLooperThread extends Thread {
public Handler mHandler;
public void run() {
// preparing a looper on current thread
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
Looper.loop();
}
}
For more information check below post
What is the relationship between Looper, Handler and MessageQueue in Android?
Android Guts: Intro to Loopers and Handlers
Understanding Android Core: Looper, Handler, and HandlerThread
Handler in Android
What Is Android Looper?
Android: Looper, Handler, HandlerThread. Part I.
MessageQueue and Looper in Android
Handling multiple down or upload items in a Service is a better example.
Handler and AsnycTask are often used to propagate Events/Messages between the UI (thread) and a worker thread or to delay actions. So they are more related to UI.
A Looper handles tasks (Runnables, Futures) in a thread related queue in the background - even with no user interaction or a displayed UI (app downloads a file in the background during a call).
I will try to explain the purpose of looper class as simple as possible.
With a normal thread of Java when the run method completes the execution we say the thread has done it's job and thread lives no longer after that.
what if we want to execute more tasks throughout our program with that same thread which is not living anymore?
Oh there is a problem now right? Yes because we want to execute more tasks but the thread in not alive anymore. It is where the Looper comes in to rescue us.
Looper as the name suggests loops. Looper is nothing more than an infinite loop inside your thread. So, it keeps the thread alive for an infinite time until we explicitly calls quit() method. Calling quit() method on the infinitely alive thread will make the condition false in the infinite loop inside the thread thus, infinite loop will exit. so, the thread will die or will no longer be alive. And it's critical to call the quit() method on our Thread to which looper is attached otherwise they will be there in your system just like Zombies.
So, for example if we want to create a background thread to do some multiple tasks over it. we will create a simple Java's thread and will use Looper class to prepare a looper and attach the prepared looper with that thread so that our thread can live as longer as we want them because we can always call quit() anytime whenever we want to terminate our thread. So our the looper will keep our thread alive thus we will be able to execute multiple tasks with the same thread and when we are done we will call quit() to terminate the thread.
What if we want our Main thread or UI thread to display the results computed by the background thread or non-UI thread on some UI elements?
for that purpose there comes in the concept of Handlers;
via handlers we can do inter-process communication or say via handlers two threads can communicate with each other.
So, the main thread will have an associated Handler and Background thread will communicate with Main Thread via that handler to get the task done of displaying the results computed by it on some UI elements on Main thread.
I know I am explaining only theory here but try to understand the concept because understanding the concept in depth is very important. And I am posting a link below which will take you to a small video series about Looper, Handler and HandlerThread and I will highly recommend watching it and all these concepts will get cleared with examples there.
https://www.youtube.com/watch?v=rfLMwbOKLRk&list=PL6nth5sRD25hVezlyqlBO9dafKMc5fAU2&index=1
I try to give an example in Kotlin. Here is below the code example.
Firstly we need to instantiate variable handler from the Handler(the provided looper instead of the default one) which ask for mainthread (Looper.getMainLooper()).
The function getAllCourses() need to return LiveData so we use handler.postDelayed() to be added to the message queque and run after x amount of millisecond specified in constant SERVICE_LATENCY_IN_MILLIS.
Please feel free to elaborate more wording to my explanation to give more clarity.
class RemoteDataSource private constructor(private val jsonHelper: JsonHelper) {
private val handler = Handler(Looper.getMainLooper())
companion object {
private const val SERVICE_LATENCY_IN_MILLIS: Long = 2000
#Volatile
private var instance: RemoteDataSource? = null
fun getInstance(helper: JsonHelper): RemoteDataSource =
instance ?: synchronized(this) {
RemoteDataSource(helper).apply { instance = this }
}
}
fun getAllCourses(): LiveData<ApiResponse<List<CourseResponse>>> {
EspressoIdlingResource.increment()
val resultCourse = MutableLiveData<ApiResponse<List<CourseResponse>>>()
handler.postDelayed({
resultCourse.value = ApiResponse.success(jsonHelper.loadCourses())
EspressoIdlingResource.decrement()
}, SERVICE_LATENCY_IN_MILLIS)
return resultCourse
}

Categories

Resources