Handler和AsyncTask的基础理解

首先说下这是一个很枯燥的文章,因为没什么效果;但是个人感觉还是非常有用的;所以今天写一下个人对 Android 异步任务的理解;
 
为什么要使用异步任务?
我们知道,Android 中只有UI线程(主线程)才能进行对UI的更新操作,其他线程是不能直接操作UI.
这样的好处是保证了UI的稳定性和准确性,避免多个线程同时对UI进行操作而造成UI的混乱.
但Android是一个多线程的 操作系统 ,我们总不能把所有的任务都放在主线程中进行实现,
比如网络操作,文件读取等耗时操作,如果全部放到主线程去执行,可能会造成后面任务的阻塞.
Android会去检测这种阻塞,当阻塞时间太长的时候,就会抛出ANR异常.
我们需要将这些耗时操作放在非主线程中去执行.这样既避免了Android的单线程模型,又避免了ANR.这时候我们就需要异步操作了;
 
异步操作android提供了两种:Handler+message  和  AsyncTask
我们先来看一个使用两种方式实现的一个小demo(点击button按钮跳转到一个activity,然后联网获取网络图片,加载到imageview上,联网是耗时操作,所以必须开启异步任务)
 
可以看到使用两种方式实现起来效果一样,两者的概述啊什么的就不聊了,直接聊demo,最后聊下两者的优缺点,什么时候用哪个;
 
首先看下AsyncTask实现:
首先我们看下AsyncTask和他的几个方法:
 
[java]   view plain   copy
  1. /** 
  2.  * AsyncTask本身是一个抽象类,后面的三个泛型是必须要写的: 
  3.  * 
  4.  * Params:启动任务时输入的参数类型 
  5.  * Progress:后台任务执行中返回进度值的类型. 
  6.  * Result:后台任务执行完成后返回结果的类型 
  7.  * 
  8.  */  
  9. public class MyAsyncTask extends AsyncTask<Void,Void,Void>{  
  10.   
  11.     @Override  
  12.     /** 
  13.      * 执行耗时操作前调用; 
  14.      */  
  15.     protected void onPreExecute() {  
  16.         super.onPreExecute();  
  17.     }  
  18.   
  19.     @Override  
  20.     /** 
  21.      * 这个方法是必须重写的方法,其他方法随意,用到就写,用不到不用管 
  22.      * 这个方法就是做耗时操作的,相当于new Thread()方法,所有的耗时操作全部在这做 
  23.      * 
  24.      */  
  25.     protected Void doInBackground(Void... params) {  
  26.         return null;  
  27.     }  
  28.   
  29.     @Override  
  30.     /** 
  31.      * 当doInBackground()方法完成后执行此方法; 
  32.      * 并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新. 
  33.      */  
  34.     protected void onPostExecute(Void aVoid) {  
  35.         super.onPostExecute(aVoid);  
  36.     }  
  37.   
  38.     @Override  
  39.     /** 
  40.      * 当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法. 
  41.      * 通过此方法我们可以知道任务的完成进度. 
  42.      */  
  43.     protected void onProgressUpdate(Void... values) {  
  44.         super.onProgressUpdate(values);  
  45.     }  
  46. }  

 上面这个类和demo无关,只是让不了解的朋友们简单熟悉下AsyncTask;
