6.7.3. AsyncTask
6.7.3.AsyncTask
既要避免长时间的阻塞,又要访问UI线程的私有数据,那该怎么办?使用Android内置的AsyncTask(异步任务)机制。要使用它,我们需要创建一个AsyncTask的子类,并覆盖doInBackground()与onPostExecute()两个方法。这两个方法里面分别对应后台执行的相关代码:任务进行时的操作,以及任务完成时的操作。
例6.5是使用AsyncTask修改过的代码,实现异步发布到服务端。它的开头部分与例6.3相似,不同在于它是使用了异步任务,不会阻塞在网络操作上。
例 6.5. StatusActivity.java, version 2
package com.marakana.yamba1;
import winterwell.jtwitter.Twitter;
import winterwell.jtwitter.TwitterException;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class StatusActivity2 extends Activity implements OnClickListener {
private static final String TAG = "StatusActivity";
EditText editText;
Button updateButton;
Twitter twitter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.status);
// Find views
editText = (EditText) findViewById(R.id.editText);
updateButton = (Button) findViewById(R.id.buttonUpdate);
updateButton.setOnClickListener(this);
twitter = new Twitter("student", "password");
twitter.setAPIRootUrl("http://yamba.marakana.com/api");
}
// Asynchronously posts to twitter
class PostToTwitter extends AsyncTask<String, Integer, String> { //
// Called to initiate the background activity
@Override
protected String doInBackground(String...statuses) { //
try {
Twitter.Status status = twitter.updateStatus(statuses[0]);
return status.text;
} catch (TwitterException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return "Failed to post";
}
}
// Called when there's a status to be updated
@Override
protected void onProgressUpdate(Integer...values) { //
super.onProgressUpdate(values);
// Not used in this case
}
// Called once the background activity has completed
@Override
protected void onPostExecute(String result) { //
Toast.makeText(StatusActivity2.this, result, Toast.LENGTH_LONG).show();
}
}
// Called when button is clicked
public void onClick(View v) {
String status = editText.getText().toString();
new PostToTwitter().execute(status); //
Log.d(TAG, "onClicked");
}
}
- PostToTwitter是StatusActivity的内部类,也是AsyncTask的子类。留意其中对泛型的使用,通过三个类型参数,决定了后面函数的类型:第一个类型参数与doInBackground()相关,第二个与onPostExecute()相关,第三个与onPostExecute()相关。
- doInBackground()是个回调方法,表示异步执行的网络操作,就像执行在后台一样。它的参数String...来自前面声明中的第一个类型参数,后面的三个.表示它接纳多个字符串作为参数,即使只用到一个字符串也必须如此。
- onProgressUpdate()在任务进度更新时触发,其中的“进度”由doInBackground()负责更新。一个应用样例是,下载工具显示已完成的百分比。但在这里没有显示进度信息的必要,因此留空。
- onPostExecute()在任务完成时触发。我们可以在这个回调方法里面更新用户界面,显示任务完成。这里使用了Android的Toast机制,在屏幕上弹出一条消息。创建Toast的静态方法是makeText(),但在创建一条Toast消息之后,还需要调用show()才能显示出来,对这点需要小心。另外onPostExecute()方法参数的类型与前面的第三个类型参数相关。
- 设置AsyncTask完毕,接下来使用它:简单创建一个实例,然后调用execute()即可。它的参数会原样传给doInBackground()。留意,这是个可变参数,因此单个字符串会被转化为字符串数组的形式。
到这里用户只要单击Upate Status按钮,Activity即可隐式地创建出一个独立的线程,在里面执行异步任务中的网络操作。到任务结束时,AsyncTask会弹出一个Toast显示任务的成功与否。这样可以避免应用程序长时间的阻塞,也可以避免用户见到讨厌的Application Not Responding: Force Close or Wait对话框,如图6.9 "Application Not Responding对话框"。到现在,我们程序的执行效果如图6.11 "StatusActivity, 1"。
图6.11. StatusActivity, 1