Android AsyncTask 初探
因为在开发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类,遵守的准则:
- Task的实例必须在UI thread中创建;
- Execute()方法必须在UI thread中调用;
- 不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;
- 该task只能被执行一次,否则多次调用时将会出现异常;
- 不能在doInBackground(Params... params)中更改UI组件的信息。
通过看源码,发现AsyncTask实际上就是一个线程池,而网上的说法是AsyncTask比handler要轻量级,显然上不准确的,只能这样说,AsyncTask在代码上比handler要轻量级别,而实际上要比handler更耗资源,因为AsyncTask底层是一个线程池!而Handler仅仅就是发送了一个消息队列,连线程都没有开。
但是,如果异步任务的数据特别庞大,AsyncTask这种线程池结构的优势就体现出来了。
下面我们用一个简单的例子来体验一下:
布局文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 <TextView 7 android:layout_width="fill_parent" 8 android:layout_height="200dp" 9 android:id="@+id/textView" 10 android:textSize="20dp" 11 android:gravity="center" /> 12 <Button 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:id="@+id/button" 16 android:layout_gravity="center" 17 android:textSize="20dp" 18 android:text="启动AsyncTask" /> 19 <ProgressBar 20 android:id="@+id/progress_bar" 21 android:layout_width="match_parent" 22 android:layout_height="wrap_content" 23 android:progress="0" 24 android:max="9" 25 style="@android:style/Widget.ProgressBar.Horizontal"/> 26 27 </LinearLayout>
在MainActivity中实现代码:
1 public class MainActivity extends Activity { 2 private static final String TAG = "topcsa"; 3 TextView textView; 4 Button button; 5 private ProgressBar progressBar; 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.main); 10 textView = (TextView)findViewById(R.id.textView); 11 button = (Button)findViewById(R.id.button); 12 progressBar = (ProgressBar) findViewById(R.id.progress_bar); 13 button.setOnClickListener(new View.OnClickListener(){ 14 15 @Override 16 public void onClick(View v) { 17 // TODO Auto-generated method stub 18 MyAsyncTask asyncTask = new MyAsyncTask(); 19 asyncTask.execute(1000); 20 } 21 }); 22 23 } 24 25 26 class MyAsyncTask extends AsyncTask<Integer, Integer, String> 27 { 28 @Override 29 protected void onPreExecute() { 30 // TODO Auto-generated method stub 31 super.onPreExecute(); 32 Log.d(TAG, "onPreExecute"); 33 } 34 35 @Override 36 protected String doInBackground(Integer... params) { 37 // TODO Auto-generated method stub 38 Log.d(TAG, "doInBackground"); 39 for(int i = 0; i < 10; i++) 40 { 41 publishProgress(i); 42 try { 43 Thread.sleep(params[0]); 44 }catch(InterruptedException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 } 49 Log.d(TAG, "Background work over"); 50 return "Background work over."; 51 } 52 @Override 53 protected void onProgressUpdate(Integer... values) { 54 // TODO Auto-generated method stub 55 super.onProgressUpdate(values); 56 Log.d(TAG, "onProgressUpdate"); 57 progressBar.setProgress(values[0]); 58 textView.setText(Integer.toString(values[0])); 59 } 60 61 @Override 62 protected void onPostExecute(String result) { 63 // TODO Auto-generated method stub 64 super.onPostExecute(result); 65 Log.d(TAG, "onPostExecute, result = " + result); 66 } 67 68 }
运行程序时,做好与日志输出信息对照查看,有助于更好地理解AsyncTask的运作。
下面我们结合java.io.File类完成一个手机文件浏览器:
默认布局文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:orientation="vertical" 5 android:layout_width="fill_parent" 6 android:layout_height="fill_parent"> 7 <ListView 8 android:id="@+id/list" 9 android:layout_width="fill_parent" 10 android:layout_height="wrap_content" /> 11 </LinearLayout>
子布局文件file_list.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <TableLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:orientation="vertical" 5 android:layout_width="fill_parent" 6 android:layout_height="fill_parent"> 7 <TableRow> 8 <ImageView 9 android:id="@+id/img" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" /> 12 <TextView 13 android:id="@+id/name" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" /> 16 </TableRow> 17 </TableLayout>
默认的.java文件:
1 public class MyAsyncTaskListFileDemo extends Activity { 2 private List<Map<String,Object>> allFileItems = new ArrayList<Map<String,Object>>() ; 3 private SimpleAdapter simple = null ; 4 private ListView list = null ; 5 private ListFileThread ft = null ; 6 @Override 7 public void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 super.setContentView(R.layout.main); 10 this.list = (ListView) super.findViewById(R.id.list) ; 11 File filePath = new File(java.io.File.separator); // 从根目录下开始列出 12 this.list.setOnItemClickListener(new OnItemClickListenerImpl()) ; 13 this.ft = new ListFileThread() ; 14 this.ft.execute(filePath) ; 15 } 16 17 private class OnItemClickListenerImpl implements OnItemClickListener{ 18 19 @Override 20 public void onItemClick(AdapterView<?> parent, View view, int position, 21 long id) { 22 File currFile = (File) MyAsyncTaskListFileDemo.this.allFileItems 23 .get(position).get("name"); 24 if (currFile.isDirectory()) { // 当前是一个目录 25 MyAsyncTaskListFileDemo.this.allFileItems = new ArrayList<Map<String,Object>>() ; 26 MyAsyncTaskListFileDemo.this.ft = new ListFileThread() ; 27 MyAsyncTaskListFileDemo.this.ft.execute(currFile) ; 28 } 29 } 30 31 } 32 33 private class ListFileThread extends AsyncTask<File, File, String> { 34 35 @Override 36 protected void onProgressUpdate(File... values) { 37 Map<String,Object> fileItem = new HashMap<String,Object>() ; // 表示可以返回 38 if (values[0].isDirectory()) { 39 fileItem.put("img", R.drawable.folder_close); // 文件夹 40 } else { // 是文件 41 fileItem.put("img",R.drawable.file) ; 42 } 43 fileItem.put("name", values[0]) ; 44 MyAsyncTaskListFileDemo.this.allFileItems.add(fileItem) ; 45 MyAsyncTaskListFileDemo.this.simple = new SimpleAdapter( 46 MyAsyncTaskListFileDemo.this, 47 MyAsyncTaskListFileDemo.this.allFileItems, 48 R.layout.file_list, new String[] { "img", "name" }, 49 new int[] { R.id.img, R.id.name }); 50 MyAsyncTaskListFileDemo.this.list 51 .setAdapter(MyAsyncTaskListFileDemo.this.simple); 52 } 53 54 @Override 55 protected String doInBackground(File... params) { 56 if (!params[0].getPath().equals(java.io.File.separator)) { // 不是根目录 57 Map<String,Object> fileItem = new HashMap<String,Object>() ; // 表示可以返回 58 fileItem.put("img",R.drawable.folder_open) ; // 可以返回 59 fileItem.put("name", params[0].getParentFile()) ; 60 MyAsyncTaskListFileDemo.this.allFileItems.add(fileItem) ; 61 } 62 if (params[0].isDirectory()) { // 是文件夹 63 File tempFile [] = params[0].listFiles() ; 64 if(tempFile != null) { 65 for (int x = 0; x < tempFile.length; x++) { 66 this.publishProgress(tempFile[x]) ; 67 } 68 } 69 } 70 return "文件已列出"; 71 } 72 } 73 }
运行程序即可。
当然,AsyncTask也不是完全的完美。下面加个有关AsyncTask不足的文章:
http://www.oschina.net/question/54100_27825
文章出处:http://www.cnblogs.com/scetopcsa/
欢迎关注微信公众号:yilu_yiyou(一路一游),一个不仅仅是代码的世界!
如果文中有什么错误,欢迎指出。以免更多的人被误导。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。