Why loop() in Looper class gets called multiple times - android

I have a simple piece of code which starts an intent but when I debug it passes through various classes and often makes me wonder why these classes get called every time and what tasks are they performing before coming back to normal execution.
the control of execution then shifts to View class and calls performClick()
after then it goes to Handler class and calls dispatchMessage(Message msg)
and at last, it calls loop() of Looper class a number of times before coming back to normal flow.
so can someone help me here understand what is happening under the hood and why this loop() gets called multiple times?

The loop() is part of the Looper class. Deep in your android app when your process initializes the application, the first thing the JVM looks for is an entry point, which in all Java applications is the main method. The android main method exists in a class called ActivityThread (check the AOSP for the activity thread).
The beauty of this class is that it does a few things,
The Looper in the ActivityThread's main method calls the prepareMainLooper() method. This. initializes the current thread as the application's main looper. i.e this is where your main thread receives its mainthread designation, that differs it from all other threads at runtime.
Also in the main method, a handler is responsible for managing a MessageQueue where messages from your app are received and handled. It is important to note a [Messages] can be executed by the MessageQueue as a Runnable or other executable object.
What makes android different than most desktop/console like java applications is the Looper class. This class has a Looper.loop() method that is called within the ActivityThread's main method, and it runs an infinite loop thanks to a for(;;){} (the double semicolon indicates infinite loop). This loop will continue to run indefinitely as unless the quit() is called externally. The loop method calls message.next() each time it has completed with a message, to retrieve a new message.
In short, without this infinite looping method, it would be difficult for android to have a basic way to process incoming messages asynchronously, which is at the core of Android's event driven nature. The loop is eagerly seeking new messages to process or pass to the handler.
Checkout the AOSP for a deeper dive if you're interested!

Related

Android- How defer main MessageQueue events during custom GLSurfaceView.Renderer.onDrawFrame(GL10 gl)?

Situation: Android
class GLRenderer implements GLSurfaceView.Renderer
..
void onDrawFrame(GL10 gl) {..}
class MainGLSurfaceView extends GLSurfaceView
..
setRenderer(new GLRenderer());
class MainActivity ..
..
boolean onTouchEvent(MotionEvent event) {..}
MainActivity.onTouchEvent receives and processes events, some of which change state used by onDrawFrame(gl).
Q 1: Is there a way to "put the message queue on hold" until onDrawFrame returns?
NOTE: my onDrawFrame might take up to ~1/3 second on a slow phone. If necessary, I can probably change it so that if it doesn't have information it needs, it can start fetching it in the background, return promptly, and then draw the new frame on a later draw request (triggered by a timer).
Q 1B: Perhaps the events are only interrupting the draw, because of something I'm doing to fetch data. Can events interrupt at any moment (in the middle of onDrawFrame), or is it only when my custom onDrawFrame logic makes certain (system?) calls?
A 1B: Unfortunately, with a breakpoint I caught the event interrupting in the middle of a computation (a VM "init" of a new instance of a small class used to hold a temporary value was all that was required, to be "interruptible"; something almost any java code might do). So I will need to cope with interrupting events, can't side-step them.
Q 2: Or would it be better to examine incoming messages, and somehow decide which ones should be handled immediately, and then ?do what? with other messages, to process them after onDrawFrame returns?
Q 3: I've made an attempt at Q 2, putting messages on to an internal queue. Then I tried processing them at end of the onDrawFrame method. This worked okay until a message which tried to open a confirmation dialog. Result: RuntimeException: Can't create handler inside thread that has not called Looper.prepare(). Yeah, I didn't think I should be doing it that way. Can i somehow shove those messages back on to the main message queue?
(I didn't want to create yet another thread, so at end of onDrawFrame I tried "new Handler().postDelayed(new Runnable() .." inside of which I was going to do something with those events. Oops - that has the same problem - can't create handler on the thread that onDrawFrame is running on.)
So the basic idea is that I seek a way to not pull the rug out from under the current draw frame. I'd rather not have to make all the event-triggered logic work on one set of data, then "freeze" that data (copy it), so that draw frame can work on a frozen set.
Q&A's that I looked at before asking this:
Message queue in android
This talks about creating a looper and a handler, including a link to another article. I might adapt this to create a handler attached to the main thread's looper. So instead of having to inject back into the MessageQueue, I just need to pass my secondary queue to this handler, and start it running. But I'm on the wrong thread at the time I want to start the handler, so not sure how to proceed. Hmm, maybe make a custom event, that I somehow trigger on the main thread?
How to pause the activity?
shows how to use a flag to pause a worker thread. Since I have multiple types of events I wish to defer, instead of that approach, it is easier to hold (copies of) those events on a separate queue. Then I just need to know how to "inject" them back into the main MessageQueue. I'm trying to avoid creating another thread, to minimize system resources.
How to pause a Thread's Message Queue in Android?
Alternate approaches (not using looper) when creating one's own thread, e.g. a worker thread. Doesn't help for my situation, which is UI events coming in to existing looper.
And in case there is some completely different way to tackle this:
isn't this a situation that everyone who uses GLSurfaceView rendering would encounter eventually?
Is there any example of a robust way to deal with gl drawing and asynchronous GUI events?
The final piece to my solution to "Q 3":
public class MainActivity ...
// Call this, if not already on UI thread.
public static void processQueuedEventsOnUIThread() {
try {
Runnable runnable = new Runnable() {
#Override
public void run() {
... process the deferred UI events, which I have stored on a private queue ...
}
};
MainActivity.mMainActivity.runOnUiThread(runnable);
} catch (Exception e) {
Log.e("MainActivity", "processQueuedEventsOnUIThread", e);
}
}
The last statement in my GLRenderer.onDrawFrame() is now
MainActivity.processQueuedEventsOnUIThread();
The exceptions no longer occur, even if the processed events cause a dialog window (with its own handler) to open. activity.runOnUiThread(runnable) is the essential step.

