Reputation: 107
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.
Upvotes: 2
Views: 2491
Reputation: 3420
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:
Upvotes: 1