Tải bản đầy đủ (.pdf) (6 trang)

Lập trình Androi part 23 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (220.94 KB, 6 trang )

CHAPTER 15: Dealing with Threads
160
 Override one or more AsyncTask methods to accomplish the
background work, plus whatever work associated with the task that
needs to be done on the UI thread (e.g., update progress).
 When needed, create an instance of the AsyncTask subclass and call
execute() to have it begin doing its work.
What you do not need to do is:
 Create your own background thread.
 Terminate that background thread at an appropriate time.
 Call all sorts of methods to arrange for bits of processing to be done
on the UI thread.
AsyncTask, Generics, and Varargs
Creating a subclass of AsyncTask is not quite as easy as, say, implementing the
Runnable interface. AsyncTask uses generics, and so you need to specify three data
types:
 The type of information that is needed to process the task (e.g., URLs
to download)
 The type of information that is passed within the task to indicate
progress
 The type of information that is passed when the task is completed to
the post-task code
What makes this all the more confusing is that the first two data types are actually used
as varargs, meaning that an array of these types is used within your AsyncTask subclass.
This should become clearer as we work our way toward an example.
The Stages of AsyncTask
There are four methods you can override in AsyncTask to accomplish your ends.
The one you must override, for the task class to be useful, is doInBackground(). This will
be called by AsyncTask on a background thread. It can run as long as necessary in order
to accomplish whatever work needs to be done for this specific task. Note, though, that
tasks are meant to be finite; using AsyncTask for an infinite loop is not recommended.


The doInBackground() method will receive, as parameters, a varargs array of the first of
the three data types listed in the preceding section—the data needed to process the
task. So, if your task’s mission is to download a collection of URLs, doInBackground()
will receive those URLs to process. The doInBackground() method must return a value
of the third data type listed—the result of the background work.
CHAPTER 15: Dealing with Threads
161
You may wish to override onPreExecute(). This method is called, from the UI thread,
before the background thread executes doInBackground(). Here, you might initialize a
ProgressBar or otherwise indicate that background work is commencing.
Also, you may wish to override onPostExecute(). This method is called, from the UI
thread, after doInBackground() completes. It receives, as a parameter, the value
returned by doInBackground() (e.g., success or failure flag). Here, you might dismiss the
ProgressBar and make use of the work done in the background, such as updating the
contents of a list.
In addition, you may wish to override onProgressUpdate(). If doInBackground() calls the
task’s publishProgress() method, the object(s) passed to that method are provided to
onProgressUpdate(), but in the UI thread. That way, onProgressUpdate() can alert the
user as to the progress that has been made on the background work, such as updating
a ProgressBar or continuing an animation. The onProgressUpdate() method will receive
a varargs of the second data type from the list in the preceding section—the data
published by doInBackground() via publishProgress().
A Sample Task
As mentioned earlier, implementing an AsyncTask is not quite as easy as implementing a
Runnable. However, once you get past the generics and varargs, it is not too bad.
For example, the following is an implementation of a ListActivity that uses an
AsyncTask, from the Threads/Asyncer sample project:
package com.commonsware.android.async;

import android.app.ListActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemo extends ListActivity {
private static String[] items={"lorem", "ipsum", "dolor",
"sit", "amet", "consectetuer",
"adipiscing", "elit", "morbi",
"vel", "ligula", "vitae",
"arcu", "aliquet", "mollis",
"etiam", "vel", "erat",
"placerat", "ante",
"porttitor", "sodales",
"pellentesque", "augue",
"purus"};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
CHAPTER 15: Dealing with Threads
162
new ArrayList()));

new AddStringTask().execute();

}

class AddStringTask extends AsyncTask<Void, String, Void> {
@Override
protected Void doInBackground(Void unused) {
for (String item : items) {
publishProgress(item);
SystemClock.sleep(200);
}

return(null);
}

@Override
protected void onProgressUpdate(String item) {
((ArrayAdapter)getListAdapter()).add(item[0]);
}

@Override
protected void onPostExecute(Void unused) {
Toast
.makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
.show();
}
}
}
This is another variation on the lorem ipsum list of words, used frequently throughout
this book. This time, rather than simply hand the list of words to an ArrayAdapter, we
simulate needing to work to create these words in the background using AddStringTask,
our AsyncTask implementation.

If you build, install, and run this project, you will see the list being populated in real time
over a few seconds, followed by a Toast indicating completion, as shown in Figure 15–2.

