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的单线程模型。那么如何用好多线程呢?总结一下:
事件处理的原则:所有可能耗时的操作都放到其他线程去处理。
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
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.threadasynctask.MainActivity" > <TextView
android:id="@+id/tv_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /> <Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="@string/strat" /> <ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/btn_start"
android:layout_below="@+id/btn_start"
android:layout_marginTop="19dp" /> </RelativeLayout>
MyTask.java
package com.example.threadasynctask; import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView; /**
* 生成该类的对象,并调用execute方法之后
* 首先执行的是onProExecute方法
* 其次执行doInBackgroup方法
* @author Administrator
*
*/
public class MyTask extends AsyncTask<Integer, Integer, String>{ private TextView textView;
private ProgressBar progressBar;
private String str; public MyTask(TextView textView, ProgressBar progressBar) {
super();
this.textView = textView;
this.progressBar = progressBar; } /**
* 这里的Integer参数对应AsyncTask中的第一个参数
* 这里的String返回值对应AsyncTask的第三个参数
* 在执行过程中可以调用publicProgress(Progress…)来更新任务的进度
* 1.所有耗时的代码,写到这里来(数据库、蓝牙、网络服务)
* 2.绝对不能碰UI
*/
@Override
protected String doInBackground(Integer... params) {
int i = 0 ;
for(i = 0 ; i <= 100 ; i++){
str = i+"%"; //模拟加载数据
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
}
//返回前端
return i + params[0].intValue() + "";
} //准备,该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
protected void onPreExecute() {
textView.setText("开始执行异步线程");
} //做完后执行
/**
* 这里的String参数对应AsyncTask中的第三个参数
* (也就是接收doInBackground的返回值)
* 在doInBackground方法执行结束之后在运行,
* 并且运行在UI线程当中 可以对UI空间进行设置
*/
@Override
protected void onPostExecute(String result) {
textView.setText("异步操作执行结束" + result);
} //分步完成
/**
* 这里的Intege参数对应AsyncTask中的第二个参数
* 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
* onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操
*/
@Override
protected void onProgressUpdate(Integer... values) {
//0,1,2,3,4
int vlaue = values[0];
progressBar.setProgress(vlaue);
textView.setText("已完成"+str);
} }
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
} });
}
}
效果如下:
Android多线程编程之AsyncTask的更多相关文章
- Android网络编程之HttpClient运用
Android网络编程之HttpClient运用 在 Android开发中我们经常会用到网络连接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便我们 ...
- iOS多线程编程之NSThread的使用
目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...
- iOS多线程编程之NSThread的使用(转)
本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation ...
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- [转] iOS多线程编程之NSOperation和NSOperationQueue的使用
<iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...
- [转]iOS多线程编程之NSThread的使用
1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- 深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- iOS多线程编程之NSThread的使用(转载)
1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1.NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的 ...
随机推荐
- android 程序代码执行adb
Runtime.getRuntime().exec("adb pull /dev/graphics/fb0 C:/fb1"); Runtime. getRuntime().exec ...
- 在MFC中使用GDI+的一般方法,以VC6.0编译器为例
1.载解压GDI+开发包: 2.正确设置include & lib 目录: 设置如下:VC6.0编译器菜单Tools->Options->Directories中添加inlude ...
- android嵌套unity3d
最近因为跟小伙伴在制作一个App参加比赛,由于有unity的开发经验,突发奇想的想要在Android应用中内嵌unity提供模型展示的功能. 为此,我们查阅了不少资料.大多发现的是unity中内嵌An ...
- AngularJS 深入理解 $scope
$scope 的使用贯穿整个 AngularJS App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了$scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更 ...
- 比较常用的几个maven第三方镜像
OSC的:<mirror> <id>CN</id> <name>OSChina Central</name> ...
- POI 设置
FileOutputStream fos = new FileOutputStream("D:\\15.xls"); HSSFWorkbook wb = new HSSFWorkb ...
- 查看python api
以下方法可以查看python 的api,包括selenium webdriver,requests等 1.cmd进入dos命令行窗口,输入python -m pydoc -p 2345 (2345 ...
- asp.net mvc在windows server 2003上部署
1.要安装mvc3.mvc4.mvc5的插件 2.部署要创建应用程序池,并指定 3.权限指定everyone
- (分享)Paxos在大型系统中常见的应用场景
原帖http://timyang.net/distributed/paxos-scenarios/ 在分布式算法领域,有个非常重要的算法叫Paxos, 它的重要性有多高呢,Google的Chubby ...
- php工作笔记2-php编码效率
1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍.当然了,这个测试方法需要在十万级以上次执行,效果才明显.其实静态方法和非静态方法的效率 ...