What is the use of implementing runnable in mainactivity

Recently, I am studying a code about printer Bluetooth connection.
The program try implement runnable in the MainActivity.
Here I would like to ask 2 question.
1.How can I execute the activity as a thread when there is no other program calling run() of this activity?
2.Is there any special meaning for implementing runnable in MainActivity? Are ther any difference between implementing runnable in a class other than MainActivity?
I am not too certain what you are asking in the first question because code inside Activity will always run on the main (UI) thread by default.
To answer your second question, the MainActivity is probably implementing the Runnable interface only to define some code that can be executed on a Thread later.
For example, you can call runOnUiThread (Runnable action) from the Activity, passing MainActivity.this as the runnable parameter to execute code on the main thread.
You can also spawn a new thread with the runnable to have it run in the background or post it to a handler.
There is a sequence of callback methods that start up an activity and a sequence of callback methods that tear down an activity.
1)Created 2)Started 3)Resumed 4) Paused 5) Stopped 6)Destroyed
However, only three of these states can be static :-3)Resumed 4) Paused 5) Stopped,,,,
Resumed State(Running state):- In this state, the activity is in the foreground and the user can interact with it.
(Also sometimes referred to as the "running" state.)
here are simply two rules to Android's single thread model:
1) Do not block the UI thread
2)Do not access the Android UI toolkit from outside the UI thread

Want to understand more about Android UI Thread's Event Queue

