2011年5月16日月曜日

AndroidStudyMemo=Working with AsyncTask

AsyncTask is an abstract helper class for managing background operations that eventually

post back to the UI thread. It creates a simpler interface for asynchronous operations than

manually creating a Java Thread class.

 

Instead of creating threads for background processing and using messages and message

handlers for updating the UI, you can create a subclass of AsyncTask and implement the

appropriate event methods.The onPreExecute() method runs on the UI thread before

background processing begins.The doInBackground() method handles background processing,

whereas publishProgress() informs the UI thread periodically about the background

processing progress.When the background processing finishes, the

onPostExecute() method runs on the UI thread to give a final update.

 

The following code demonstrates an example implementation of AsyncTask to perform

the same functionality as the code for the Thread:

private class ImageLoader extends

              AsyncTask<URL, String, String> {

                            @Override

                            protected String doInBackground(

                                                        URL... params) {

                                          // just one param

                                          try {

                                                        URL text = params[0];

                                                        // ... parsing code {

                                                        publishProgress(

                                                        "imgCount = " + curImageCount);

                                                        // ... end parsing code }

                                          }

                                          catch (Exception e ) {

                                                        Log.e("Net",

                                                        "Failed in parsing XML", e);

                                                        return "Finished with failure.";

 

                                          }

                                          return "Done...";

                            }

                           

                            protected void onCancelled() {

                                          Log.e("Net", "Async task Cancelled");

                            }

                           

                            protected void onPostExecute(String result) {

                                          mStatus.setText(result);

                            }

                           

                            protected void onPreExecute() {

                                          mStatus.setText("About to load URL");

                            }

                           

                            protected void onProgressUpdate(

                            String... values) {

                                          // just one value, please

                                          mStatus.setText(values[0]);

                            }

              }

 

When launched with the AsyncTask.execute() method, doInBackground() runs in a

background thread while the other methods run on the UI thread.There is no need to

manage a Handler or post a Runnable object to it.This simplifies coding and debugging.

 

Using Threads for Network Calls

The following code demonstrates how to launch a new thread that connects to a remote

server, retrieves and parses some XML, and posts a response back to the UI thread to