Figure 15–2. The AsyncDemo, partway through loading the list of words
CHAPTER 15: Dealing with Threads
163
Let’s examine this project’s code piece by piece.
The AddStringTask Declaration
First, let’s look at the AddStringTask declaration:
class AddStringTask extends AsyncTask<Void, String, Void> {
Here, we use the generics to set up the specific types of data we are going to leverage
in AddStringTask, as follows:
 We do not need any configuration information in this case, so our first
type is Void.
 We want to pass each string generated by our background task to
onProgressUpdate(), to allow us to add it to our list, so our second
type is String.
 We do not have any results, strictly speaking (beyond the updates), so
our third type is Void.
The doInBackground() Method
Next up is the doInBackground() method:
@Override
protected Void doInBackground(Void unused) {
for (String item : items) {
publishProgress(item);
SystemClock.sleep(200);
}

return(null);
}

The doInBackground() method is invoked in a background thread. Hence, we can take
as long as we like. In a production application, we might be doing something like
iterating over a list of URLs and downloading each. Here, we iterate over our static list of
lorem ipsum words, call publishProgress() for each, and then sleep 1/4 second to
simulate real work being done.
Since we elected to have no configuration information, we should not need parameters
to doInBackground(). However, the contract with AsyncTask says we need to accept a
varargs of the first data type, which is why our method parameter is Void unused.
Since we elected to have no results, we should not need to return anything. Again,
though, the contract with AsyncTask says we must return an object of the third data type.
Since that data type is Void, our returned object is null.
The onProgressUpdate() Method
The onProgressUpdate() method looks like this:
CHAPTER 15: Dealing with Threads
164
@Override
protected void onProgressUpdate(String item) {
((ArrayAdapter)getListAdapter()).add(item[0]);
}
The onProgressUpdate() method is called on the UI thread, and we want to do something
to let the user know we are making progress on loading these strings. In this case, we
simply add the string to the ArrayAdapter, so it is appended to the end of the list.
The onProgressUpdate() method receives a String varargs because that is the
second data type in our class declaration. Since we are passing only one string per call
to publishProgress(), we need to examine just the first entry in the varargs array.
The onPostExecute() Method
Here’s the onPostExecute() method:
@Override
protected void onPostExecute(Void unused) {
Toast

.makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
.show();
}
The onPostExecute() method is called on the UI thread, and we want to do something to
indicate that the background work is complete. In a real system, there may be some
ProgressBar to dismiss or some animation to stop. Here, we simply raise a Toast.
Since we elected to have no results, we should not need any parameters. The contract
with AsyncTask says we must accept a parameter of the third data type. Since that data
type is Void, our method parameter is Void unused.
The Activity
Finally, let’s look at the activity:
new AddStringTask().execute();
To use AddStringsTask, we simply create an instance and call execute() on it. That
starts the chain of events eventually leading to the background thread doing its work.
If AddStringsTask required configuration parameters, we would not have used Void as
our first data type, and the constructor would accept zero or more parameters of the
defined type. Those values would eventually be passed to doInBackground().
And Now, the Caveats
Background threads, while eminently possible using the Android Handler system, are
not all happiness and warm puppies. Background threads not only add complexity, but
they also have real-world costs in terms of available memory, CPU, and battery life.
CHAPTER 15: Dealing with Threads
165
Hence, there are a wide range of scenarios you need to account for with your
background thread, including the following:
 The possibility that users will interact with your activity’s UI while the
background thread is chugging along. If the work that the background
thread is doing is altered or invalidated by the user input, you will need
to communicate this to the background thread. Android includes many
classes in the java.util.concurrent package that will help you

communicate safely with your background thread.
 The possibility that the activity will be killed off while background work
is occurring. For example, after starting your activity, the user might
have a call come in, followed by a text message, followed by a need to
look up a contact—all of which might be sufficient to kick your activity
out of memory. Chapter 16 will cover the various events Android will
take your activity through. Hook to the proper ones, and be sure to
shut down your background thread cleanly when you have the chance.
 The possibility that your user will get irritated if you chew up a lot of
CPU time and battery life without giving any payback. Tactically, this
means using ProgressBar or other means of letting the user know that
something is happening. Strategically, this means you still need to be
efficient at what you do—background threads are no panacea for
sluggish or pointless code.
 The possibility that you will encounter an error during background
processing. For example, if you are gathering information from the
Internet, the device might lose connectivity. Alerting the user of the
problem via a notification (discussed in Chapter 31) and shutting down
the background thread may be your best option.

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×