Is there a robust way to detect if Thread.currentThread() is the Android system UI thread in an application?
I would like to put some asserts in my model code that asserts that only one thread (eg the ui thread) accesses my state, to assure that no kind of synchronization is necessary.
Common practice to determine the UI Thread's identity is via Looper#getMainLooper:
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
From API level 23 and up, there's a slightly more readable approach using new helper method isCurrentThread on the main looper:
if (Looper.getMainLooper().isCurrentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
I think that best way is this:
if (Looper.getMainLooper().equals(Looper.myLooper())) {
// UI thread
} else {
// Non UI thread
}
As of API level 23 the Looper has a nice helper method isCurrentThread. You could get the mainLooper and see if it's the one for the current thread this way:
Looper.getMainLooper().isCurrentThread()
It's practically the same as:
Looper.getMainLooper().getThread() == Thread.currentThread()
but it could be a bit more readable and easier to remember.
public boolean onUIThread() {
return Looper.getMainLooper().isCurrentThread();
}
But it requires API level 23
Besides checking looper, if you ever tried to logout thread id in onCreate(), you could find the UI thread(main thread) id always equals to 1. Therefore
if (Thread.currentThread().getId() == 1) {
// UI thread
}
else {
// other thread
}
Nice extension for Kotlin:
val Thread.isMain get() = Looper.getMainLooper().thread == Thread.currentThread()
So you just call:
Thread.currentThread().isMain
Couldn't you use the runOnUiThread method in the Activity class?See..
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29
Related
I am executing tasks parallelly on threads using threadPoolExecuter and i want to wait for all the tasks to complete without blocking the main ui. I don't want to use async task here. and methods like service.awaitTermination() is blocking the main ui.I have checked similar questions but didn't find answer to my particular problem. I am using a for loop to pass runnables to threads like this :
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info));
}
MyTask() function execute the same opertaion for all the ApplicationInfo type objects here.
Please help.....
Well, I can see you are using java, so probably you aren't allowed for some reason to use coroutines. With coroutines, it would be easier to achieve such a result.
Consider using them, especially have a look at their way to solve your problem.
What I would use in your case is - CountDownLatch.
Your code will look similar to this one:
CountDownLatch latch = new CountDownLatch(applicationInfoList.size);
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info, latch));
}
latch.await();
MyTask under the hood should call latch.countDown() when your work is done.
latch.await() throws InterruptedException so it should be handled.
Note: Anyway, it blocks the thread you are currently on.
The easiest way would be to migrate this logic to Runnable and provide a callback:
class YourButchTask implements Runnable {
private WorkDoneCallback callback;
public YourButchTask(WorkDoneCallback callback) {
this.callback = callback;
}
#Override
public void run() {
CountDownLatch latch = new CountDownLatch(applicationInfoList.size);
for (ApplicationInfo info : applicationInfoList) {
service.execute(new MyTask(info, latch));
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
//handle it
}
callback.workWasDone();
}
}
Afterward, you can submit your task to your service.
Note: your callback will be invoked from the executor thread, so you aren't allowed to access UI from it.
Here is a nice and simple tutorial, hopefully, that will help.
Update:
To be clear - Callback is your custom interface that will notify you when the work is done. Go ahead and use SAM, example:
interface WorkDoneCallback{
void workWasDone();
}
P.S. To redirect calls on main thread just use Handler with mainLooper under the hood, or runOnUiThread().
I am trying to compress an image in android but and I don't want to use runBlocking.
How can I make the main UI thread to wait for the compression to take place?
Currently, I am doing this
var compressedImage: File? = null
runBlocking {
compressedImage = Compressor.compress(this#UpdateProfileActivity, cachedFile.absoluteFile)
}
camera = "gallery"
//doing something with the compressedImage.
How to do it without runBlocking?
You should not make the main-thread to wait for task completion. It causes freezing of your app until the main-thread gets free. You can do your long-running job in another thread, then switch to the main-thread to do whatever you want.
var compressedImage: File? = null
CoroutineScope().launch(Dispatchers.IO) {
compressedImage = Compressor.compress(this#UpdateProfileActivity, cachedFile.absoluteFile)
withContext(Dispatchers.Main) {
camera = "gallery"
// doing something with the compressedImage.
}
}
I have an acync method with callback:
myAsyncMethod(params) {
handleResult(it)
}
I need to convert it to sync method (block and return result) like this:
val result = mySyncMethod(params)
handleResult(result)
I can't re-implement it by another way because this method provided by third-party library.
I am trying to use ReentrantLock:
fun mySyncMethod(params:Type) {
Log.d("tag", "1")
val result = null
val mutex = ReentrantLock()
myAsyncMethod(params) {
Log.d("tag", "3")
result = it
mutex.unlock()
}
Log.d("tag", "2")
mutex.lock()
Log.d("tag", "4")
return result
}
handleResult(mySyncMethod(params))
I wait that I should see 1, 2, 3, 4. But I get 1, 2, 4, 3 and null in handleResult. I am trying the same with mutex but with the same result. How to make it works?
P.S. Sure I can use synchronized, but in this case I have to use Object-variable additionally.
Here is my code first. I used a thread instead of your method to test myself.
fun main() {
val mutex = ReentrantLock(true)
val asyncCondition = mutex.newCondition()
mutex.lock()
try
{
print(1)
thread {
mutex.lock()
try
{
print(2)
}
finally
{
asyncCondition.signalAll()
mutex.unlock()
}
}
asyncCondition.await()
print(3)
}
finally
{
mutex.unlock()
}
}
Java's ReentrnatLock.lock method will block a thread when it is already locked on the only same thread. Since you are trying to lock an async thread from another thread, your code is not working. To block or release another thread, you may use a Condition like my code.
The reason why I am using try..finallystatement everywhere is that if an exception occurred after locking a thread, you are going to meet the infinity loop, so you must be careful about this case.
You may see these references.
Concurrency (ReentrantLock) in different threads
How do java.util.concurrent.locks.Condition work?
I expect that I should see 1, 2, 3, 4.
Then you misunderstood what ReentrantLock is actually for.
If mySyncMethod can be called from different threads, then after mutex.lock() is called, only one thread at a time can execute the code following mutex.lock() - the other threads executing this method have to wait. Once mutex.unlock() is called, one of the waiting threads will execute the code too and so on.
So, the thread owning the mutex forces the other threads to wait but its own flow isn't blocked. myAsyncMethod starts running after the outer method has completed already and hence result is still null.
I need to convert it to sync method (block and return result) like this:
According to your requirements, you need to block the current thread until the async task is complete. To achieve this, you could use Semaphore or CountDownLatch. For example, with Semaphore, your method could look as follows:
fun mySyncMethod(params:Type) {
Log.d("tag", "1")
val result = null
val semaphore = Semaphore(0)
myAsyncMethod(params) {
Log.d("tag", "3")
result = it
semaphore.release()
}
Log.d("tag", "2")
semaphore.acquireUninterruptibly()
Log.d("tag", "4")
return result
}
while it is very convenient to use, from my understanding, AsyncTask has two important limitations:
doInBackground of any instances will share the same worker
thread, i.e. one long running AsyncTasks can block all others.
execute, onPostExecute and other "synchronizing" methods must/will always be executed on the UI-thread, i.e. not on the Thread, which wants to start the task.
I ran into trouble, when I tried to reuse some existing AsyncTasks in a background IntentService that are responsible for the client-server communication of my app. The tasks of the service would fight over time in the worker thread with those of the UI activities. Also they would force the service to fall back onto the UI-thread, although that service should perform its work quietly in the background.
How would I go about removing/circumventing these limitations? I basically want to achieve:
A framework that closely resembles AsyncTask (because I need to migrate a lot of critical code there).
Each instance of such a task should run its doInBackground on its own thread instead of a single worker thread for all instances.
Edit: Thx to VinceFR for pointing out this can be achieved by simply calling executeOnExecutor instead of execute.
The callbacks like onPostExecute should be called on the same thread that started the task by calling execute, which should not need to be the UI-thread.
I figure, I'm not the first person to require something like this. Therefore I wonder: Is there already some third-party library that can be recommended to accomplish this? If not, what would be a way to implement this?
Thanks in advance!
The solution looks like this:
All classes that spawn AsyncTasks that might interfere with each other get their own Executor like this one (make that elaborate as you like using thread pools etc.):
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
As pointed out by VinceFR you can run an AsyncTask on a given Executor by calling it like this (where payload are the parameters that you would regularly pass to a task):
task.executeOnExecutor(serviceExecutor, payload);
However, this breaks backwards-compatibility to Gingerbread and earlier. Also, if you want to support Honeycomb, you need to make sure, this call happens on the UI thread. Jelly Bean will take care of this automatically.
Now the trickier part: Keeping the service running on its own thread. As many things in Android this seems harder than it needs to be (or maybe I'm lacking some information here). You can't use an IntentService, because that will shut down automatically the first time an AsyncTask takes over and let's the onHandleIntent callback complete.
You need to setup your own thread and event loop on the service:
public class AsyncService extends Service {
private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
public Handler threadHandler = null;
public void run() {
Looper.prepare();
this.threadHandler = new Handler();
Looper.loop();
}
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;
#Override
// This happens on the UI thread
public void onCreate() {
super.onCreate();
}
#Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
this.serviceThread = new LooperThread();
this.serviceThread.start();
while(this.serviceThread.threadHandler == null) {
Log.d(TAG, "Waiting for service thread to start...");
}
this.serviceThreadHandler = this.serviceThread.threadHandler;
this.serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheFirstThingOnTheServiceThread();
}
});
return Service.START_STICKY;
}
// doTheFirstThingOnTheServiceThread
}
No you need to make sure that each time an AsyncTask returns to the UI thread, you end up in your service thread instead:
// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
// do some stuff
// here we can reuse a class that performs some work on an AsyncTask
ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
// the existing class performs some work on an AsyncTask and reports back via an observer interface
someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
#Override
// This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
public void onOperationComplete() {
serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheSecondThingOnTheServiceThread();
}
});
}
}
someUsefulObject.performOperation();
}
// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
// continue working on the serviceThread
}
So, this works for me. I'd be delighted to see a simpler solution for this. Note that the solution requires the service to know that is will be called back by the ExistingClassWithAsyncOperation on the UI thread. I don't particularly like this dependency, but don't know how to do better right now. However, I don't have to rewrite a lot of existing classes that perform asynchronous operations using AsyncTask.
I am building an Android application (using Scala 2.9) and am using a Thread that renders to a SurfaceView; this is for a game so it should update as often as it can. I imagine this issue is similar to other game "event loops" where the input comes from a different thread.
Here is a gross approximation of the current approach that relies on synchronization. It "works well enough", but I have general misgivings about having to use explicit synchronization and "tying up" the View/input thread.
View, "UI thread":
def View.onTouchEvent(e) { // on UI thread
Game.handleInput(e)
}
Game, "Game Thread":
def Game.handleInput(e) = S synchronized { // on UI thread
alterStateBasedOnInput
}
def Game.run () { // on Game thread
while (running) {
S synchronized {
doGameStuff
}
View.post(someStateRelayedViaRunnable)
yield
}
}
Instead of explicitly using synchronization, I'd like to have something like this:
def View.onTouchEvent(e) { // on UI thread
Game.sendMessage(e)
}
def Game.run () { // on Game thread
while (running) {
processMessage
doGameStuff
View.sendMessage(someState) // hopefully same as Game.sendMessage
yield
}
}
Now, this is relatively easy to implement manually using a ConcurrentLinkedQueue or similar, but I would really not like to reinvent the wheel here. In addition, it would be nice to use such an actor/queue to post-back to the UI as well - right now I am using Android's support for posting an (asynchronous) Runnable to the UI thread.
I've briefly looked at several different actor implementations (mainly standard Scala and the Scalaz) and some different Java "message passing" libraries such as Jetlang, but most seem to use implicit threads or a thread executor service. But, in my case I wish to [run the actor and] process messages at a specific time on a specific thread. For View.sendMessage the messages should also be processed on the UI thread, but timing is not as important and can piggyback off of the Runnable execution noted above.
Then, I guess my question is, given the above:
What would be a good - as in "efficient" and idiomatic - approach to feed data between these two threads?
(I am also willing to entertain the suggestion that I completely fail to understand Scala actors and/or Scalaz actors and/or other message passing libraries; Scalaz seems like it might be able to work as I envision, but is hard for me to follow.)
Well, while I would still like to know of a generic/reusable approach to the above, practicality calls. This can also be done by running a Looper on the game thread and then putting the game "event loop stuff" inside the IdleHandler, but I did not like that inversion ..
Here is how I have currently implemented it:
Game/Thread class:
var handler: Handler = _ // handler created on View thread
// Send Message to Looper that exists on View thread
// (Created implicitly for all UI threads.)
def publishEvent(event: OutputEvent) {
handler.obtainMessage(0, event).sendToTarget
}
protected val queue = new ConcurrentLinkedQueue[InputEvent]
def queueEvent(event: InputEvent) { // on UI thread
queue.add(event)
}
def processQueuedEvents() { // on game Thread
#tailrec
def processNextEvent {
val event = queue.poll
if (event ne null) {
doStuffWithInputEvent(event)
processNextEvent
}
}
processNextEvent
}
override def run() { // on game Thread
while (running) {
processQueuedEvents
doOtherGameStuff ~ call_publishEvent ~ etc
}
}
View class:
// Created on UI thread, passed to Game instance
// (The Looper will dispatch Messages to Handlers.)
val handler = new Handler {
override def handleMessage(m: Message) {
val event = m.obj
doStuffWithOutputEvent(event)
}
}
// on UI thread
override def onTouch(v: View, ev: MotionEvent): Boolean = {
// safely queued, will be processed at the start of each game loop
game.queueEvent(InputEvent(..))
}