我们知道,Android不许在非UI线程中更新UI组件,所以Android提供了几种解决方案:
1. 使用Handler实现线程之间的通信。
2. Activity.runOnUiThread(Runnable)。
3. View.post(Runable)。
4.View.postDelayed(Runnable,long)。
后面的三种方式会导致编程略显繁琐,而异步任务(AsyncTask)可以简化这种操作。
AsyncTask<Params,Progress,Result>是个抽象类,它定义了三种泛型类型:
· Params :启动任务执行的输入参数的类型。
· Progress: 后台任务完成的进度值的类型。
· Result: 后台执行任务完成后返回结果类型。
实现AsyncTask只需要三步:
1. 创建AsyncTask子类,并指定泛型类型,如果某个泛型参数不需要指定,则使用Void。
2. 根据需要实现AsyncTask方法:
· doInBackground(Params...): 重写该方法就是后台线程将要完成的任务。 该方法可以调用publishProgress(Progress... values)方法更新任务的执行进度。
· onProgressUpdate(Progress... values): 在doInBackground()方法中调用publishProgress()方法更新任务执行进度后,将会触发该方法。
· onPreExecute(): 该方法将在后台执行耗时任务前被调用,通常该方法完成一些初始化的操作。比如在界面上显示等待进度框等。
· onPostExecute(Result result): 当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值传递给该方法。
3. 调用AsyncTask子类的实例的execute(Params... params)开始执行耗时任务。
使用AsyncTask的规则:
· 必须在UI线程中创建爱你AsyncTask的实例。
· 必须在UI线程中调用AsyncTask的execute方法。
· AsyncTask的回调方法有系统自动触发,程序员不应该主动去调用。
· 每个AsyncTask只能执行一次,多次调用将会引发异常。
示例:异步下载
public class AsyncTaskTest extends Activity { private TextView show; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); show = (TextView) findViewById(R.id.show); } // 重写该方法,为界面的按钮提供事件响应方法 public void download(View source) throws MalformedURLException { DownTask task = new DownTask(this); task.execute(new URL("http://www.crazyit.org/ethos.php")); } class DownTask extends AsyncTask<URL, Integer, String> { // 可变长的输入参数,与AsyncTask.exucute()对应 ProgressDialog pdialog; // 定义记录已经读取行的数量 int hasRead = 0; Context mContext; public DownTask(Context ctx) { mContext = ctx; } @Override protected String doInBackground(URL... params) { StringBuilder sb = new StringBuilder(); try { URLConnection conn = params[0].openConnection(); // 打开conn连接对应的输入流,并将它包装成BufferedReader BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); String line = null; while ((line = br.readLine()) != null) { sb.append(line + "\n"); hasRead++; publishProgress(hasRead); } return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(String result) { // 返回HTML页面的内容 show.setText(result); pdialog.dismiss(); } @Override protected void onPreExecute() { pdialog = new ProgressDialog(mContext); // 设置对话框的标题 pdialog.setTitle("任务正在执行中"); // 设置对话框 显示的内容 pdialog.setMessage("任务正在执行中,敬请等待..."); // 设置对话框不能用“取消”按钮关闭 pdialog.setCancelable(false); // 设置该进度条的最大进度值 pdialog.setMax(202); // 设置对话框的进度条风格 pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); // 设置对话框的进度条是否显示进度 pdialog.setIndeterminate(false); pdialog.show(); } @Override protected void onProgressUpdate(Integer... values) { // 更新进度 show.setText("已经读取了【" + values[0] + "】行!"); pdialog.setProgress(values[0]); } } }
上述实例中,我们在onPreExecute方法里初始化ProgressDialog弹出框; 在doInBackground()方法里进行耗时任务的操作(下载),接收的URL参数由UI线程传递过来task.execute(new URL("http://www.crazyit.org/ethos.php")); 耗时任务完成后,我们再onPostExecute方法里更新UI线程,并关闭了弹出框。
此时注意,onProgressUpdate()方法主要用于更新进度,要想触发该方法,我们需要在doInBackground()方法里调用publishProgress()方法。