change a TextView:

 

              import java.net.URL;

              import org.xmlpull.v1.XmlPullParser;

              import org.xmlpull.v1.XmlPullParserFactory;

              // ...

              new Thread() {

                            public void run() {

                                          try {

                                                        URL text = new URL(

                                                                      "http://api.flickr.com/services/feeds/photos_public.gne?

                                                                      ?id=26648248@N04&lang=en-us&format=atom");

                                                        XmlPullParserFactory parserCreator =

                                                                      XmlPullParserFactory.newInstance();

                                                        XmlPullParser parser =

                                                                      parserCreator.newPullParser();

                                                        parser.setInput(text.openStream(), null);

                                         

                                                        mHandler.post(new Runnable() {

                                                                      public void run() {

                                                                      status.setText("Parsing...");

                                                                      }

                                                                      });

 

                                                        int parserEvent = parser.getEventType();

                                                        while (parserEvent !=

                                                                      XmlPullParser.END_DOCUMENT) {

                                                                      // Parsing code here ...

                                                                      parserEvent = parser.next();

                                                        }

 

                                                        mHandler.post(new Runnable() {

                                                                      public void run() {

                                                                                    status.setText("Done...");

                                                                                    }

                                                                      }

                                                        );

                                          } catch (Exception e) {

                                                        Log.e("Net", "Error in network call", e);

                                          }

                            }

              }.start();

 

For this example, an anonymous Thread object will do.We create it and call its start()

method immediately.However, now that the code runs on a separate thread, the user interface

updates must be posted back to the main thread.This is done by using a Handler

object on the main thread and creating Runnable objects that execute to call setText()

on the TextView widget named status.

 

The rest of the code remains the same as in the previous examples. Executing both the

parsing code and the networking code on a separate thread allows the user interface to

continue to behave in a responsive fashion while the network and parsing operations are

done behind the scenes, resulting in a smooth and friendly user experience.This also allows

for handling of interim actions by the user, such as canceling the transfer.You can

accomplish this by implementing the Thread to listen for certain events and check for

certain flags.

 

Displaying Images from a Network Resource

Now that we have covered how you can use a separate thread to parse XML, let's take our

example a bit deeper and talk about working with non-primitive data types.

Continuing with the previous example of parsing for image locations from a flickr

feed, let's display some images from the feed.The following example reads the image data

and displays it on the screen, demonstrating another way you can use network resources:

 

              import java.io.InputStream;

              import java.net.URL;

              import org.xmlpull.v1.XmlPullParser;

              import org.xmlpull.v1.XmlPullParserFactory;

              import android.os.Handler;

              // ...

              final String imageSrc =

                            parser.getAttributeValue(null, "href");

              final String currentTitle = new String(title);

              imageThread.queueEvent(new Runnable() {

                            public void run() {

                                          InputStream bmis;

                                          try {

                                                        bmis = new URL(imageSrc).openStream();

                                                        final Drawable image = new BitmapDrawable(

                                                        BitmapFactory.decodeStream(bmis));

 

                                                        mHandler.post(new Runnable() {

                                                                      public void run() {

                                                                                    imageSwitcher.setImageDrawable(image);

                                                                                    info.setText(currentTitle);

                                                                      }

                                                        });

                                          } catch (Exception e) {

                                          Log.e("Net", "Failed to grab image", e);

                                          }

                            }

              });

 

You can find this block of code within the parser thread, as previously described.After the

image source and title of the image have been determined, a new Runnable object is

queued for execution on a separate image handling thread.The thread is merely a queue

that receives the anonymous Runnable object created here and executes it at least 10 seconds

after the last one, resulting in a slideshow of the images from the feed.

 

Retrieving Android Network Status

The Android SDK provides utilities for gathering information about the current state of

the network.This is useful to determine if a network connection is even available before

trying to use a network resource.The ConnectivityManager class provides a number of

methods to do this.The following code determines if the mobile (cellular) network is

available and connected. In addition, it determines the same for the Wi-Fi network:

              import android.net.ConnectivityManager;

              import android.net.NetworkInfo;

              // ...

              ConnectivityManager cm = (ConnectivityManager)

                            getSystemService(Context.CONNECTIVITY_SERVICE);

              NetworkInfo ni =

                            cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

             

              boolean isWifiAvail = ni.isAvailable();

              boolean isWifiConn = ni.isConnected();

              ni = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

              boolean isMobileAvail = ni.isAvailable();

              boolean isMobileConn = ni.isConnected();

              status.setText("WiFi\nAvail = "+ isWifiAvail +

              "\nConn = " + isWifiConn +

              "\nMobile\nAvail = "+ isMobileAvail +

              "\nConn = " + isMobileConn);

 

First, an instance of the ConnectivityManager object is retrieved with a call to the

getSystemService() method, available as part of your application Context.Then this instance

retrieves NetworkInfo objects for both TYPE_WIFI and TYPE_MOBILE (for the cellular

network).These objects are queried for their availability but can also be queried at a

more detailed status level to learn exactly what state of connection (or disconnection) the

network is in. Figure 12.2 shows the typical output for the emulator in which the mobile

network is simulated but Wi-Fi isn't available.

 

If the network is available, this does not necessarily mean the server that the network

resource is on is available.However, a call to the ConnectivityManager method

requestRouteToHost() can answer this question.This way, the application can give the

user better feedback when there are network problems.

For your application to read the status of the network, it needs explicit permission.The

following statement is required to be in its AndroidManifest.xml file:

<uses-permission

android:name="android.permission.ACCESS_NETWORK_STATE"/>

 

References and More Information

Java.net package:

http://developer.android.com/reference/java/net/package-summary.html

Android.net package:

http://developer.android.com/reference/android/net/package-summary.html

XML Pull Parsing:

http://www.xmlpull.org/

Android XML Pull Parser:

http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html

 

0 件のコメント:

コメントを投稿