Communication between main thread and worker threads in android - android

In my very first android project, I do some data manipulation, so I use multi-threading approach.
In MainActivity, I created multiple Runnable object and use ExecutorService to run all the threads. As my understanding, all threads are put in message queue and executed in turn. And the because the main thread is already in the queue, it will be executed before starting other threads. Is there any way that I can make the main thread wait for other threads to finish and then continue?
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//call MyFunction here
}
private List<Pair[]> myFunction(int dataInput) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(12);
MyTask MyTask = new MyTask();
for (int i = 0; i < gallerySize; ++i) {
final int index = i;
Runnable runnable = MyTask.runLongOperationWithThread(new MyTask.DataCallback(){
#Override
public void onSuccess(double[] scores) {
// get data back to main thread
}
#Override
public void onError(Exception ex) {
//TODO: log this error out to file
}
});
executorService.execute(runnable);
}
// try to get back all data from multi threading and do some operations
return returnList;
}
Do Looper and Handler help in this case?
And please correct me if I have any misunderstanding in android concept and threading.
Thanks.

In Android, stopping main thread is discouraged. The system will tell the user that the app is not responding. However, you can "notify" the main thread that the background thread has finished its work. Once the main thread knows this, it will do something. It is common in Android, it is what AsyncTask for.
However, AsyncTask is used for a simple one thread. In your case, one of the solution is to combine ExecutorService and AsyncTask. In doInBackground method of AsyncTask instance you make, use ExecutorService like usual, and wait it to finish by either shutdown(); awaitTermination() or invokeAll(). Read this question/answer for more information about how to wait ExecutorService to finish.
private class WrappingTask extends AsyncTask<Void, Void, Exception> {
protected Exception doInBackground(Void... args) {
ExecutorService taskExecutor = Executors.newFixedThreadPool(12);
for (. . .) {
taskExecutor.execute(new MyTask(. . .));
}
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
. . .
return e;
}
return null;
}
protected void onPostExecute(Exception error) {
// Notify the user that the task has finished or do anything else
// and handle error
}
}
In case of long running task
AsyncTask is a handy class to make threading and communicating (to main thread) easier. The problem for long running task is that the user can leave the Activity (and then come again), or there is an incoming call, etc. If you don't handle this Activity lifecycle with care, it is so "dangerous", AsyncTask does not handle this.
Long running task should be run in a Service. Note that Service is also run in the main thread, so the approach would be the same, unless you use IntentService. In case of IntentService, just execute all of the threads (formerly in doInBackground) in the onHandleIntent method and wait it there, this method is called on a worker thread.
Communicating Service with Activity and maintaining consistency of Activity's state through its lifecycle is a long story. You better read the documentation in "a full concentration" with a cup of coffee :D. This might helps:
Managing the Activity Lifecycle
Best Practices for Background Jobs

Related

Is this code executing in a different thread to the main UI thread

