Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组件的属性值。但实际开发中,很多地方需要在工作线程中改变UI组件的属性值,比如下载网络图片、动画等等。本篇博客主要介绍Handler是如何发送与处理线程上传递来的消息,并讲解Message的几种传递数据的方式,最后均会以小Demo来演示。

Handler

   Handler ,它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。

Handler主要有两个作用:

  • 在工作线程中发送消息。
  • 在UI线程中获取、处理消息。

上面介绍到Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage:

  • Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
  • sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对象和Message对象被入队到消息队列中,是立即执行还是延迟执行。

Post

对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。

在Handler中,关于Post方式的方法有:

  • boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。
  • boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。
  • boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行
  • void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。

有一点值得注意的是,对于Post方式而言,它其中Runnable对象的run()方法的代码,均执行在UI线程上,所以对于这段代码而言,不能执行在UI线程上的操作,一样无法使用post方式执行,比如说访问网络,下面提供一个例子,使用post方式从互联网上获取一张图片,并且显示在ImageView中。

package com.bgxt.datatimepickerdemo;import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;public class HandlerPostActivity2 extends Activity {  private Button btnDown;
  private ImageView ivImage;
  private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
  private ProgressDialog dialog;
  // 一个静态的Handler,Handler建议声明为静态的
  private static  Handler handler=new Handler();
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.asynctask_activity);

    btnDown = (Button) findViewById(R.id.btnDown);
    ivImage = (ImageView) findViewById(R.id.ivSinaImage);    dialog = new ProgressDialog(this);
    dialog.setTitle("提示");
    dialog.setMessage("正在下载,请稍后...");
    dialog.setCancelable(false);

    btnDown.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // 开启一个子线程,用于下载图片
        new Thread(new MyThread()).start();
        // 显示对话框
        dialog.show();
      }
    });
  }

  public class MyThread implements Runnable {    @Override
    public void run() {
      // 下载一个图片
      HttpClient httpClient = new DefaultHttpClient();
      HttpGet httpGet = new HttpGet(image_path);
      HttpResponse httpResponse = null;
      try {
        httpResponse = httpClient.execute(httpGet);
        if (httpResponse.getStatusLine().getStatusCode() == 200) {
          byte[] data = EntityUtils.toByteArray(httpResponse
              .getEntity());
          // 得到一个Bitmap对象,并且为了使其在post内部可以访问,必须声明为final
          final Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
          handler.post(new Runnable() {
            @Override
            public void run() {
              // 在Post中操作UI组件ImageView
              ivImage.setImageBitmap(bmp);
            }
          });
          // 隐藏对话框
          dialog.dismiss();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }  }
}

Message

Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。下面先介绍一下Message。

Message是一个final类,所以不可被继承。Message封装了线程中传递的消息,如果对于一般的数据,Message提供了getData()和setData()方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对,对于基本数据类型,使用起来很简单,这里不再详细讲解。而对于复杂的数据类型,如一个对象的传递就要相对复杂一些。在Bundle中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些Android自带的类,其实已经实现了这两个接口中的某一个,可以直接使用。方法如下:

putParcelable(String key,Parcelable value):需要传递的对象类实现Parcelable接口。

pubSerializable(String key,Serializable value):需要传递的对象类实现Serializable接口。

还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:

int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。

int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。

Object obj:传递一个任意的对象。

int what:定义的消息码,一般用于设定消息的标志。

对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。

既然Message是在线程间传递消息,那么先以一个Demo讲解一下Message的使用,还是常规的从互联网上下载一张图片的Demo,下载后使用ImageView控件展示:

package com.bgxt.datatimepickerdemo;import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;public class HandlerMessageActivity1 extends Activity {  private Button btnDown;
  private ImageView ivImage;
  private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
  private ProgressDialog dialog;
  private static int IS_FINISH = 1;  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.asynctask_activity);    btnDown = (Button) findViewById(R.id.btnDown);
    ivImage = (ImageView) findViewById(R.id.ivSinaImage);    dialog = new ProgressDialog(this);
    dialog.setTitle("提示信息");
    dialog.setMessage("正在下载,请稍后...");
    dialog.setCancelable(false);    btnDown.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          new Thread(new MyThread()).start();
          dialog.show();
      }
    });
  }  private  Handler handler = new Handler() {
    // 在Handler中获取消息,重写handleMessage()方法
    @Override
    public void handleMessage(Message msg) {
      // 判断消息码是否为1
      if(msg.what==IS_FINISH){
        byte[] data=(byte[])msg.obj;
        Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
        ivImage.setImageBitmap(bmp);
        dialog.dismiss();
      }
    }
  };  public class MyThread implements Runnable {    @Override
    public void run() {
      HttpClient httpClient = new DefaultHttpClient();
      HttpGet httpGet = new HttpGet(image_path);
      HttpResponse httpResponse = null;
      try {
        httpResponse = httpClient.execute(httpGet);
        if (httpResponse.getStatusLine().getStatusCode() == 200) {
          byte[] data = EntityUtils.toByteArray(httpResponse
              .getEntity());
          // 获取一个Message对象,设置what为1
          Message msg = Message.obtain();
          msg.obj = data;
          msg.what = IS_FINISH;
          // 发送这个消息到消息队列中
          handler.sendMessage(msg);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

下载地址 :  ThreadDemo

Android–多线程之Handler下载图片源码相关推荐

  1. Android 多线程之Handler

    前言 Android的消息传递机制是另外一种形式的"事件处理",这种机制主要是为了解决Android应用中多线程的问题,在Android中不允许Activity新启动的线程访问该A ...

  2. Android多线程之IntentService源码解析

    想要了解 IntentService 的工作原理需要先对 Android 系统中以 Handler.Looper.MessageQueue 组成的异步消息处理机制以及 HandlerThread 有所 ...

  3. Android 多线程之IntentService 完全详解

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52426425 出自[zejian的博客] 关联文章: Android ...

  4. Android 多线程之HandlerThread 完全详解

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52426353 出自[zejian的博客] 关联文章: Android ...

  5. Android多线程之ArrayBlockingQueue源码解析

    阻塞队列系列 Android多线程之LinkedBlockingQueue源码解析 Android多线程之SynchronousQueue源码解析 Andorid多线程之DelayQueue源码分析 ...

  6. python爬取图片源码_半次元图片爬取-python爬取半次元图片源码下载-西西软件下载...

    python爬取半次元图片源码,由大神自制的python爬取工具,本源码针对半次元图片平台,可以爬取最新的网站图片资源,支持自定义保存目录,非常方便,需要requests库的支持,想要相关源码资源的朋 ...

  7. 分享66个ASP贺卡图片源码,总有一款适合您

    分享66个ASP贺卡图片源码,总有一款适合您 66个ASP贺卡图片源码下载链接:https://pan.baidu.com/s/1kkCBziEePMdsXsMb1Ytbaw?pwd=lswt  提取 ...

  8. 【老生谈算法】MATLAB生成雪花图片源码——生成雪花图片

    MATLAB生成雪花图片源码 1.文档下载: 本算法已经整理成文档如下,有需要的朋友可以点击进行下载 序号 文档(点击下载) 本项目文档 [老生谈算法]MATLAB生成雪花图片源码.doc 2.算法详 ...

  9. 分享107个ASP贺卡图片源码,总有一款适合您

    分享107个ASP贺卡图片源码,总有一款适合您 107个ASP贺卡图片源码下载链接:https://pan.baidu.com/s/15zaUiNl-PifQY0SSWMjgow?pwd=a1b8  ...

最新文章

  1. 点击文字弹出一个DIV层窗口代码
  2. Flink从入门到精通100篇(二十二)-微博基于Flink的机器学习实战项目
  3. latex转word_Latex与word转换及相关问题解决方法
  4. orange软件_Orange和戴尔技术公司合作 联合测试和开发5G和商业模式
  5. php 字符串的比较大小,PHP如何比较字符串的大小?
  6. 权限操作-springSecurity概述及快速入门步骤分析
  7. 使用Q进行同步的Promises操作
  8. fis pure开发php,50个精品网站鉴赏
  9. 使用vlc播放器做rtsp流媒体服务器
  10. python入门应该学什么专业好_真的能半个月学会Python吗?(文末附python入门进阶教程)...
  11. 读取unicode编码文件的乱码解决
  12. python画曲线图-如何使用python画曲线图
  13. TP-link路由器设置界面展示
  14. PR学习笔记总结,附带剪辑成品
  15. 模型预测控制Paolo Falcone 博士面试 (二) - MPC控制的稳定性
  16. 如何下载安装fireBug
  17. 小学计算机课动画制作的评课稿,信息技术评课稿
  18. 计算机函数求销售额公式,利用excel函数公式中的LARGE函数和SUM函数提取前五名的销售额...
  19. OutputFormat类——Hadoop
  20. P4165 [SCOI2007]组队 推柿子+差分

热门文章

  1. hdu4990 矩阵快速幂
  2. visual studio 64位汇编 listing列表文件
  3. 【Linux 内核 内存管理】Linux 内核内存布局 ② ( x86_64 架构体系内存分布 | 查看 /proc/meminfo 文件 | /proc/meminfo 重要字段解析 )
  4. 【Windows 逆向】使用 CE 分析内存地址 ( 运行游戏 | 使用 CE 工具分析游戏内子弹数量对应的内存地址 | 内存地址初步查找 | 使用二分法定位最终的内存地址 )
  5. 【错误记录】Android 编译时技术版本警告 ( 注解处理器与主应用支持的 Java 版本不匹配 )
  6. socket_循环发送消息
  7. iOS开发-登录界面开发(6)Toast-Swift的使用-Swfit4.1_Xcode9.3.1
  8. Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake 线段树维护dp
  9. HDU2222 Keywords Search(AC自动机模板)
  10. NOIP2010-普及组复赛模拟试题-第一题-手机