MainActivity的代码就不复制了,很简单,布局只有一个button,代码只有一个跳转,当点击button的时候跳转到第二个页面;
第二个页面(显示图片的activity),布局是一个相对布局,里面放一个imageview,上面放了一个进度条,当加载图片的时候显示出来,加载完后隐藏掉;
我们来看下第二个activity的代码:
[java]   view plain   copy
  1. public class ImageActivity extends Activity{  
  2.   
  3.     private ImageView mImageView;  
  4.     private ProgressBar mProgressBar;  
  5.     String url="http://image.tianjimedia.com/uploadImages/2015/129/56/J63MI042Z4P8.jpg";  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_image);  
  11.   
  12.         init();  
  13.     }  
  14.   
  15.     private void init() {  
  16.         mImageView= (ImageView) findViewById(R.id.imageview);  
  17.         mProgressBar= (ProgressBar) findViewById(R.id.progressbar);  
  18.   
  19.         ImageAsyncTask myAsyncTast = new ImageAsyncTask(mImageView,mProgressBar);  
  20.   
  21.         /** 
  22.          * 启动异步任务的处理 
  23.          * 只能在UI线程中调用AsyncTask的execute方法. 
  24.          * 每个AsyncTask只能被执行(execute方法)一次,多次执行将会引发异常 
  25.          * 
  26.          */  
  27.         myAsyncTast.execute(url);  
  28.     }  
  29. }  

自定义AsyncTask的代码:
[java]   view plain   copy
  1. /** 
  2.  * 执行顺序:onPreExecute-->doInBackground-->onPostExecute 
  3.  * 三个参数的的解释:第一个是指 doInBackground中接收的参数的类型 
  4.  * 第二个是指onProgressUpdate中接收的参数的类型 
  5.  * 第三个是每日doInBackground返回值的类型以及onPostExecute接收的参数的类型 
  6.  * 
  7.  * task.execute(url);   图片的url就是传到doInBackground中的参数 
  8.  */  
  9. public class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {  
  10.   
  11.     private ImageView mImageView;  
  12.     private ProgressBar mProgressBar;  
  13.   
  14.     public ImageAsyncTask(ImageView mImageView, ProgressBar mProgressBar) {  
  15.         this.mImageView = mImageView;  
  16.         this.mProgressBar = mProgressBar;  
  17.     }  
  18.   
  19.     @Override  
  20.     //用于异步处理前的操作  
  21.     protected void onPreExecute() {  
  22.         super.onPreExecute();  
  23.         mProgressBar.setVisibility(View.VISIBLE);  
  24.     }  
  25.   
  26.     @Override  
  27.     //所有的异步任务都在这进行;这个params是一个数组,可以传递过来多个值,我们这里只用到一个  
  28.     protected Bitmap doInBackground(String... params) {  
  29.         //获取传进来的参数  
  30.         String url = params[0];  
  31.         Bitmap bitmap = null;  
  32.         URLConnection connection;  
  33.         InputStream is;  
  34.         try {  
  35.             connection = new URL(url).openConnection();  
  36.             is = connection.getInputStream();  
  37.             //为了更清楚的看到加载图片的等待操作,将线程休眠3秒钟.  
  38.             Thread.sleep(1000);  
  39.             BufferedInputStream bis = new BufferedInputStream(is);  
  40.             //通过decodeStream方法解析输入流  
  41.             bitmap = BitmapFactory.decodeStream(bis);  
  42.             is.close();  
  43.             bis.close();  
  44.         } catch (IOException e) {  
  45.             e.printStackTrace();  
  46.         } catch (InterruptedException e) {  
  47.             e.printStackTrace();  
  48.         }  
  49.         return bitmap;  
  50.     }  
  51.   
  52.     @Override  
  53.     //用于UI的更新.此方法的参数为doInBackground方法返回的值  
  54.     protected void onPostExecute(Bitmap bitmap) {  
  55.         super.onPostExecute(bitmap);  
  56.         //隐藏进度条  
  57.         mProgressBar.setVisibility(View.GONE);  
  58.         //将图片设置到view  
  59.         mImageView.setImageBitmap(bitmap);  
  60.   
  61.     }  
  62. }  

这里面为了演示异步任务,所以使用IO流来;在真实的项目中可以直接使用glide;
 
