因为在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则:

1. 不要阻塞UI线程 
2. 确保只在UI线程中访问Android UI工具包

(当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。)

android提供了几种在其他线程中访问UI线程的方法。 
Activity.runOnUiThread( Runnable ) 
View.post( Runnable ) 
View.postDelayed( Runnable, long ) 
Hanlder

(在之前的《线程与消息处理》中我们学习了线程和Handler消息处理机制,如果有计算量比较大的任务,可以创建一个新线程执行计算工作,但是子线程无法更新UI界面,所以通过Handler消息处理机制与UI线程通信,更新UI界面。)

但是有一个问题需要注意,创建的子线程太多时,会影响系统性能。而且,Hanlder这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。针对这个问题,Android为我们提供了代替使用Thread和Handler的方案,这就是AsyncTask。它使创建需要与用户界面交互的长时间运行的任务变得更简单。

下面我们来直接认识AsyncTask :

先来看看AsyncTask的定义:

public abstract class AsyncTask<Params, Progress, Result> 三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。

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

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组件上。

使用AsyncTask类,遵守的准则:

  1. Task的实例必须在UI thread中创建;
  2. Execute()方法必须在UI thread中调用;
  3. 不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;
  4. 该task只能被执行一次,否则多次调用时将会出现异常;
  5. 不能在doInBackground(Params... params)中更改UI组件的信息。

通过看源码,发现AsyncTask实际上就是一个线程池,而网上的说法是AsyncTask比handler要轻量级,显然上不准确的,只能这样说,AsyncTask在代码上比handler要轻量级别,而实际上要比handler更耗资源,因为AsyncTask底层是一个线程池!而Handler仅仅就是发送了一个消息队列,连线程都没有开。
但是,如果异步任务的数据特别庞大,AsyncTask这种线程池结构的优势就体现出来了。

下面我们用一个简单的例子来体验一下:

布局文件:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="200dp"
android:id="@+id/textView"
android:textSize="20dp"
android:gravity="center" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_gravity="center"
android:textSize="20dp"
android:text="启动AsyncTask" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="9"
style="@android:style/Widget.ProgressBar.Horizontal"/> </LinearLayout>

在MainActivity中实现代码:

 public class MainActivity extends Activity {
private static final String TAG = "topcsa";
TextView textView;
Button button;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView)findViewById(R.id.textView);
button = (Button)findViewById(R.id.button);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
button.setOnClickListener(new View.OnClickListener(){ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
MyAsyncTask asyncTask = new MyAsyncTask();
asyncTask.execute(1000);
}
}); } class MyAsyncTask extends AsyncTask<Integer, Integer, String>
{
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
Log.d(TAG, "onPreExecute");
} @Override
protected String doInBackground(Integer... params) {
// TODO Auto-generated method stub
Log.d(TAG, "doInBackground");
for(int i = 0; i < 10; i++)
{
publishProgress(i);
try {
Thread.sleep(params[0]);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(TAG, "Background work over");
return "Background work over.";
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
Log.d(TAG, "onProgressUpdate");
progressBar.setProgress(values[0]);
textView.setText(Integer.toString(values[0]));
} @Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.d(TAG, "onPostExecute, result = " + result);
} }

运行程序时,做好与日志输出信息对照查看,有助于更好地理解AsyncTask的运作。

下面我们结合java.io.File类完成一个手机文件浏览器:

默认布局文件:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>

子布局文件file_list.xml:

 <?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableRow>
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>

默认的.java文件:

 public class MyAsyncTaskListFileDemo extends Activity {
private List<Map<String,Object>> allFileItems = new ArrayList<Map<String,Object>>() ;
private SimpleAdapter simple = null ;
private ListView list = null ;
private ListFileThread ft = null ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.main);
this.list = (ListView) super.findViewById(R.id.list) ;
File filePath = new File(java.io.File.separator); // 从根目录下开始列出
this.list.setOnItemClickListener(new OnItemClickListenerImpl()) ;
this.ft = new ListFileThread() ;
this.ft.execute(filePath) ;
} private class OnItemClickListenerImpl implements OnItemClickListener{ @Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
File currFile = (File) MyAsyncTaskListFileDemo.this.allFileItems
.get(position).get("name");
if (currFile.isDirectory()) { // 当前是一个目录
MyAsyncTaskListFileDemo.this.allFileItems = new ArrayList<Map<String,Object>>() ;
MyAsyncTaskListFileDemo.this.ft = new ListFileThread() ;
MyAsyncTaskListFileDemo.this.ft.execute(currFile) ;
}
} } private class ListFileThread extends AsyncTask<File, File, String> { @Override
protected void onProgressUpdate(File... values) {
Map<String,Object> fileItem = new HashMap<String,Object>() ; // 表示可以返回
if (values[0].isDirectory()) {
fileItem.put("img", R.drawable.folder_close); // 文件夹
} else { // 是文件
fileItem.put("img",R.drawable.file) ;
}
fileItem.put("name", values[0]) ;
MyAsyncTaskListFileDemo.this.allFileItems.add(fileItem) ;
MyAsyncTaskListFileDemo.this.simple = new SimpleAdapter(
MyAsyncTaskListFileDemo.this,
MyAsyncTaskListFileDemo.this.allFileItems,
R.layout.file_list, new String[] { "img", "name" },
new int[] { R.id.img, R.id.name });
MyAsyncTaskListFileDemo.this.list
.setAdapter(MyAsyncTaskListFileDemo.this.simple);
} @Override
protected String doInBackground(File... params) {
if (!params[0].getPath().equals(java.io.File.separator)) { // 不是根目录
Map<String,Object> fileItem = new HashMap<String,Object>() ; // 表示可以返回
fileItem.put("img",R.drawable.folder_open) ; // 可以返回
fileItem.put("name", params[0].getParentFile()) ;
MyAsyncTaskListFileDemo.this.allFileItems.add(fileItem) ;
}
if (params[0].isDirectory()) { // 是文件夹
File tempFile [] = params[0].listFiles() ;
if(tempFile != null) {
for (int x = 0; x < tempFile.length; x++) {
this.publishProgress(tempFile[x]) ;
}
}
}
return "文件已列出";
}
}
}

