背景:

1、Android是单线程UI模型,所以假如不另外开辟线程做一些下载图片、获取网络内容的的操作,会使UI给用户一种“很卡”的感觉;

2、假如不引入多线程,很容易导致Application Not Responding 也就是ANR,应用程序无响应,在手机上面一般表现为弹出一个警告窗口,“强制关闭”、“Force Close”这种恶心的问题;

3、Android本身提供一个封装好的异步线程类叫AsyncTask,为我们管理线程起到很好的作用。

 

AsyncTask<Params, Progress, Result>

用法:

    必须继承AsyncTask并重写至少一个方法 doInBackground(Params...),经常使用的是也重写第二个方法 onPostExecute(Result)

参数:

  1. Params, 开始任务前传入参数,注意的是,可变长输入,可以一次性启动执行多个下载任务,例如传入一组String[];
  2. Progress,在后台任务计算时,向外发布进程的单位,一般是Int或者Double或者其他;
  3. Result,后台任务计算结束后,返回的结果

    注意以上三个参数皆可为空,只需要传入AsyncTask<Void,Void,Void>即可。

 

进程4部曲:(其实还有1个~)

  1. onPreExecute(),在UI线程调用,然后立刻被执行。这个过程一般用来做一些初始化操作,例如显示出一个ProgressBar提示用户任务已经在执行中、例如让启动任务的Button变为Disabled,防止多次执行;
  2. doInBackground(Params...),当onPreExecute()执行完毕,会立刻在后台线程调用。这个过程一般用来做一些比较耗时的操作,如计算PI(当然没人这么无聊吧~)、例如下载网络图片,结果将会传给最后一个过程onPostExecute(Result)。当然为了使你的程序更加友好,可以显示进度,而具体进度如何,就是通过在这个过程调用 publishProgress(Progress...) 来向外(指UI线程)发布进程。
  3. onProgressUpdate(Progress...),当 publishProgress(Progress...)被调用时,会在UI线程调用此方法。一般是用来提示用户进度,例如用在Notification上面显示下载进度条;
  4. onPostExecute(Result),当任务结束时在UI线程调用,传入参数为doInBackground()的结果~~
  5. onCancelled(),在AsyncTask的cancel()方法被调用时触发调用。

以下是一个自己写的Demo,有一个按钮,按钮启动异步任务下载CSDN logo并显示出来 

 

<注意:以下属性match_parent须在Android2.2之后才可以支持,效果同Android2.1及之前的fill_parent>

 

AsyncTaskDemoActivity.java

1 package com.csheng.asynctask;
 2 
 3 import java.io.InputStream;
 4 import .URL;
 5 import .URLConnection;
 6 
 7 import .Activity;
 8 import android.graphics.Bitmap;
 9 import android.graphics.BitmapFactory;
10 import android.os.AsyncTask;
11 import android.os.Bundle;
12 import android.view.View;
13 import android.view.View.OnClickListener;
14 import android.widget.Button;
15 import android.widget.ImageView;
16 
17 public class AsyncTaskDemoActivity extends Activity {
18 
19     public static final String TAG = "AsyncTaskDemoActivity";
20 
21     private Button downloadBtn = null;
22     private ImageView logoIv = null;
23     /* CSDN logo */
24     private final String LOGO_URL = "";
25 
26     @Override
27     public void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.main);
30         findViews();
31     }
32 
33     private void findViews() {
34         downloadBtn = (Button) findViewById(.downloadBtn);
35         logoIv = (ImageView) findViewById(.logoIv);
36         downloadBtn.setOnClickListener(new OnClickListener() {
37 
38             @Override
39             public void onClick(View v) {
40                 new DownloadAsyncTask().execute(LOGO_URL);// 启动匿名任务
41             }
42         });
43     }
44 
45     private class DownloadAsyncTask extends AsyncTask<String, Void, Bitmap> {
46 
47         @Override
48         protected Bitmap doInBackground(String... params) {
49             final String urlStr = params[0];// 取出execute所传入参数
50             URL url = null;
51             try {
52                 url = new URL(urlStr);
53                 final URLConnection connection = url.openConnection();
54                 final InputStream inputStream = connection.getInputStream();
55                 final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
56                 if (bitmap != null) {
57                     return bitmap;// 交给onPostExecute()处理
58                 }
59             } catch (Exception e) {
60                 e.printStackTrace();
61             }
62             return null;
63         }
64 
65         @Override
66         protected void onPostExecute(Bitmap result) {
67             if (result != null) {
68                 logoIv.setImageBitmap(result);// 取出doInBackground()的计算结果
69             }
70             downloadBtn.setEnabled(true);
71             super.onPostExecute(result);
72         }
73 
74         @Override
75         protected void onPreExecute() {
76 
77             downloadBtn.setEnabled(false);// 在整个异步下载期间,不允许重新启动下载任务
78             super.onPreExecute();
79         }
80 
81     }
82 }

 

main.xml

1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http:///apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5 
 6     <Button
 7         android:id="@+id/downloadBtn"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:layout_centerHorizontal="true"
11         android:text="@string/downloadText" />
12 
13     <!-- 图片放置于按钮下方 -->
14 
15     <ImageView
16         android:id="@+id/logoIv"
17         android:layout_width="wrap_content"
18         android:layout_height="wrap_content"
19         android:layout_below="@+id/downloadBtn"
20         android:layout_centerHorizontal="true"
21         android:contentDescription="@string/contentDescription" />
22 
23 </RelativeLayout>

 

strings.xml

1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3 
 4     <string name="app_name">AsyncTaskDemo</string>
 5     <string name="downloadText">下载图片</string>
 6     <string name="contentDescription">这是一张图片</string>
 7     <string name="startDownloadToast">开始下载图片</string>
 8     <string name="setImageToast">设置图片资源</string>
 9 
10 </resources>

 

AndroidManifest.xml

1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http:///apk/res/android"
 3     package="com.csheng.asynctask"
 4     android:versionCode="1"
 5     android:versionName="1.0" >
 6 
 7     <uses-sdk android:minSdkVersion="8" />
 8 
 9     <uses-permission android:name="android.permission.INTERNET" />
10 
11     <application
12         android:icon="@drawable/ic_launcher"
13         android:label="@string/app_name" >
14         <activity
15             android:name=".AsyncTaskDemoActivity"
16             android:label="@string/app_name" >
17             <intent-filter>
18                 <action android:name="android.intent.action.MAIN" />
19 
20                 <category android:name="android.intent.category.LAUNCHER" />
21             </intent-filter>
22         </activity>
23     </application>
24 
25 </manifest>