6.7.3. AsyncTask

优质
小牛编辑
132浏览
2023-12-01

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");

}

}

  1. PostToTwitter是StatusActivity的内部类,也是AsyncTask的子类。留意其中对泛型的使用,通过三个类型参数,决定了后面函数的类型:第一个类型参数与doInBackground()相关,第二个与onPostExecute()相关,第三个与onPostExecute()相关。
  2. doInBackground()是个回调方法,表示异步执行的网络操作,就像执行在后台一样。它的参数String...来自前面声明中的第一个类型参数,后面的三个.表示它接纳多个字符串作为参数,即使只用到一个字符串也必须如此。
  3. onProgressUpdate()在任务进度更新时触发,其中的“进度”由doInBackground()负责更新。一个应用样例是,下载工具显示已完成的百分比。但在这里没有显示进度信息的必要,因此留空。
  4. onPostExecute()在任务完成时触发。我们可以在这个回调方法里面更新用户界面,显示任务完成。这里使用了Android的Toast机制,在屏幕上弹出一条消息。创建Toast的静态方法是makeText(),但在创建一条Toast消息之后,还需要调用show()才能显示出来,对这点需要小心。另外onPostExecute()方法参数的类型与前面的第三个类型参数相关。
  5. 设置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