运行程序即可。

当然,AsyncTask也不是完全的完美。下面加个有关AsyncTask不足的文章:

http://www.oschina.net/question/54100_27825

Android AsyncTask 初探的更多相关文章

  1. android AsyncTask介绍(转)

    android AsyncTask介绍 AsyncTask和Handler对比 1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接 ...

  2. 《Android 性能测试初探》

    移动测试站点推荐: https://testerhome.com/ 专项相关帖子推荐: <Android 性能测试初探>合集 移动无线应用专项测试浅谈 公开课: [腾讯课堂]Testerh ...

  3. Android Activity初探

    原地址:Android Activity初探 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供一个 ...

  4. 十九、Android Activity初探

    原文:十九.Android Activity初探 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供 ...

  5. Android AsyncTask异步加载WebAPI

    之前做的程序一直存在很多问题,因为需要加载的Activity需要从网络加载数据.并没有完全正确的使用异步的方法去加载! 之前用的虽然是AsyncTask,但是在加载完成的时候还是并没有使用AsyncT ...

  6. Android -- AsyncTask 使用和缺陷

    一.AsyncTask的基本用法 由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它.在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下: ...

  7. Android 性能测试初探(六)

    书接前文 Android 性能测试初探之功耗(五) 本节聊聊性能测试的最后一项- 流量,当然我所指的性能测试是针对大部分应用而言的,可能还有部分应用会关注网速.弱网之类的测试,但本系列文章都不去一一探 ...

  8. Android 性能测试初探(五)

    书接上文 Android 性能测试初探之 GPU(四) 前文说了的一些性能测试项大家可能都听说,接下来我们聊聊大家不常关注的测试项- 功耗 . 功耗测试主要从以下几个方面入手进行测试 测试手机安装目标 ...

  9. Android 性能测试初探(四)

    书接上文 Android 性能测试初探(三) 自从 cpu及内存后,GPU 这个词对于 PC 性能测试者也不陌生了,什么 3Dmax,安兔兔之类的第三方软件让 GPU 在移动端性能测试领域都知晓,但对 ...

随机推荐

  1. [Tommas] Web测试中,各类web控件测试点总结

    一 .界面检查 进入一个页面测试,首先是检查title,页面排版,字段等,而不是马上进入文本框校验 1.页面名称title是否正确 2.当前位置是否可见  您的位置:xxx>xxxx 3.文字格 ...

  2. [Irving]DateTime格式处理大全

    DateTime dt = DateTime.Now;//    Label1.Text = dt.ToString();//2005-11-5 13:21:25//    Label2.Text = ...

  3. linux下的oracle11gR2静默安装,经验分享

    说明: 1.我的linux是64位的redhat6.5,安装的oracle版本是11.2.0的. 2.我这是自己安装的linux虚拟机,主机名为ora11g,ip为192.168.100.122 3. ...

  4. JZ2440开发笔记(1)——arm-linux-gcc环境搭建

    1 下载arm-linux-gcc-4.4.3安装包,http://arm9.net/download.asp 2 解压arm-linux-gcc-4.4.3-20100728.tar.gz,使用命令 ...

  5. Cocos2d-x ios 下http请求的另一种实现

    简单描述下需求:游戏要加入事件log,比如玩家升到10级:创建角色:或是,触发这些事件后要求客户端忘后台抛送一条log信息.一般情况下,我们可以直接使用cocos自带的HttpClient(底层用li ...

  6. SSAS数据挖掘算法简介

    决策树分析算法:以二叉树的形式展现,分析出影响某种行为(如购买自行车)的因素,并对这些因素排序. 聚类分析算法:物以类聚,人以群分.分析特定群体所共同含有的属性(因素). 未完,待续..

  7. Android SDK 离线安装方法

    有朋友反映从连接直接下载安装包不能获取到最新版本(每次更新后的包地址需要重新去查找),而且经常无法访问. 最方便的方法是使用代理或vpn接入网络,即可及时下载最新版sdk. 作为一名开发人员,流畅地浏 ...

  8. 【转载】linux 技巧:使用 screen 管理你的远程会话

    转自:https://www.ibm.com/developerworks/cn/linux/l-cn-screen/ 总结 启动并进入一个screen会话:screen 或者 screen -S 名 ...

  9. 部署ActiveMQ的Share File System Master-Slave

    之前在项目里用MQ是用单节点,因为业务量不大没有主从.这样风险很大,会有单点问题.新项目起来了,需要一个高可用的MQ,故研究了下AMQ的几种master-slave方式: 1.Pure Master- ...

  10. [delphi技术]Delphi常见图象格式转换技术

    TJPEGScale = (jsFullSize, jsHalf, jsQuarter, jsEighth);//图片大小(全部,1/2,1/4,1/8)TBitmap.pixelFormat:=pf ...