• 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类,遵守的准则:

    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这种线程池结构的优势就体现出来了。

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

    布局文件:

     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>
    View Code

    在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        } 
    View Code

    运行程序时,做好与日志输出信息对照查看,有助于更好地理解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>
    View Code

    子布局文件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>
    View Code

    默认的.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 }
    View Code

    运行程序即可。

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

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

    作者:af74776
    文章出处:http://www.cnblogs.com/scetopcsa/
    欢迎关注微信公众号:yilu_yiyou(一路一游),一个不仅仅是代码的世界!
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    小白学 Python 爬虫(31):自己构建一个简单的代理池
    编程语言排名到底是哪来的?
    复盘 2019 ,展望 2020
    小白学 Python 爬虫(30):代理基础
    小白学 Python 爬虫(29):Selenium 获取某大型电商网站商品信息
    小白学 Python 爬虫(28):自动化测试框架 Selenium 从入门到放弃(下)
    小白学 Python 爬虫(27):自动化测试框架 Selenium 从入门到放弃(上)
    小白学 Python 爬虫(26):为啥上海二手房你都买不起
    [Vue 牛刀小试]:第八章
    从学生到社会银,我的两年记
  • 原文地址:https://www.cnblogs.com/scetopcsa/p/3676148.html
Copyright © 2020-2023  润新知