Android多线程编程之AsyncTask

进程?线程?

  进程是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态的概念。每个进程都有自己的地址空间(进程空间)。进程空间的大小与处理机位数有关。进程至少有5种基本状态:初始态,执行态,等待状态,就绪状态,终止状态。

  在多用户环境下,一个服务器通常需要接受大量的不学定数量用户的并发请求,而为每一个请求都创建一个进程非常不明智,无论从系统资源开销方面还是响应用户请求的效率上来看。这也是多线程诞生的一个原因。线程是进程的一部分,一个没有线程的进程可以看做是单线程。线程也是CPU调度的一个基本单位

多线程的实现

1)Activity.runOnUiThread(Runnable)

2)View.post(Runnable) ;View.postDelay(Runnable , long)

3)Handler

4)AsyncTask

为何引入AsnyncTask?

在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但是一个进程却是可以有许多线程的。

  在这些线程中,有一个线程叫做UI线程,也叫做Main Thread,除了Main Thread之外的线程都可称为Worker Thread。Main Thread主要负责控制UI页面的显示、更新、交互等。因此所有在UI线程中的操作要求越短越好,只有这样用户才会觉得操作比较流畅。一个比较好的做法 是把一些比较耗时的操作,例如网络请求、数据库操作、复杂计算等逻辑都封装到单独的线程,这样就可以避免阻塞主线程。Android的程序运行时是多线程的,为了更方便的处理子线程和UI线程的交互,引入了AsyncTask。

  Android是单线程模型,这意味着Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,所以单纯的new一个Thread并且start()是不行的,因为这违背了Android的单线程模型。那么如何用好多线程呢?总结一下:  
事件处理的原则:所有可能耗时的操作都放到其他线程去处理

AsyncTask介绍

  Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。

  首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

  Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

  AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。

AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

使用AsyncTask 一个异步加载数据最少要重写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled() 用户调用取消时,要做的操作

 

一个异步任务的执行一般包括以下几个步骤:

  1.execute(Params... params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

  2.onPreExecute(),在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。

  3.doInBackground(Params... params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。

  4.onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。

  5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

在使用的时候,有几点需要格外注意

  1.异步任务的实例必须在UI线程中创建。

  2.execute(Params... params)方法必须在UI线程中调用。

  3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

  4.不能在doInBackground(Params... params)中更改UI组件的信息。

  5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

下面是一个模拟加载视频、数据、连接网络的进度条案例

activity_main.xml

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context="com.example.threadasynctask.MainActivity" >
10
11     <TextView
12         android:id="@+id/tv_start"
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:text="@string/hello_world" />
16
17     <Button
18         android:id="@+id/btn_start"
19         android:layout_width="wrap_content"
20         android:layout_height="wrap_content"
21         android:layout_alignParentRight="true"
22         android:text="@string/strat" />
23
24     <ProgressBar
25         android:id="@+id/progressBar1"
26         style="?android:attr/progressBarStyleHorizontal"
27         android:layout_width="match_parent"
28         android:layout_height="wrap_content"
29         android:layout_alignRight="@+id/btn_start"
30         android:layout_below="@+id/btn_start"
31         android:layout_marginTop="19dp" />
32
33 </RelativeLayout>
MyTask.java
 1 package com.example.threadasynctask;
 2
 3 import android.os.AsyncTask;
 4 import android.widget.ProgressBar;
 5 import android.widget.TextView;
 6
 7 /**
 8  * 生成该类的对象,并调用execute方法之后
 9  * 首先执行的是onProExecute方法
10  * 其次执行doInBackgroup方法
11  * @author Administrator
12  *
13  */
14 public class MyTask extends AsyncTask<Integer, Integer, String>{
15
16     private TextView textView;
17     private ProgressBar progressBar;
18     private String str;
19
20
21     public MyTask(TextView textView, ProgressBar progressBar) {
22          super();
23          this.textView = textView;
24         this.progressBar = progressBar;
25
26     }
27
28     /**
29      * 这里的Integer参数对应AsyncTask中的第一个参数
30      * 这里的String返回值对应AsyncTask的第三个参数
31      * 在执行过程中可以调用publicProgress(Progress…)来更新任务的进度
32      * 1.所有耗时的代码,写到这里来(数据库、蓝牙、网络服务)
33      * 2.绝对不能碰UI
34      */
35     @Override
36     protected String doInBackground(Integer... params) {
37         int i = 0 ;
38         for(i = 0 ; i <= 100 ; i++){
39             str = i+"%"; //模拟加载数据
40             try {
41                 Thread.sleep(100);
42             } catch (InterruptedException e) {
43                 e.printStackTrace();
44             }
45             publishProgress(i);
46         }
47         //返回前端
48         return i + params[0].intValue() + "";
49     }
50
51     //准备,该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
52      protected void onPreExecute() {
53           textView.setText("开始执行异步线程");
54          }
55
56
57     //做完后执行
58      /**
59       *  这里的String参数对应AsyncTask中的第三个参数
60       *  (也就是接收doInBackground的返回值)
61       * 在doInBackground方法执行结束之后在运行,
62       * 并且运行在UI线程当中 可以对UI空间进行设置
63       */
64     @Override
65     protected void onPostExecute(String result) {
66         textView.setText("异步操作执行结束" + result);
67     }
68
69
70     //分步完成
71     /**
72      * 这里的Intege参数对应AsyncTask中的第二个参数
73      * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
74      * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操
75      */
76         @Override
77         protected void onProgressUpdate(Integer... values) {
78             //0,1,2,3,4
79             int vlaue = values[0];
80              progressBar.setProgress(vlaue);
81              textView.setText("已完成"+str);
82         }
83
84
85 }

MainActivity.java

package com.example.threadasynctask;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

    private Button btn;
    private TextView tv;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv =(TextView)findViewById(R.id.tv_start);
        btn =(Button)findViewById(R.id.btn_start);
        progressBar = (ProgressBar)findViewById(R.id.progressBar1);

        btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                MyTask mt = new MyTask(tv,progressBar);
                mt.execute(1000);//里面的参数是传给doInBackground
            }

        });
    }
}