Ive been struggling with the concept of threads on android. I thought the following code was running on a different thread to the main UI thread but I am not 100% sure so I thought i would come here for clarification as the android docs arent written in any language i understand. below is my code.
public void retrieveImages(final ImagePresenterInt imagepresenter) {
storedImages = new ArrayList<Image>();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
File imagedir = new File("/mnt/shared/images");
File [] myfiles = File.listRoots();
String canread = String.valueOf(imagedir.canRead());
String isfile = String.valueOf(imagedir.isFile());
String isdir = String.valueOf(imagedir.isDirectory());
Log.d("Can Read?","Canread from file :" + canread);
Log.d("is file?","Is a file ? :" + isfile);
Log.d("is dir?","Is a Dir file :" + isdir);
File [] rootfiles =myfiles[0].listFiles();
for (File item : rootfiles)
{
Log.d(item.getAbsolutePath(),item.getName());
}
if(Looper.myLooper() == Looper.getMainLooper())
{
Log.d("main thread ?", "YES");
}
}
}, 2000);
}
my understanding of the above code is that I create a handler. which is associated with the main thread or UI thread. It has a message queue and a looper associated with it. this code is passed to the message queue and run by the looper on a seperate thread to the main UI thread? I could be well wrong here. but mainly I want to know if this is running on the main thread. And how would i get it onto a different thread if not? I tried to verify that the code is running on a different thread using code i found in this question
How to check if current thread is not main thread
this apparently tells me Iam still running in the main thread. thanks for your help
The Handler you create in retrieveImages() is bound to the thread which this function is called from.
The doc on Handler says:
Default constructor associates this handler with the Looper for the current thread. If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
So if retrieveImages() is called from the UI thread, the Handler created in it is also bound to the UI thread.
UPDATE: If you want your code to be executed in different thread, the easiest way is to use AsyncTask.
The Handler is created in the calling thread, which is probably the UI-Thread in your case. If you like to start a new Thread, there are three possibilities I know of: the first is to simple start a new thread:
thread = new Thread() {
#Override
public void run() {
//Do your thing here
}
};
thread.start();
The thread will die, if your Activity gets killed.
The second is to define an IntentService:
public class SimpleIntentService extends IntentService {
public SimpleIntentService() {
super("SimpleIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
//Do your thing here
}
and start it via
Intent intent = new Intent(this, SimpleIntentService.class);
intent.putExtra("SomeString", "SomeValueYouNeed");
startService(intent);
The IntentService will run on, until onHandleIntent() is done and than close itself.
The third possibility is an AsyncTask:
private class TestTask extends AsyncTask<Datatype1, Datatype2, Datatype3>{
protected Long doInBackground(Datatype1... params) {
// Do your thing here
}
protected void onProgressUpdate(Datatype2... progress) {
//Do a Progress-Bar or something like that
}
protected void onPostExecute(Datatype3 result) {
//Do something, when your work is done
}
}
And in your Activity:
new TestTask().execute(params);
The docs state you shouldn't use Async-Tasks for very long calulations, but I'm not shure why. It might be easier to get your data back to the UI-Thread if you use an Asynctask instead of the Intentservice, but I for myself don't use them very often, so I'm maybe not the best person to ask here.
Edit: I forgot this:
IntentService is executed once for every ntent you pass, the Asynctask will be callable just once.
Furthermore the IntentService has to be declared in the Manifest.

For how long the Thread will live in a previous Activity

I'm wondering if I can rely on a task which is executing in a separate non UI thread if I'm leaving an Activity. Looking on example below I can see the Runnable in a separate Thread is executing even if I'm on another Activity. But when would it be killed?
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
runTask();
startActivity(new Intent(this, SecondActivity.class));
}
private void runTask() {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
Log.i("Dev", "here I am");
SystemClock.sleep(1000);
}
}
}).start();
}
}
The java.lang.Thread is not tied to the Android UI component lifecycle, so just like in a normal JVM it will keep going until its run() method returns... unless Android terminates your entire application process before that happens, which it can do if you app is in the background and another app needs the RAM.
Incidentally, because the thread is not tied to the UI component lifecycle, you cannot simply call into another UI component from that thread. You'll have to post to a Handler or issue a broadcast or something if you want to get back to the UI, but you may already know that.
Finally, in your sample code, the Thread instance (through the anonymous Runnable) will keep the enclosing Activity class from being garbage collected, so you may want to re-think that construct.
If you want to do background work that's not tied to any single Activity, you're generally better off modelling it as an IntentService.
you can call Interrupt() that will post a interrupt request for your thread.
http://developer.android.com/reference/java/lang/Thread.html

How to implement a more flexible AsyncTask?

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.

Android ANRs from code running in a Handler?