下面我们看下Handler+Message怎么实现:
[java]   view plain   copy
  1. public class ImageActivity extends Activity{  
  2.   
  3.     private ImageView mImageView;  
  4.     private ProgressBar mProgressBar;  
  5.     String url="http://image.tianjimedia.com/uploadImages/2015/129/56/J63MI042Z4P8.jpg";  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_image);  
  11.   
  12.         init();  
  13.     }  
  14.   
  15.     private void init() {  
  16.         mImageView= (ImageView) findViewById(R.id.imageview);  
  17.         mProgressBar= (ProgressBar) findViewById(R.id.progressbar);  
  18.   
  19.         //这时候需要加载网络图片,属于耗时操作,必须放到子线程中执行  
  20.         <span style="color:#ff6666;">new Thread(){  
  21. </span>            @Override  
  22.             public void run() {  
  23.                 mProgressBar.setVisibility(View.VISIBLE);  
  24.                 Bitmap bitmap =  null;  
  25.                 URLConnection connection ;  
  26.                 InputStream is ;  
  27.                 try {  
  28.                     connection = new URL(url).openConnection();  
  29.                     is = connection.getInputStream();  
  30.                     BufferedInputStream bis = new BufferedInputStream(is);  
  31.                     //通过decodeStream方法解析输入流  
  32.                     bitmap = BitmapFactory.decodeStream(bis);  
  33.                     is.close();  
  34.                     bis.close();  
  35.   
  36.                     <span style="color:#ff6666;">//创建message  
  37.                     Message msg = Message.obtain();  
  38.                     //给msg赋值,可以赋任何类型的值  
  39.                     msg.obj=bitmap;  
  40.                     //延时一秒发送消息,一旦handler收到消息立即执行  
  41.                     handler.sendMessageDelayed(msg,1000);  
  42.   
  43. </span>                } catch (IOException e) {  
  44.                     e.printStackTrace();  
  45.                 }  
  46.             }  
  47.         }.start();  
  48.     }  
  49.   
  50.    <span style="color:#ff6666;"private Handler handler=new Handler(){  
  51.         @Override  
  52.         //只要子线程一发消息,此方法马上执行,并且是在主线程中做的,更新UI的操作可以在这里面做  
  53.         public void handleMessage(Message msg) {  
  54.             mProgressBar.setVisibility(View.GONE);  
  55.             //获取图片  
  56.             Bitmap bitmap= (Bitmap) msg.obj;  
  57.             mImageView.setImageBitmap(bitmap);  
  58.   
  59.         }  
  60. </span>    };  
  61. }  
 
开启子线程也有两种方法开启:
[java]   view plain   copy
  1. new Thread(){  
  2.             public void run() {  
  3.   
  4.             };  
  5.         }.start();  

 
[java]   view plain   copy
  1. new Thread(new Runnable() {  
  2.             public void run() {  
  3.   
  4.             }  
  5.         }).start();  

第一个方法可以直接sleep,第二种方法Thread.sleep;  因为sleep是Thread的方法,第一个run方法是在Thread方法内,第二个run是内名对象
在子线程中做耗时操作完成后发送message也有两种方式:
第一种就是我们demo中使用的这种;
第二种就是发送空消息;不用创建msg,直接发送,然后handler收到这个空消息做指定操作;
[java]   view plain   copy
  1. //这个100可以理解为一个标示,因为在handler接收的时候需要来看这个标示判断做什么操作  
  2. handler.sendEmptyMessage(100);  
  3.     
[java]   view plain   copy
  1. //在这里面做一个switch判断:因为有可能一个类中发送多个消息执行不同的操作  
  2.             switch (msg.what){  
  3.                 case 100:  
  4.                     //做相应的操作  
  5.                     break;  
  6.             }  

好了,基本用法就这些了,下面说下两者的优缺点,以便日后大家用到之时选择用哪个:

AsyncTask:
优点:简单,快捷,过程可控;
缺点:使用多个异步操作并需要修改UI时,就非常复杂了;
 
Handler+Message:
优点:结果清晰,功能定义明确;执行多个后台任务时简单;
缺点:在单个后台异步处理时,显得代码稍多,结构稍复杂;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值