ZOFTINO.COM android and web dev tutorials

Android Threads Tutorial

Android starts a thread when a component in an app is requested to start. The thread created one per app is called the main thread. System creates a new thread when the requested component is the first one to start in the app. Subsequent requests to start any component within the same application will be run in the same thread.

If there are multiple tasks which the main thread can’t handle due to the number of request to it or due to long running tasks, you’ll have to create threads and run those tasks in it instead of on the main thread to improve your application responsiveness and prevent application not responding dialog.

Table of Contents

Running Code on Background Thread

You can add a piece of code, which you want to run on a worker thread, to a class which implements Runnable interface and its method run() and then start the worker thread by creating an instance of Thread, passing Runnable instance which has the code to be executed to its constructor and calling start on it.

The example shows how to download file on background thread. For downloading file it uses okhttp.

 public class ThreadsActivity extends AppCompatActivity {
    private static final String TAG = "ThreadsActivity";
    private String FILE_URL="http://www.zoftino.com/api/coupons";

    ….
    public void threadExample(View v){
        Thread r =  new Thread(new DownloadRunnable(FILE_URL));
        r.start();
    }

    public class DownloadRunnable implements Runnable {
        private String downloadUrl;

        public DownloadRunnable(String url){
            downloadUrl = url;
        }
        @Override
        public void run() {
            downloadFile();
        }
        public void downloadFile(){
            try{

                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder().url(downloadUrl)
                        .addHeader("Content-Type", "application/text")
                        .build();
                Response response = client.newCall(request).execute();
                InputStream in = response.body().byteStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String result, line = reader.readLine();
                result = line;
                while((line = reader.readLine()) != null) {
                    result += line;
                }
                Log.d("Thread : ", result);
                response.body().close();
            }catch (Exception e){ Log.d("exception : ", e);}
        }
    }
} 

But the problem with running code on the worker thread is that you shouldn’t modify UI components from it because UI components are not thread safe. Updates to UI components should be done on the main thread. Android provides ways which can be used to update UI components from the worker threads.

Updating UI Components from Background Thread

Android provides Activity.runOnUiThread, View.post and View.postDelayed methods for updating UI components from background thread. In the code which runs on the background thread, whenever UI needs to be updated from background thread, you need to call runOnUiThread() method of activity by passing a new runnable which will be executed on the main thread.

 public class ThreadsActivity extends AppCompatActivity {

    . . . .

    private TextView messageTextView;

    . . . .

    public class DownloadRunnable implements Runnable {
        private String downloadUrl;

        public DownloadRunnable(String url){
            downloadUrl = url;
        }
        @Override
        public void run() {
            String msg;
           if(downloadFile()){
               msg = "downloading the file successful";
           }else{
               msg = "failed to download the file";
           }
            updateUI(msg);
        }

        public void updateUI(final String msg){
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    messageTextView.setText(msg);
                }
            });
        }

     . . . .

    }
} 

Similarly, you can use post() or postDelaye() methods of View class to update UI from background thread. To do that, create runnable with the code that updates UI components and pass it to post() or postDelaye() methods and call this code on background thread when it needs to update UI components.

 public void updateUIView(final String msg){
    messageTextView.post(new Runnable() {
        @Override
        public void run() {
            messageTextView.setText(msg);
        }
    });
} 

AsyncTask

Methods Activity.runOnUiThread, View.post and View.postDelayed can be used for simple tasks only because as the complexity of the code that needs to be run on main thread grows, it will be difficult to manage the code.

In complex scenarios, you can use AsyncTask to update UI components from worker thread. Please see AsyncTask example to learn how to use it.

Using AsyncTask can possibly lead to memory leaks if AsyncTask is defined as non static inner class and it holds a strong reference to activity context. That is because a non static inner class holds implicit reference to its enclosing class, due to that the activity can’t be garbage collected even after it finishes while AsyncTask is still running in the background.

