Tuesday, 18 September 2012

Multi-threading in Android

       This is very important concept for every application

                            (MULTI-THREADING)


Let’s say if you want to do a very long operation when the user pushes a button. If you not put or add any thread in your program, the coding will look like this:

Button btn = (Button)findViewById(R.id.button1);
btn. setOnClickListener(           
             new OnClickListener() 
            {
         
                @Override
                   public void onClick(View v) 
                  {
                     int myapp =longRunningOperation();
                     updateUI(myapp);
                  }
            });

In this program there is a possibility that this program may crash and this is really not a good logic for UI. For every application there is a default thread given by Android and this is known as MainThread or HandlerThread or UI thread.If you want to touch any thread directly,the program will crash.


Now we check it in another way. Now we create a thread and run this program under that thread.
Lets’ see what happens if we use a thread for long running operation:

Button btn = (Button)findViewById(R.id.button1);
btn. setOnClickListener(           
             new OnClickListener() 
            {
         
                @Override
                   public void onClick(View v) 
                  {
                     (new Thread(new Runnable() {
                     
                    @Override
                    public void run() 
                   {
                                 int myapp =longRunningOperation();
                                 updateUI(myapp);
                   }
                })).start();

                  }
            });

But when executing this program, again the program crashes. For details you can check in LogCat.

ERROR/AndroidRuntime(210): FATAL EXCEPTION: Thread-8
ERROR/AndroidRuntime(210): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
ERROR/AndroidRuntime(210): at ...

Here you are touching the UI directly that’s why it’s crashing.You can’t touch UI directly from other thread. If you want to touch UI, you need to take permission from other thread. This is achieved by inter thread communication. 


Solution for the above Problem:

Handler:
Now you need to know about the Handler Thread in Android.In the above program we are calling long running operation that means we are updating the operation for long time. The Handler class can solve this problem.The  Handler class can update the user interface. A Handler provides methods for receiving instances of the  Message  or  Runnable class. The Handler is the middleman between a new thread and the message queue.

Example:
1. Assume there is a queue for messages. Each messages to be handled.
2. Threads can add the messages.
3. Only a single thread pulls the messages one by one from the queue.



Now Run the new thread and use the handler to send messages for ui changes.

final Handler myHandler = new Handler(){
    @Override
public void handleMessage(Message msg) {
        updateUI((String)msg.obj);
}
     
};

(new Thread(new Runnable() {
     
    @Override
    public void run() {
        Message msg = myHandler.obtainMessage();
         
        msg.obj = longRunningOperation();
         
        myHandler.sendMessage(msg);
    }
})).start();

keep in mind that updating the UI should still be a short operation, since the UI freezes during the updating process.



Looper:
If we want to dive a bit deeper into the android mechanism we have to understand what is a Looper.
We have talked about the message queue that the main thread pulls messages and runnables from it and executes them.
We also said that each handler you create has a reference to this queue.
What we haven’t said yet is that the main thread has a reference to an object named Looper.
The Looper gives the Thread the access to the message queue.
Only the main thread has executes to the Looper by default.

(new Thread(new Runnable() {

                    @Override
                    public void run() {

                        Looper.prepare();
                        innerHandler = new Handler();
                                 
                        Message message = innerHandler.obtainMessage();
                        innerHandler.dispatchMessage(message);
                        Looper.loop();
                    }
                })).start();



ASYNC Task:

AsyncTask has 4 operations, which are executed by order.
1. onPreExecute() – is invoked before the execution.
2. onPostExecute() - is invoked after the execution.
3. doInBackground() - the main operation. Write your heavy operation here.
4. onProgressUpdate() – Indication to the user on progress. It is invoked every time publishProgress() is called.

AsyncTask defines 3 generic types:
AsyncTask<{type of the input}, {type of the update unit}, {type of the result}>
You don’t have to use all of them – simply use ‘Void’ for any of them.

Android developer website also mentions these 4 rules regarding the AsyncTask:
The task instance must be created on the UI thread.
execute(Params…) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)


class MyAsyncTask extends AsyncTask<Integer, String, Long> {
         
        @Override
        protected Long doInBackground(Integer... params) {
             
            long start = System.currentTimeMillis();
            for (Integer integer : params) {
                publishProgress("start processing "+integer);
                doLongOperation();
                publishProgress("done processing "+integer);
            }
             
            return start - System.currentTimeMillis();
        }

         
         
        @Override
        protected void onProgressUpdate(String... values) {
            updateUI(values[0]);
        }
         
        @Override
        protected void onPostExecute(Long time) {
            updateUI("Done with all the operations, it took:" +
                                     time + " millisecondes");
        }

        @Override
        protected void onPreExecute() {
            updateUI("Starting process");
        }
         
         
        public void doLongOperation() {
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
             
        }
         
    }

1 comment:

  1. good tutorial i was searching similar tutorial from past one week great work

    ReplyDelete