180 likes | 326 Views
Concurrency in Android with Handlers and AsyncTasks, Adding Custom Libraries and Accessing the Internet. Concurrency and Java.
E N D
Concurrency in Android withHandlers and AsyncTasks,Adding Custom Librariesand Accessing the Internet
Concurrency and Java Concurrency is the ability to run several parts of a program or several programs in parallel, which means at the same time. Running multiple tasks at the same time means they are running asynchronously. If time consuming tasks can be performed asynchronously or in parallel, this improve the overall performance and the interactivity of your program. Java supports concurrency by allowing programs to create multiple threads. Threads are processes for executing code that can run in parallel to other threads, with each thread having its own memory cache or call stack.
Android Handlers and Threads An Android Handler allows you to send and process targeted Messages on the Android Activity’s main thread. The main thread is the one which starts when the main() method begins in the Standard Java Runtime Environment, or when the onCreate() method begins in an Android Activity. Threads are parallel processes which allow different code segments to independently interact with resources. Unless well written, threads can interfere with one another if they are interacting with the same resources, and this should be avoided unless you are well versed in thread management.
Android Handlers and Threads When you first start your Android Activity, the main thread, which is also called the UI thread, is automatically created. It is in charge of dispatching and managing all the event-driven activities in the main layout, and this includes the drawing events. For instance, if you touch a button on screen, the UI thread dispatches the touch event to the button’s handler, sets its pressed state and posts an invalidate request to the event queue. When a Handler is triggered, it runs on the UI thread and dequeues the request and notifies the component to redraw itself. Since the UI thread is very busy, you should avoid lengthy operations in the UI thread and create other background (or worker) threads whenever possible.
Android Handlers and Threads Scheduling Handler tasks is accomplished in two ways: • One approach uses the post(), postAtTime() and postDelayed() methods. • The other approach uses the sendMessage(), sendEmptyMessage(), sendMessageAtTime(), and sendMessageDelayed() methods. The post versions allow you to enqueue Runnable objects to the message queue that will execute on the UI thread when they are dequeued. The sendMessage versions allow you to enqueue a Message object containing a Bundle of data that will be processed by the Handler's handleMessage(Message) method on the UI thread. We will be using this second type in our new projects, although we did use the post() method with the timers we created for our Dove animation project.
Creating a HandlerFor SendMessage() Messages Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: // Do work associated with message 1 break; case 2: // Do work associated with message 2 break; default: // Do default work break; } super.handleMessage(msg); }
Creating a Message for a Handler You can create a Message to send to a Handler that contains data using the Bundle class in the following way for the 1st case statement in this example: Message message = new Message(); Bundle bundle = new Bundle(); bundle.putString("Message", someDataString); message.setData(bundle); message.what = 1; handler.sendMessage(message); “Message” is a key, and someDataString is a value paired with it. You can add many such key/value pairs this way. If you only have a single object to send you can use the Message.obtain() method to send your object as follows: handler.sendMessage(Message.obtain(handler, 2, someDataString)); If you have no Message object to send because you just need to trigger a certain case statement, you can use sendEmptyMessage as follow: handler.sendEmptyMessage(3);
Receiving a Message in a Handler The following shows how you would retrieve the data sent from the previous slide for case 1 (that used a Bundle), case 2 (that used Message.obtain) and case 3 (that used sendEmptyMessage): Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: String msgStr = msg.getData().getString("Message"); // Do some work associated with the string break; case 2: String msgStr = (String) msg.obj; // Do some work associated with the string break; case 3: // No object was sent, so do some work without it break; } super.handleMessage(msg); }
Putting a Message into the MessageQueue handler.sendMessage(Message); Sends a Message object to the handler’s handleMessage() method. handler.sendEmptyMessage(CaseNumber); Sends a null object to the handler triggering the given switch case number. handler.sendMessageDelayed(Message,4000); Sends a Message object to the handler after 4 seconds (4000 millis) have passed. This is a simple way to implement a timer because you can have the matching case statement issue another sendMessageDelayed() call with the same time delay, which loops whatever action occurs at that case statement according to the delay time. handler.sendMessageAtTime(Message,nextTimeMillis); Sends a Message object to the handler at nextTimeMillis, which is an absolute number of milliseconds since the start time. You can determine how many milliseconds have past since start time using SystemClock.uptimeMillis().
Android AsyncTasks The AsyncTask class allows you to run non-UI Threads that interact with the UI thread in a well defined way. This class allows to perform background operations and publish results on the UI thread without having to manipulate other threads and/or handlers. AsyncTasks are given high priority, so they should ideally be used for short operations (a few seconds at the most). If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
Android AsyncTasks The AsyncTask is designed to be a helper class, and there are four common methods you will often need to implement: • onPreExecute() • doInBackground(Params… values) • onProgressUpdate(Progress... values) • onPostExecute(Result result)
Android AsyncTasks 1. onPreExecute() – This calls on the UI thread before the thread starts running. This method is usually used to setup the task, for example by displaying a progress bar. 2. doInBackground(Params… values) – this is the method that runs on the background thread. In this method you should put all the code you want the application to perform in background. Referring to our Simple Chat Application, you would put here the code that manages the P2P session. The doInBackground() is called immediately after onPreExecute(). When it finishes, it sends the result to the onPostExecute().
Android AsyncTasks 3. onProgressUpdate(Progress... values) - called when you invoke publishProgress() in the doInBackground(). Runs on the UI thread. 4. onPostExecute(Result result) – called on the UI thread after the background thread finishes. It takes as parameter the result received from doInBackground().
Creating an AsyncTasks You create an AsyncTask object by first creating a class derived from the AsyncTask class. The derived class must use generics to identify the parameter data types to the doInBackground, onProgressUpdate, and onPostExecute methods respectively like so: private class SendP2P extends AsyncTask<String, Void, String> In the class you create, you add code for whatever AsyncTask methods you want to use. Then after you have added this class as a subclass in your Activity or View code, you do the following to run the AsyncTask at some other place in your code, and you pass it whatever values (or array of values) you wish to pass to it: new SendP2P().execute(outgoingLine);
Android AsyncTasks private class SendP2P extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { p2p.sendString(params[0]); String errMess = p2p.getErrorStatus(); if (errMess == null || errMess.equals("")) return getString(R.string.data_sent); return errMess; } @Override protected void onPostExecute(String result) { if (result.equals(getString(R.string.data_sent))) { statusBox.setText(statusStr); } else reportError(result); } }
Class Libraries • A class library is a collection of classes that we can use when developing programs • The Java standard class library is part of any Java development environment • Its classes are not part of the Java language per se, but we rely on them heavily • Various classes we've already used (System , Scanner, String) are part of the Java standard class library
Custom Android Libraries • In any Java IDE, custom libraries must be added to the CLASSPATH of the workspace. • In an Android project, in addition to being added to the CLASSPATH, custom libraries must also be stored in the “libs” folder.
Accessing the Internet You must give permission to your Android Application to allow it to Access the Internet by putting the following XML tag into your AndroidManifest.xml file: <uses-permission android:name="android.permission.INTERNET" />