To solve this problem, you need to define async task as static inner class and define weak reference to context.

 private static class DownloadAsyncTask extends AsyncTask<Void, Void, String> {

    private final WeakReference<ThreadsActivity> threadsActivity;

    public DownloadAsyncTask(ThreadsActivity activity){
        threadsActivity = new WeakReference<>(activity);
    }

    @Override
    protected String doInBackground(final Void ... params) {
        String msg;
        if(downloadFile()){
            msg = "downloading the file successful";
        }else{
            msg = "failed to download the file";
        }
        return msg;
    }

    @Override
    protected void onPostExecute( final String downloadMsg ) {
        if (threadsActivity.get() != null){
            threadsActivity.get().messageTextView.setText(downloadMsg);
        }
    }
    public boolean downloadFile(){
        //download file .....
        return true;
    }
} 

Updating UI Using Handler and Looper

Another way to update Views with results from background thread is by using Handler. Handler needs to know the thread on which it needs to run. You can make Handler connect to a new Thread or an existing thread. To connect handler to an existing thread, you need to pass Looper object to it so that it will run on the same thread that Looper object runs on. To get main thread looper object, you need to call getMainLooper method on Looper class.

You need to implement Handler’s handleMessage method which is called by the system when it receives a message. System passes the message object received from the background thread to handleMessage method.

Message can be sent to handler from background thread using the handler object, back ground thread needs to have reference to the handler object in order for it to create a message and send it to system. To create a message object, you need to call obtainMessage() method on the handler passing results from background thread as data object that you want to send it to handler so that it can update UI on main thread. Finally, call sendToTarget() method on message object to send the message.

 public void downloadFileHandlerUpdate(){
    //create Handler connected to main thread
    messageHandler();

    //run background task
    Thread t = new Thread(new DownloadHandlerRunnable(FILE_URL, handler));
    t.start();
}
//creates handler using main Looper
public void messageHandler(){
    if(handler == null){
        handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message inputMessage) {
                String msg =(String)inputMessage.obj;
                messageTextView.setText(msg);
            }
        };
    }
}
public class DownloadHandlerRunnable implements Runnable {

    private String downloadUrl;
    //handler used to send message to main thread
    private Handler mainHandler;

    public DownloadHandlerRunnable(String url, Handler handler){
        downloadUrl = url;
        mainHandler = handler;
    }

    @Override
    public void run() {
        //download file
        String msg;
        if(true){
            msg = "downloading the file successful";
        }else{
            msg = "failed to download the file";
        }

        //send data to handler
        Message mainMessage =
                mainHandler.obtainMessage(1, msg);
        mainMessage.sendToTarget();
    }
}

Running Background Tasks Using RxJava

Using RxJava, you can implement clean code to run tasks in background and update UI views on the main thread with results from the background process. Please see RxJava use cases and RxJava example for more information.

IntentService

So far we have seen creating a background thread, running a task on it and updating UI components on the main thread. This way of creating a background thread to run a task on it is useful to run a task on background thread once.

But if you want to run a task repeatedly with different set of data and one task at time meaning sequentially on background thread, then you can use IntentService. Please see IntentService tutorial for more information and example.

Thread Pool

To run multiple tasks at the same time, you can create thread pools using concurrency framework. You can use Executors and ThreadPoolExecutor classes to create thread pools.

The Executors class provides utility and factory methods for creating Executor, ExecutorService, and ScheduledExecutorService.

ThreadPoolExecutor executes tasks from the queue it holds when there is a free thread available in the thread pool. Task producer adds task to the task queue. ThreadPoolExecutor give more control over thread pool configuration.

You can create ExecutorService instance using Executors class and by calling newFixedThreadPool() method on it passing the number of threads that you want in the thread pool. Whenever you need to run a task on background thread, you just pass the task in the form of Runnable to ExecutorService object by calling execute() method on it.

ExecutorService executorService = Executors.newFixedThreadPool(6);

//use ExecutorService instance to run the task background
executorService.execute(new Runnable() {
    @Override
    public void run() {
        //download file or do something
        String message = "file downloaded";

        //send results to UI
        Message mainMessage =
                handler.obtainMessage(1, message);
        mainMessage.sendToTarget();
    }
});