效果如下:

  

时间: 2024-08-07 04:33:10

Android多线程编程之AsyncTask的相关文章

Android多线程编程之Handler篇(消息机制)

Android多线程编程之Handler篇(消息机制) Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑. MessageQueue 消息队列,以队列的形式(实为单链表结构)对外提供插入和删除的工作, Looper 以无限循环的形式不断获取MessageQueue中的消息,有则处理,无则等待. ThreadLocal ThreadLocal可以在不同的线程互不干扰的存储并提供数据,通过ThreadLocal可以很

C#多线程编程之:异步方法调用

异步方法 当一个线程调用方法后,直到方法执行完毕,线程才继续执行,这种方法被称为同步方法.然而,有些方法执行时间可能非常长,比如串口操作或访问网络,这样线程被阻塞,而无法响应用户的其他请求.这种情况通常是无法忍受的,所以这时我们应该使用异步方法. 异步方法的原理是,在方法调用前为异步方法指定一个回调函数,方法调用后被线程池中的一个线程接管,执行该方法.主线程立即返回,继续执行其他工作或响应用户请求.如果异步方法执行完毕,回调函数被自动执行,以处理异步方法的调用结果. 如何实现异步方法呢?C#通过

iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术.以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的.它首次公布在Mac OS X 10.6 ,iOS 4及以上也可用. 设计: GCD的工作原理是:让程序平行排队的特定任务.依据可用的处理资源,安排他们在不论什么可用的处理器核心上运行任务. 一个任务能够是一个函数(function)或者是一个block. GCD的底层依旧是用线程实现,只是这样能够让程序

iOS多线程编程之NSOperation和NSOperationQueue的使用(转自容芳志专栏)

转自由http://blog.csdn.net/totogo2010/ 使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似.和Java的Runnable一样,NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main.相当与ja

iOS多线程编程之NSThread的使用

目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 新建singeView app 线程间通讯 线程同步 线程的顺序执行 其他同步 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用) 3.GCD 

Cocoa多线程编程之block与semaphore(信号量)

首先大家要了解 dispatch_queue 的运作机制及线程同步 我们可以将许多 blocks 用 dispatch_async 函数提交到 dispatch_queue ,如果类型是DISPATCH_QUEUE_SERIAL (串行),那么这些 block 是按照 FIFO (先入先出)的规则调度的,也就是说,先加入的先执行,后加入的一定后执行,但在如果类型是DISPATCH_QUEUE_CONCURRENT(并行),那么某一时刻就可能有多个 block 同时在执行. 这个时候,如果两个 b

【转载】iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

[转载]http://blog.csdn.net/totogo2010/article/details/8016129 iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用 分类: iOS开发进阶2012-09-25 16:22 35382人阅读 评论(32) 收藏 举报 目录(?)[+] 介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程

iOS 多线程编程之Grand Central Dispatch(GCD)

介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用. 设计: GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务. 一个任务可以是一个函数(function)或者是一个block. GCD的底层依然是用线程实现,不过这样可以让程序员不

iOS多线程编程之NSOperation和NSOperationQueue的使用

前一篇 <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似.和Java的Runnable一样,NSOperation也是设计用来扩展