A game I wrote some time ago has a problem with ANRs, and debugging suggests they're down to HTTP requests taking a long time (and thus causing the ANR).
I'd thought that by assigning the HTTP code into a Runnable called from within a Handler, I'd could avoid the ANR - but it seems this isn't the case?
The stack dumps suggest the runnable/handler code is still running within the 'Main' thread and thus still causes ANRs??
The task it's doing is asynchronous (uploading highscores and achievements) and so can be started and left to it's own devices entirely - what is the best way to implement this so that ANRs aren't going to become a problem?
One topic suggested that the Handler should be created in the Application class and not within the Game's Activity - but I can't find any detail on the differences between those cases??
All ideas greatly apprec.
p.s. extending this to ask - I assume an ANR relating to HTTP comes down to the phone being out-of-service/network/WiFi, because I've set a SHORT timeout for these requests (they're non-essential and can be retried later!?)
A Handler will execute code / handle messages per default (any constructor without Looper e.g. new Handler()) in the current thread. That is in almost every case the main thread. If you want it to execute in a different thread you have to tell it which Looper thread it should use.
Android has a utility class called HandlerThread that creates a Thread with a Looper.
Short example:
public class MyActivity extends Activity {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HandlerThread handlerThread = new HandlerThread("background-handler");
handlerThread.start();
Looper looper = handlerThread.getLooper();
mHandler = new Handler(looper);
mHandler.post(new Runnable() {
public void run() {
// code executed in handlerThread
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
// stops the HandlerThread
mHandler.getLooper().quit();
}
}
In case your task needs only a some information and does not need to report back, I'd go with an IntentService. Those don't go mad if your Activity-lifecycle recreates the Activity.
You would create a small Service in it's own file
public class SaveService extends IntentService {
public SaveService() {
super("SaveService");
}
#Override
protected void onHandleIntent(Intent intent) {
if ("com.example.action.SAVE".equals(intent.getAction())) {
String player = intent.getStringExtra("com.example.player");
int score = intent.getIntExtra("com.example.score", -1);
magicHttpSave(player, score); // assuming there is an implementation here
}
}
}
Add it to the AndroidManifest.xml
<application ....
<service android:name=".SaveService" />
</application>
And in your code start it with
Intent intent = new Intent(this /* context */, SaveService.class);
intent.setAction("com.example.action.SAVE");
intent.putExtra("com.example.player", "John123");
intent.putExtra("com.example.score", 5123);
startService(intent);
IntentService#onHandleIntent() runs on a background thread already so you don't have to bother about that.
Your Handler runs on the main thread. That is what causes ANR.
Even if you create it in the Application, by default (no parameters given to Handler) will be created on the main thread. You have to create a Looper, with its own Thread. See here.
A Handler initialized with your own Looper, that is a viable option to solve ANR...
A more simple alternative solution can be, if you place your async network operation into an AsyncTask. A simple approach is to place the AsyncTask into your Activity. A somewhat more complex could be to create a Service (holder for non-ui related functionality), that does the communication, and cleans itself from memory, once the communication is over...
I'd use AsyncTask and place it into the Activity / fire it up from the Activity...
Finally, HERE you can find a nice tutorial on threads in android.

Specifics on using Looper.prepare() in Android

I'm having a bit of trouble understanding how to use the Looper prepare()/loop()/quit() logic.
I have three threads: one is the UI thread, one is a game logic thread and the last is a network communication thread (a background thread, lives only while being used).
The game thread has many dependencies on the results of the network calls, so I wanted to spin the network thread off of the game thread and have a Handler post the result back.
Of course, since the UI thread is not involved I need to call Looper.prepare()... somewhere. I thought it should be called in the game thread, but I can't do that because loop() takes it over.
How do I go about posting back to the game thread from network thread with my handler?
What's going on is that once you call Looper.prepare() followed by Looper.loop() on a Thread, all that Thread will ever do is service its MessageQueue until someone calls quit() on its Looper.
The other thing to realize is that, by default, when a Handler is instantiated, it's code will always execute on the Thread it was created on
What you should do is create a new Thread and in run() call Looper.prepare(), setup any Handlers, and then call Looper.loop().
Bearing these things in mind here is the basic pattern I use a lot of places. Also, there's a good chance you should just be using AsyncTask instead.
public class NetworkThread extends Thread {
private Handler mHandler;
private Handler mCallback;
private int QUIT = 0;
private int DOWNLOAD_FILE = 1;
public NetworkThread(Handler onDownloaded) {
mCallback = onDownloaded;
}
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
// things that this thread should do
case QUIT:
Looper.myLooper().quit();
break;
case DOWNLOAD_FILE:
// download the file
mCallback.sendMessage(/*result is ready*/);
}
}
}
Looper.loop();
}
public void stopWorking() {
// construct message to send to mHandler that causes it to call
// Looper.myLooper().quit
}
public void downloadFile(String url) {
// construct a message to send to mHandler that will cause it to
// download the file
}
}
Could you tell some examples for what you are using your network thread? I think you can solve your problems without using Looper.
You can use ASyncTask to perform background task that may update some values in your UI thread. If user has to wait until background operation will be finished, you can show ProgressDialog and block application in OnPreExecute method, and then hide it in onPostExecute.
As I said, please describe more your needs and target which you want to achieve.

Categories

Resources