using SurfaceTexture i need to call this function :
setOnFrameAvailableListener (SurfaceTexture.OnFrameAvailableListener listener,
Handler handler)
I would like to gave the Handler of the main UI thread, but I don't know how to get it ...
NOTE: i know i can do Handler handler = new Handler(Looper.getMainLooper()); but their is not an already created object of Handler accessible somewhere ?
HandlerThread handlerThread = new HandlerThread("BGHandler") // string here can be any name
handlerThread.start()
surfaceTexture.setOnFrameAvailableListener(this, Handler(handlerThread.getLooper())) //this means that the class calling this function implements the interface, I am sure u understand that since you have not asked for it, but if necessary I can elaborate more, just ask in the comments
Related
I have a class with multiple functions, each function were containing a separate handler to execute a runnable. Recently I realized that we must remove all the callbacks on the onDestroy method to avoid memory leaks, so for that, I declared a class-level handler and used the same handler to post runnable in all the functions.
Now my confusion is, what happens if we use the same instance of Handler for multiple runnable compared to a separate handler instance for each runnable?
No matter how many handlers you have, all those handler will pos their messages to the same queue which is main thread queue by default, unless you attach the handler to different looper objects excplicitly. To illustrate in code:
// This handler will be attached to the main thread's looper,
// hence to its queue implicitly but however this constructor
// is deprecated and is not recommended.
Handler handlerMain = new Handler();
// This handler will be attached to the main thread's looper
// object explicitly and this is the recommended way by Google.
Handler handlerMain = new Handler(Looper.getMainLooper());
// Another handler will be attached to the main thread's looper object.
Handler handlerMain2 = new Handler(Looper.getMainLooper());
// This is a custom handler thread whis has a looper object same as the apllication's main (ui) thread. But this one will be a background thread.
HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
// Now this handler will post messages to the mHandlerThread's queue.
// Hence you cannot access directly to the UI elements from this thread,
// you must post the ui touching codes to the main thread's queue.
Handler handlerCustom = new Handler(mHandlerThread.getLooper());
You can attach many handlers to a looper, the handlers are not the problem. The problem is the code that they post. You can post a delayed code that will be executed in a future time, and that code touches some UI elements of a fragment or access context of a fragment. The problem comes when the fragment's view and context is destroyed before the posted code has been executed.
It seems like just calling new Handler() associates the handler with the current thread’s looper without any thread-specific arguments being passed to the constructor.
How does it identify what the current thread is, though?
Why is calling new Handler() in specific methods (onLooperPrepared(), onCreate() ) mandatory?
How does it identify what the current thread is, though?
If you dive into the calling new Handler(), you'll see the source code, I'll show you :
The red rectangle shows you that you need a Looper when you new Handler.
The case mLooper==null only occurs when you call new Handler not in the UI thread, or you didn't call Looper.prepare() in your work-thread.
Also, you can associate the handler with the current thread’s looper obviously, refer to Define a handler on the UI thread, like handler = new Handler(Looper.getMainLooper()).
How does it identify what the current thread is, though?
By calling Thread.currentThread()static method
Why is calling new Handler() in specific methods (onLooperPrepared(), onCreate() ) mandatory?
It actually is not mandatory depending on the task you want your handler to do.
But in general Looper is required for Handler to process messages.
More: How to Use Thread, Looper and Handler in Android
I'm new to Android development. There seem to be 2 important classes when dealing with threading in Android: Looper and Handler. There are static Looper.myLooper() and Looper.getMainLooper() methods to get the current thread's looper and the UI thread's looper, respectively. However, there are no such static methods for Handler. If you want to post to the UI thread, for example, code samples suggest doing this:
new Handler(Looper.getMainLooper()).post(new Runnable() { ...
Why doesn't Handler expose a cached, static getMainHandler() method that looks like this? Wouldn't that avoid creating unnecessary garbage?
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
public static Handler getMainHandler() { return mainHandler; }
Each Looper might have many Handlers. So which Handler would you return for the main Looper?
You can add a Handler to a Looper using the code you provided.
The responsibility of a Looper is to pull messages from an associated message queue, find the message's target handler, and dispatch the message to it. The handler will receive the message and execute its handleMessage(Message) callback where custom message-handling logic is specified.
To post a message to the message queue, you call Handler.sendMessage() or, similarly, Handler.post(Runnable), which uses messages internally. sendMessage() is defined on Handler instead of, say, Looper, because in this way the Message's target can be set to the specified Handler. Therefore, when the Looper receives the message, it knows what specific handleMessage of what specific Handler to run.
Finally, let's say you have a static method that returns the "main" Handler, for example, the Handler used by the system to handle things like configuration changes. That would be quite dangerous as you could call handleMessage() yourself and trigger logic that should be triggered only by the system.
The quick answer is no, I'm afraid.
The common way to do what you ask in Android is to use Activity#runOnUiThread(Runnable).
Also, as an alternative way to be able to do this from any class, I like to provide the helper you can see in this other answer.
Finally, there are other alternatives, like using RxJava (with Android bindings) or other libraries like Anko for Kotlin.
I'm confused by Handler and HandlerThread classes usage. The reason I'm trying to use them is I want to utilize AudioRecord class and its setRecordPositionUpdateListener method (reference). The methos description says:
Use this method to receive AudioRecord events in the Handler associated with another thread than the one in which you created the AudioTrack instance.
And that's exactly what I want - to setup the AudioRecord in the main thread, but receive data in a working thread. I figure I need a HandlerThread so I've created and started one. I've also defined a callback method that implements AudioRecord.OnRecordPositionUpdateListener interface. I want this callback to be called from the worker HandlerThread. What I don't understand now is how to create the Handler to pass to setRecordPositionUpdateListener.
To associate Handler with a certain thread, you should create it by passing corresponding Looper in its constructor. So, if you already have a HandlerThread it can be done in the following way:
Looper looper = myHandlerThread.getLooper();
Handler handler = new Handler(looper);
And that's it, just use this handler in setRecordPositionUpdateListener method and callback will be executed at the worker thread. If you need more explanation on Handler, Looper and HandlerThread, you can take a look here.
There's something weird happening. I can't show all the code, but situation is like this;
Runnable program = new Runnable() {
#Override
public void run() {
//This code is running
new Handler();
//This code not running
}};
new Thread(program).start();
Log shows nothing. Main thread is working good.
You should always declare Handler in UI thread.You need to provide the Handler with a Looper from some thread.E.g. from main UI thread:
Handler mHandler = new Handler(Looper.getMainLooper());
Handler always runs in the Looper thread context. When you create another thread its context is different from the Looper. Right solution is to declare Handlers always in onCreate(), onStart() and onResume().
Creating a Handler needs a Looper polling on that thread first. By the way, there's usually no need to create a Handler inside non UI threads. Create a Handler outside the runnable. An easier alternative is to use runOnUiThread() method.