AsyncTask介绍
Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。
首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。
AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。
AsyncTask定义了三种泛型类型 Params,Progress和Result。
- Params 启动任务执行的输入参数,比如HTTP请求的URL。
- Progress 后台任务执行的百分比。
- Result 后台执行任务最终返回的结果,比如String。
使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
- doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以 调用publicProgress(Progress…)来更新任务的进度。
AsyncTask.excute(参数1)只能调用一个参数
但doInBackground可以传递多个参数,其中第一个和AsyncTask的参数1对应
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
有必要的话你还得重写以下这三个方法,但不是必须的:
- onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
- onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
- onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
-
该task只能被执行一次,否则多次调用时将会出现异常条必须遵守的准则:
下载图片并显示进度的代码:
private UserLoginTask mAuthTask = null
.....
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
new MyAsyTask().execute(path);
mAuthTask = new UserLoginTask();
mAuthTask.execute(stuid,pwd);
.............
/** * AsyncTask定义了三种泛型类型 Params,Progress和Result。 * Params启动任务执行的输入参数,比如HTTP请求的URL。传给doInBackground * Progress 后台任务执行的百分比。 onProgressUpdate的参数 * Result后台执行任务最终返回的结果,比如String。由doInBackground返回 */ public class MyAsyTask extends AsyncTask<String, Integer, Bitmap> { /* * 这两个参数在AsyncTask声明的泛型参数列表中指定, * 第一个为doInBackground接受的参数 * ,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。 */ @Override protected void onPreExecute() { // 该方法将在执行实际的后台操作前被UI thread调用,如在界面上显示一个进度条。 super.onPreExecute(); progressDialog.show(); } @Override protected Bitmap doInBackground(String... params) { // doInBackground返回的结果和onPostExecute的参数必须对应, // 完成对图片的下载功能,apache的协议 HttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(params[0]); HttpResponse httpResponse = null; InputStream inputStream = null; Bitmap bitmap = null; // 不能赋值null,记得初始化 ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); try { httpResponse = client.execute(httpGet); // 表示请求有响应 if (httpResponse.getStatusLine().getStatusCode() == 200) { // 这一步相当与建立通信管道,但是并没有将数据从网络取出来 // 在调用read()方法时才开始取数据 inputStream = httpResponse.getEntity().getContent(); // 获得文件总长度 long file_length = httpResponse.getEntity() .getContentLength(); // 实时下载的长度 long total_length = 0; byte[] data = new byte[1024]; int len = 0; // inputStream可以直接转吗生成bitmap,但这里通过outStream获得inputStream的数据再转汉城图片 // 估计:inputStream的每一次read都会减少一部分,循环结束时,inputStream没有内容了 // 所以每次while执行,将这一部分流转入outStream while ((len = inputStream.read(data)) != -1) { total_length += len;// //实时下载的长度 int value = (int) ((total_length / (float) file_length) * 100); Log.i("Value", "" + value); publishProgress(value); arrayOutputStream.write(data, 0, len); } byte[] result = arrayOutputStream.toByteArray(); Log.i("result", "" + result.length); bitmap = BitmapFactory.decodeByteArray(result, 0, result.length); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bitmap; } @Override protected void onProgressUpdate(Integer... values) { // 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况 super.onProgressUpdate(values); progressDialog.setProgress(values[0]); } @Override protected void onPostExecute(Bitmap bitmap) { // 在doInBackground 执行完成后,onPostExecute 方法将被UIthread调用 // 参数和doInBackground返回结果一致 // 相当于handler处理消息,改变UI的方式
mAuthTask = null;
super.onPostExecute(bitmap); progressDialog.dismiss(); imageView.setImageBitmap(bitmap); } }
Done!