zoukankan      html  css  js  c++  java
  • 安卓开发笔记——关于AsyncTask的使用

    在安卓开发中,我们经常要进行一些耗时操作,比如数据库操作,获取网络资源,读取内存文件等等,当我们在处理这些耗时操作的时候,如果我们直接在UI主线程进行,那么可能会导致阻塞UI主线程,使得UI界面卡顿,带来很不好的用户体验,因此安卓也给我们提供了2个异步操作的类,Handler和AsyncTask。

    今天先讲AsyncTask,AsyncTask类是Andorid提供给我们的一个轻量级异步类,算是一个框架,它对线程之间的通讯进行了封装,并且提供了简易的编程操作,使得我们可以很轻松的实现后台线程和UI主线程之间的通讯。

    我写了一个异步获取网络图片的小例子,先来看实现效果:

    以上是官网对AsyncTask的一些描述,大致意思是:

    AsyncTask是一个易操作线程使用类,它可以帮助我们把后台线程处理程序的结果发送给UI主线程,使UI线程得到更新。

    AsyncTask类提供了3个泛型参数(Params,Progress,Result)和4个执行步骤(下文会具体提及)

    先来看下3个泛型参数

    1、Params:这是一个任务参数,一般我们会定义成String类型的,例如本例子中要获取网络资源的URL地址

    2、Progress:任务执行的刻度,一般我们会定义成Integer类型

    3、Result:返回结果类型,例如本例中是对网络图片进行获取,那么它的返回类型应该是BitMap

    再来看下4个步骤:

    当我们的类去实现AsyncTask类的时候至少需要实现doInBackground(Params...)方法,这里作为学习,我把每一个的具体工作任务也说说

    它的执行顺序是这样的 onPreExecute-->doInBackground-->onProgressUpdate-->onPostExecute

    1、onPreExecute:这是一个预处理方法,在任务开始的时候执行,我们可以在这里进行一些控件的实例化,设置属性等。(非必须)

    2、doInBackground:这是一个任务操作方法,也是最重要的一个方法,所有的耗时操作都应该在这里执行。(必须)

    3、onProgressUpdate:这是一个进度即时更新方法,在这里我们可以即时更新任务滚动条的进度。(非必须,当在doInBackground里调用publishProgress时触发)

    4、onPostExecute:这是一个任务结果处理方法,在doInBackground里执行完任务,会将结果通知给这个类,在这类中我们可以对UI进行更新操作(非必须)

    上面的1、3、4是UI主线程触发调用的,所以可以对UI进行更新操作,而第2步是个异步操作,不能在里面进行UI的更新操作。

    关于AsyncTask的调用,其实非常简单,我们在AsyncTask类被继承实现的时候,在主线程直接对其对象调用execute(Params..)方法即可。

    好了,文字介绍到此结束,上代码:

    1、布局文件

     1 <LinearLayout 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:gravity="center"
     6     android:orientation="vertical">
     7 
     8     <ImageView
     9         android:id="@+id/imageView"
    10         android:layout_width="wrap_content"
    11         android:layout_height="wrap_content" />
    12 
    13     <Button
    14         android:id="@+id/bt_download"
    15         android:layout_width="wrap_content"
    16         android:layout_height="wrap_content"
    17         android:text="下载图片" />
    18 
    19 </LinearLayout>

    2、AsyncTask的实现类

      1 package com.example.asynctasktest;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.IOException;
      5 import java.io.InputStream;
      6 import java.io.OutputStream;
      7 
      8 import org.apache.http.HttpResponse;
      9 import org.apache.http.client.ClientProtocolException;
     10 import org.apache.http.client.HttpClient;
     11 import org.apache.http.client.methods.HttpGet;
     12 import org.apache.http.impl.client.DefaultHttpClient;
     13 
     14 import android.app.ProgressDialog;
     15 import android.graphics.Bitmap;
     16 import android.graphics.BitmapFactory;
     17 import android.os.AsyncTask;
     18 import android.widget.ImageView;
     19 
     20 public class MyAsyncTask extends AsyncTask<String, Integer, Bitmap> {
     21 
     22     private ImageView imageView;
     23     private ProgressDialog progressDialog;
     24 
     25     public MyAsyncTask(ImageView imageView, ProgressDialog progressDialog) {
     26         this.imageView = imageView;
     27         this.progressDialog = progressDialog;
     28     }
     29 
     30     /**
     31      * 执行第一步 这里为预处理操作,被UI线程所调用(可以在这里完成进度条的属性设置)
     32      */
     33     @Override
     34     protected void onPreExecute() {
     35         super.onPreExecute();
     36         progressDialog.setTitle("当前任务");
     37         progressDialog.setMessage("正在下载图片,请稍后...");
     38         progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置进度条样式,横项
     39         progressDialog.show();
     40     }
     41 
     42     /**
     43      * 执行第二步 这里为异步线程,在这里处理耗时任务操作(比如:下载,读取文件)
     44      * 通过调用publishProgress方法(传递即时任务进度)可以触发onProgressUpdate的执行
     45      */
     46     @Override
     47     protected Bitmap doInBackground(String... params) {
     48         String path=params[0];
     49         Bitmap bitmap=null;
     50         HttpClient httpClient=new DefaultHttpClient();
     51         HttpGet httpGet=new HttpGet(path);
     52         InputStream inputStream=null;
     53         try {    
     54             HttpResponse httpResponse=httpClient.execute(httpGet);
     55             if(httpResponse.getStatusLine().getStatusCode()==200){
     56                 //连接成功
     57 //                HttpEntity entity=httpResponse.getEntity();
     58 //                byte[] data=EntityUtils.toByteArray(entity);
     59 //                bitmap=BitmapFactory.decodeByteArray(data, 0, data.length);
     60                 
     61                 inputStream=httpResponse.getEntity().getContent();
     62                 ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
     63                 long fileSize=httpResponse.getEntity().getContentLength();//文件总大小
     64                 byte[] data=new byte[1024];//每次读取的大小
     65                 int len=0;//本次读取的大小
     66                 int total=0;//累计读取的大小
     67                 while((len=inputStream.read(data))!=-1){
     68                         total+=len;//累计读取的大小
     69                         int values=(int) ((total/(float)fileSize)*100);//得到当前任务进行百分比
     70                         publishProgress(values);//触发onProgressUpdate更新即时进度
     71                         outputStream.write(data, 0, len);
     72                 }
     73                 byte[] result=outputStream.toByteArray();//转换为字节数组
     74                 bitmap=BitmapFactory.decodeByteArray(result, 0, result.length);
     75             }
     76         } catch (ClientProtocolException e) {
     77             e.printStackTrace();
     78         } catch (IOException e) {
     79             e.printStackTrace();
     80         }finally{
     81             if(inputStream!=null){
     82                 try {
     83                     inputStream.close();
     84                 } catch (IOException e) {
     85                     e.printStackTrace();
     86                 }
     87             }
     88         }
     89         
     90         return bitmap;
     91 
     92     }
     93 
     94     /**
     95      * 执行第三步 这里为实时UI更新操作,被UI线程所调用 在这里可以即时更新(如进度条进度)
     96      */
     97     @Override
     98     protected void onProgressUpdate(Integer... values) {
     99         super.onProgressUpdate(values);
    100         progressDialog.setProgress(values[0]);
    101     }
    102 
    103     /**
    104      * 执行第四步 在这里会返回doInBackground的操作结果,被UI线程调用,更新最后UI结果
    105      */
    106     @Override
    107     protected void onPostExecute(Bitmap result) {
    108         super.onPostExecute(result);
    109         progressDialog.dismiss();
    110         imageView.setImageBitmap(result);
    111     }
    112 
    113 }

    3、主类

     1 package com.example.asynctasktest;
     2 
     3 import android.app.ProgressDialog;
     4 import android.os.Bundle;
     5 import android.support.v7.app.ActionBarActivity;
     6 import android.view.View;
     7 import android.view.View.OnClickListener;
     8 import android.widget.Button;
     9 import android.widget.ImageView;
    10 
    11 public class MainActivity extends ActionBarActivity {
    12 
    13     private ImageView imageView;
    14     private Button bt_download;
    15     private ProgressDialog progressDialog;//进度对话框
    16     private String path="http://img.pconline.com.cn/images/photoblog/5/3/7/5/5375781/20096/6/1244302842840.jpg";//下载图片路径
    17     
    18     @Override
    19     protected void onCreate(Bundle savedInstanceState) {
    20         super.onCreate(savedInstanceState);
    21         setContentView(R.layout.activity_main);
    22         
    23         imageView=(ImageView) findViewById(R.id.imageView);
    24         bt_download=(Button) findViewById(R.id.bt_download);
    25         progressDialog=new ProgressDialog(this);
    26         
    27         bt_download.setOnClickListener(new OnClickListener() {
    28             
    29             @Override
    30             public void onClick(View v) {
    31                 MyAsyncTask myAsyncTask=new MyAsyncTask(imageView,progressDialog);
    32                 myAsyncTask.execute(path);
    33             }
    34         });
    35         
    36     }
    37 
    38 
    39 }

    代码到此结束,注释很详细应该很好理解。

    使用AsyncTask类,以下是几条必须遵守的准则:

    • Task的实例必须在UI主线程中创建。
    • execute方法必须在UI主线程中调用。
    • 不要手动的调用onPreExecute(),onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法。
    • 该task只能被执行一次,否则多次调用时将会出现异常。

    当然AsyncTask类不止这些东西,还有线程池的概念,今天先不讲,过几天连同Handler一起说。

    对于简单的异步操作,掌握这些已经够了。

    项目代码:http://pan.baidu.com/s/1kTkTgm7

    作者:Balla_兔子
    出处:http://www.cnblogs.com/lichenwei/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

  • 相关阅读:
    第 2 章 MySQL 架构组成
    MySql学习笔记
    大型项目成功的关键
    内连接区别外连接
    UML2.0
    软件架构师之路
    UVA
    ZOJ
    UVA
    UVA
  • 原文地址:https://www.cnblogs.com/lichenwei/p/4396341.html
Copyright © 2011-2022 走看看