分享

多线程异步处理:AsyncTask异步更新UI界面(详细完整总结篇)

 和帅书馆 2015-07-02

转载自:http://blog.csdn.net/mylzc/article/details/6772129 ,在原先的基础上整理项目并重新发布。

AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数。

AsyncTask抽象出后台线程运行的五个状态,分别是:1、准备运行,2、正在后台运行,3、进度更新,4、完成后台任务,5、取消任务,对于这五个阶段,AsyncTask提供了五个回调方法:

1、准备运行:onPreExecute(),该回调方法在任务被执行之后立即由UI线程调用。这个步骤通常用来建立任务,在UI上显示进度条。

2、正在后台运行:doInBackground(Params...),该回调方法由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算,计算的结果必须由该方法返回,并被传递到onPostExecute()中。在该方法内也可使用publishProgress(Progress...)来发布一个或多个进度单位(units of progress),这些值将会在onProgressUpdate(Progress...)中被发布到UI线程。

3. 进度更新:onProgressUpdate(Progress...),该方法由UI线程在publishProgress(Progress...)方法调用完后被调用,一般用于动态地显示一个进度条。

4. 完成后台任务:onPostExecute(Result),当后台计算结束后调用。后台计算的结果会被作为参数传递给该方法。

5、取消任务:onCancelled (),在调用AsyncTask的cancel()方法时调用

 

AsyncTask的构造函数有三个模板参数:

1.Params:传递给后台任务的参数类型。

2.Progress:后台计算执行过程中,进步单位(progress units)的类型(就是后台程序已经执行了百分之几了)。

3.Result:后台执行返回的结果的类型。

AsyncTask并不总是需要使用上面的全部3种类型。标识不使用的类型很简单,只须用Void类型即可。

 

项目分析:

1、获取网络图片

点击按钮,模拟一个耗时动作,从网站下载图片并显示,取消按钮模拟取消操作,将进度条的值置零,并且换背景图片。

 

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.xsjayz.at;
 
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
 
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
 
/**
 * AsyncTask
 *
 * @version 2012-09-02
 */
public class AsyncTaskActivity extends Activity {
 
    private final static String IMAGE_PATH = "http://www.oschina.net/img/logo.gif";
    private ImageView imageView;
    private Button button;
    private Button button2;
    private ProgressBar progressBar;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        imageView = (ImageView) findViewById(R.id.imageView);
        button = (Button) findViewById(R.id.button);
        button2 = (Button) findViewById(R.id.button2);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
 
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                MyTask myTask = new MyTask();
                myTask.execute(IMAGE_PATH);
            }
        });
 
        button2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                MyTask myTask = new MyTask();
                myTask.cancel(true);
            }
        });
    }
 
    /**
     * 继承AsyncTask
     */
    class MyTask extends AsyncTask<String, Integer, Bitmap> {
 
        /**
         * 准备运行
         */
        // 该回调方法在任务被执行之后立即由UI线程调用。这个步骤通常用来建立任务,在UI上显示进度条。
        @Override
        protected void onPreExecute() {
 
            imageView.setImageBitmap(null);// 每次在准备阶段先清除掉设置的图片
            progressBar.setProgress(0);// 进度条初始值0
        }
 
        /**
         * 正在后台运行
         */
        // 该回调方法由后台线程在onPreExecute()方法执行结束后立即调用。
        // 通常在这里执行耗时的后台计算,计算的结果必须由该函数返回,并被传递到onPostExecute()中。
        // 在该方法内也可使用publishProgress()来发布一个或多个进度单位,这些值将会在onProgressUpdate()中被发布到UI线程。
        @Override
        protected Bitmap doInBackground(String... params) {
 
            // 发布进度单位,系统将会调用onProgressUpdate()方法更新这些值。
            publishProgress(0);// 进度值0
 
            final Bitmap bitmap;
            HttpClient httpClient = new DefaultHttpClient();
 
            // 获取网站图片
            HttpGet httpGet = new HttpGet(params[0]);
 
            publishProgress(30);// 进度值30
 
            try {
                HttpResponse httpResponse = httpClient.execute(httpGet);
 
                publishProgress(70);// 进度值70
 
                bitmap = BitmapFactory.decodeStream(httpResponse.getEntity()
                        .getContent());
            } catch (Exception e) {
 
                return null;
            }
 
            publishProgress(100);// 进度值100
 
            return bitmap;
        }
 
        /**
         * 进度更新
         */
        // 该方法由UI线程在publishProgress()方法调用完后被调用,一般用于动态地显示一个进度条。
        protected void onProgressUpdate(Integer... progress) {
            // 更新进度条的进度
            progressBar.setProgress(progress[0]);
        }
 
        /**
         * 完成后台任务
         */
        // 后台任务执行完之后被调用,在UI线程执行。
        protected void onPostExecute(Bitmap result) {
 
            if (result != null) {
                Toast.makeText(AsyncTaskActivity.this, "获取图片成功",
                        Toast.LENGTH_LONG).show();
                imageView.setImageBitmap(result);
            } else {
                Toast.makeText(AsyncTaskActivity.this, "获取图片失败",
                        Toast.LENGTH_LONG).show();
            }
        }
 
        /**
         * 取消任务
         */
        // 在调用AsyncTask的cancel()方法时调用,在UI线程执行。
        @Override
        protected void onCancelled() {
            progressBar.setProgress(0);// 进度条复位
            imageView.setImageDrawable(getResources().getDrawable(
                    R.drawable.ic_launcher));
            Toast.makeText(AsyncTaskActivity.this, "取消从网络获取的图片",
                    Toast.LENGTH_LONG).show();
        }
    }
}

布局文件:main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas./apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </ProgressBar>
 
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:orientation="horizontal" >
 
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/download_btn" />
 
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/cancel_btn" />
    </LinearLayout>
 
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
</LinearLayout>

总结:

AsyncTask抽象出一个后台任务的五种状态,对应了五个回调接口,我们只需要根据不同的需求实现这五个接口(doInBackground是必须要实现的),就能完成一些简单的后台任务。

流程说明:

1、  点击按钮时,创建一个MyTask,并且传入图片地址(String类型参数,因此AsyncTask的第一个模板参数为String类型)。

2、  UI线程执行onPreExecute(),把ImageView的图片清空,progrssbar的进度清零。

3、  后台线程执行doInBackground(),不可以在doInBackground()操作UI,调用publishProgress(0)更新进度,此时会调用onProgressUpdate()更新进度条(进度用整形表示,因此AsyncTask的第二个模板参数是Integer)。方法最后返回result(例中返回Bitmap类型,因此AsyncTask的第二个模板参数是Bitmap)。

4、  当后台任务执行完成后,调用onPostExecute(Result),传入的参数是doInBackground()中返回的对象。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多