All over the web and on Stack Overflow there are references to the UI Thread's Event Queue. For example runOnUiThread() will post an action to the UI thread's Event Queue. But I haven't been able to find a detailed description of this queue, so could someone please point me to a detailed one, or answer a few questions?
1. I get that it's a queue and that it contains "actions", but I'm a little unclear what an "action" is. Are actions method calls with their associated parameters, or instructions to the thread itself, or what?
2. Do all threads have event queues or just the UI thread?
3. How can I see what's in the Event Queue, or get a count of events?
4. What exactly determines when an action in the queue is executed?
5. The View class has a method called cancelPendingInputEvents() which is used to "Cancel any deferred high-level input events that were previously posted to the event queue." If the event queue is a property of a thread, why is this a method of the View class, or do views have some different Event Queue?
6. Are the message queue and event queue two different queues? N.B. - someone asked this on SO here and the answerer started by saying they were synonymous and then appended an addendum which seemed to imply messages were different so I'm unclear what the final answer was.
it's a queue with Runnables. The thread calls run(); on each of the runnables.
only threads that called Looper.prepare(), so any thread can potentially have them. There's an Runtime Exception for that "Can't create handler inside thread that has not called Looper.prepare()"
You can't. Stuff is managed by the platform and calls Activity callbacks, Fragment callbacks, dispatch touch events, run animations, run layout, measure and draw. All this in the UI thread.
AFAIK it's a FIFO. But I might be wrong on that one.
Views have a Handler to the UI thread. Handlers are bound to the thread and it's MessageQueue. That's how you can create a new UI thread handler by calling new Handler() on the UI thread. And then post stuff to that thread queue by calling handler.post(Runnable)
I don't believe they're different. But would have to dig on source code to be sure.
It's always helpful to read the docs:
https://developer.android.com/reference/android/os/Handler.html
https://developer.android.com/reference/android/os/MessageQueue.html
It's just a standard message loop, like every GUI platform uses. "Event" is a CS term, not a particular object. Imagine that inside the Android framework you'd see something like this:
MessageQueue queue;
void run(){
while(1){
queue.waitForEvent();
Message msg = queue.getEvent();
//Handle msg
}
}
Only the UI thread has an event loop, although you could write your own on another thread.
You cannot see the event queue or get a list of events. The ones you need to know about will call some function in your code
Events are executed as soon as the thread can. If there are no events in the queue, the thread sleeps. They should be executed in order, although the framework may cheat on some events.
A message queue and event queue are the same thing. There's also a class called MessageQueue, which is not the same as the queue we're talking about here but which may be used to implement one.

Does posting a Runnable with a Handler make things asynchronous?

I am updating an activity's UI from a BroadcastReceiver that I register in the same activity. The API docs say:
[...] The function [onReceive()] is normally called within the main thread
of its process [...]
so I suppose updating the UI is okay.
The docs also say:
[...] you should never perform long-running operations in it (there is
a timeout of 10 seconds [...]
I am just setting some text on a TextView so I suppose that won't ever take longer than 10 seconds.
But, and here comes finally my actual question: Does it make any sense at all to add a Runnable to the main thread's message queue using a Handler, so that onReceive() can return immediately and the UI update happens at some later point in time, as the docs suggest:
There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; [...]
?
If you're just setting text on TextViews then you won't have issues. No need to over-complicate things with Handlers.
Though I will say that some people like using handlers just because it keeps things organized if multiple calls to a specific UI method need to be called. Using a handler will guarantee that that executed code will be initially placed on the UI thread, so it avoids having to check which thread you are running on.
The important thing to keep in mind is that all UI actions should be performed on the UI thread, and any sort of intensive processing should be done on a background thread.
Yes, using a Handler to schedule a Runnable is the standard.

Handler class and the timing of when its message queue is emptied

I was curious about the nature of the handleMessage() and sendMessage() behavior of the Handler class. I want to be able to send message to another thread in such a way that the destination thread can process the message queue when it wants to. It seems, however, that the message is processed by handleMessage() practically as soon as it's sent.
I'm trying to design a game loop thread that does something like this:
void run(){
while (gameIsActive){
handleInput();
updateGameState();
}
}
handleInput(){
//Remove an item from the handler's message queue
//which can be UI events (click, touch, etc.)
}
However, I as soon as sendMessage() is called (from the parent/calling thread), the Handler.handleMessage() is processed (in the child/receiving thread), even if the child/receiving thread is blocking in a while loop.
I've seen this problem solved in other games by using a thread-safe list (ConcurrentLinkedQueue). The UI thread just posts events to this queue, and the game loop can remove the events as it seems fit. I just assumed the Handler class was designed for this purpose. It seems it's more intended for asynchronous callbacks to the parent thread.
Well, I can't find a good answer about this timing (and it would be useful to know in other instances), but, as a workaround I just used a public List that was thread safe, and my UI thread can access this public list and add information to it. In particular I used a ConcurrentLinkedQueue. I found this in the official JetBoy game sample provided by Google, so maybe they don't even encourage using the Handler in this situation :)

Categories

Resources