zoukankan      html  css  js  c++  java
  • 安卓开发_深入理解Handler消息传递机制

    一、概述

    因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面

    二、消息类(Message)

    消息类是存放在MessageQueue中的,而一个MessageQueue中可以包含多个Message对象

    每一个Message对象可以通过Message.obtain()或者Handler.obtainMessage()方法获得

    一个Message具有的属性:

    属性

    类型

    介绍

    arg1

    int

    存放整型数据

    arg2

    int

    存放整型数据

    obj

    Object

    存放Object类型的任意对象

    replyTo

    Message

    指定此Message发送到哪里的可选Message对象

    what          

    int

    指定用户自定义的消息代码,接受者可以了解这个消息的信息

    一个Message对象可以携带int类型的数据,而如果要携带其他类型的数据,可以将要携带的数据保存到Bundle对象中,然后通过Message类的setDate()方法将其添加到Message中

    注:

    1、尽量使用Message.what标识信息,方便用于不同的方式处理Message

    2、通常情况下,尽量使用Message.obtain()或者Handler.obtainMessage()方法从消息池中获得空消息对象,以便节省资源,而不是使用Message的默认构造方法

    3、当一个Message对象只需要携带int型数据的时候,优先使用Message.arg1或Message.arg2属性,这要比用Bundle携带int数据节省内存

    三、消息处理类(Handler)

    Handler 允许 发送或者处理 Message或者Runnable 类的对象到其(Handler)所在线程的MessageQueue中

    主要有两个作用:

    1、连接主线程和子线程进行通信(UI线程和工作线程通信)

    2、将Message对象 通过post()或者sendMessage()方法发送到MessageQueue中,

    当MessageQueue循环到该对象时,调用相应的Handler对象的handlerMessage()方法进行处理

    Handler类提供的部分方法:

    方法

    介绍

    handleMessage(Message msg)

    处理消息的方法。

    通常使用该方法处理消息,

    在发送消息时,该方法会自动回调

    Post(Runnable r)

    立即发送Runnable对象,

    注:该Runnable对象最终将被封装成Mwssage对象

    PostAtTime(Runnable r,long uptimeMillis)

    定时发送Runnable对象,

    注:该Runnable对象最终将被封装成Mwssage对象

    postDelayed(Runnable r,long delayMillis)

    延迟发送Runnable对象,

    注:该Runnable对象最终将被封装成Mwssage对象

    sendEmptyMessage(int what)

    发送空消息

    sendMessage(Message msg)

    立即发送消息

    sendMessageAtTime(Message msg)

    定时发送消息

    sendMessageDelayed(Message msg,long delayMillis)

    延迟发送消息

    注:在一个线程中,只能有一个Looper和MessageQueue,却可以有多个Handler,这些Handler共享同一个Looper和MessageQueue

    四、循环着(Looper)

    1、从上面只是可以知道:一个线程中,只能有一个Looper和MessageQueue。

    也就是说一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列),一个MessageQueue又存放着多条Message

    注意:MessageQueue中,消息的存放时FIFO(先进先出)的。

    2、Looper对象是为了一个线程开启一个消息循环,来操作MessageQueue

    注:在主线程中,系统会为主线程自动创建一个Looper对象来开启消息循环。而在非主线程中,是没有Looper对象的,没有Looper对象就不能创建Handler对象

    so,在主线程中直接创建Handler对象是可以的。但是在非主线程中创建Handler对象则会产生异常

    3、如果需要在非主线创建Handler对象

    (1)使用Looper类的prepare()方法来初始化一个Looper对象

    (2)创建Handler对象

    (3)使用Looper类的loop()方法启动Looper,开启消息循环

                       //需要先有Looper对象
                Looper.prepare();//会创建一个Looper对象,并把该对象放入到该线程的本地变量中,在Looper的构造方法中创建了MessageQueue对象
                //在子线程中实例化handler,子线程中没有Looper对象 
                
                handler = new Handler(){
                    
                };//如果直接实例化Handler,会异常 new RuntimeException,原因是子线程中没有Looper对象 
                
                //让Looper对象循环读取MessageQueue中的消息
                //循环从队列中读取消息,当读到消息时,会去调用   msg.target.dispatchMessage(msg);
                //在Message类中有一个target成员,当发送消息时,target成员被赋值为当前的 handler对象
                Looper.loop();

    Looper提供的部分方法:

    方法

    描述

    prepare()

    用于初始化Looper

    loop()

    启动Looper线程,线程循环消息队列(MessageQueue)获取和处理信息

    myLooper()

    获得当前线程的Looper对象

    getThread

    获得Looper对象所属的线程

    quit()

    结束Looper循环

    *注*:Looper.loop()方法,这个方法是循环消息队列!即这个方法内部相当于正在执行一个死循环,所以在Looper.loop()代码之后的代码都不会执行

    ,而只有再调用 Looper.quit()之后才会执行后面的代码

    -------------------------------------------------------------华丽的分割线------------------------------------------------------------------

    让我们看几个例子来深入理解下Handler消息传递机制

    1、子线程向主线程发送消息

    在主线程中启动一个子线程下载图片,子线程传消息递给主线程,让主线程处理。(了解子线程发送Runnable对象和发送Message对象的两种方法)

     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:orientation="vertical"
     6     android:gravity="center_horizontal"
     7      >
     8 
     9     <ImageView 
    10         android:layout_width="200dp"
    11         android:layout_height="200dp"
    12         android:id="@+id/show_image"
    13         android:src="@drawable/ic_launcher"
    14         />
    15     
    16     <Button 
    17         android:layout_width="wrap_content"
    18         android:layout_height="wrap_content"
    19         android:id="@+id/down_image"
    20         android:text="下载"
    21         />
    22 
    23 </LinearLayout>
    布局文件代码

    (1)发送Message对象的方法

     1 package com.xqx.handle;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.http.HttpResponse;
     6 import org.apache.http.client.ClientProtocolException;
     7 import org.apache.http.client.HttpClient;
     8 import org.apache.http.client.methods.HttpGet;
     9 import org.apache.http.impl.client.DefaultHttpClient;
    10 import org.apache.http.util.EntityUtils;
    11 
    12 import android.app.Activity;
    13 import android.graphics.Bitmap;
    14 import android.graphics.BitmapFactory;
    15 import android.os.Bundle;
    16 import android.os.Handler;
    17 import android.os.Message;
    18 import android.view.View;
    19 import android.view.View.OnClickListener;
    20 import android.widget.Button;
    21 import android.widget.ImageView;
    22 
    23 
    24 public class MainActivity extends Activity {
    25     private String path = "http://images2015.cnblogs.com/blog/493196/201509/493196-20150911220222090-1272536050.jpg";//图片下载地址
    26     private ImageView showImage;
    27     private Button downImage;
    28     //哪一个线程是接受消息的,就在哪个线程中实例化Handler对象
    29     //因为主线程中,系统会为自动创建Looper对象,开启循环消息,所以只需要在主线程中定义Handler对象
    30     private Handler handler = new Handler(){
    31         @Override //处理消息的方法,当消息发送过来时,该方法自动回调
    32         public void handleMessage(android.os.Message msg) {
    33             //处理方法,将图片显示在ImageView中
    34             showImage.setImageBitmap((Bitmap) msg.obj);
    35             
    36         };
    37     };
    38     @Override
    39     protected void onCreate(Bundle savedInstanceState) {
    40         // TODO Auto-generated method stub
    41         super.onCreate(savedInstanceState);
    42         setContentView(R.layout.activity_main);
    43         
    44         showImage = (ImageView) findViewById(R.id.show_image);
    45         downImage = (Button) findViewById(R.id.down_image);
    46         
    47         downImage.setOnClickListener(new OnClickListener() {
    48             
    49             @Override
    50             public void onClick(View v) {
    51                 // TODO Auto-generated method stub
    52                 //开启一个线程下载图片
    53                 new Thread(new Runnable() {
    54                     
    55                     @Override
    56                     public void run() {
    57                         // TODO Auto-generated method stub
    58                         HttpGet get = new HttpGet(path);
    59                         HttpClient client = new DefaultHttpClient();
    60                         HttpResponse response = null;
    61                         
    62                         try {
    63                             response = client.execute(get);
    64                             if(response.getStatusLine().getStatusCode()==200)
    65                             {
    66                                 //获得下载后的图片的字节数据
    67                                 byte b[] = EntityUtils.toByteArray(response.getEntity());
    68                                 //将图片字节数据转换成Bitmap格式
    69                                  Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
    70                                  //下载完成,将图片发送给主线程
    71                                  //从MessageQueue中获取可用的Message对象,如果没有可用的,则会创建一个新的Message对象
    72                                  Message msg = Message.obtain();
    73                                  //把发送的图片放到msg对象中
    74                                  msg.obj = bitmap;
    75                                  //使用Handler.sendMessage(Message msg)方法传递消息
    76                                  handler.sendMessage(msg);
    77                             }
    78                             
    79                             
    80                         } catch (ClientProtocolException e) {
    81                             // TODO Auto-generated catch block
    82                             e.printStackTrace();
    83                         } catch (IOException e) {
    84                             // TODO Auto-generated catch block
    85                             e.printStackTrace();
    86                         }
    87                         
    88                         
    89                     }
    90                 }).start();//不要忘记开启线程
    91             }
    92         });
    93         
    94     }
    95     
    96     
    97 }
    Handler.sendMessage(Message msg)

    (2)、发送Runnable对象的方法

     1 package com.xqx.handle;
     2 
     3 import java.io.IOException;
     4 
     5 import org.apache.http.HttpResponse;
     6 import org.apache.http.client.ClientProtocolException;
     7 import org.apache.http.client.HttpClient;
     8 import org.apache.http.client.methods.HttpGet;
     9 import org.apache.http.impl.client.DefaultHttpClient;
    10 import org.apache.http.util.EntityUtils;
    11 
    12 import android.app.Activity;
    13 import android.graphics.Bitmap;
    14 import android.graphics.BitmapFactory;
    15 import android.os.Bundle;
    16 import android.os.Handler;
    17 import android.os.Message;
    18 import android.view.View;
    19 import android.view.View.OnClickListener;
    20 import android.widget.Button;
    21 import android.widget.ImageView;
    22 
    23 
    24 public class Handler2 extends Activity {
    25     private String path = "http://images2015.cnblogs.com/blog/493196/201509/493196-20150911220222090-1272536050.jpg";//图片下载地址
    26     private ImageView showImage;
    27     private Button downImage;
    28     //哪一个线程是接受消息的,就在哪个线程中实例化Handler对象
    29     //因为主线程中,系统会为自动创建Looper对象,开启循环消息,所以只需要在主线程中定义Handler对象
    30     private Handler handler = new Handler();
    31     @Override
    32     protected void onCreate(Bundle savedInstanceState) {
    33         // TODO Auto-generated method stub
    34         super.onCreate(savedInstanceState);
    35         setContentView(R.layout.activity_main);
    36         
    37         showImage = (ImageView) findViewById(R.id.show_image);
    38         downImage = (Button) findViewById(R.id.down_image);
    39         
    40         downImage.setOnClickListener(new OnClickListener() {
    41             
    42             @Override
    43             public void onClick(View v) {
    44                 // TODO Auto-generated method stub
    45                 //开启一个线程下载图片
    46                 new Thread(new Runnable() {
    47                     
    48                     private Bitmap bitmap;
    49 
    50                     @Override
    51                     public void run() {
    52                         // TODO Auto-generated method stub
    53                         HttpGet get = new HttpGet(path);
    54                         HttpClient client = new DefaultHttpClient();
    55                         HttpResponse response = null;
    56                         
    57                         try {
    58                             response = client.execute(get);
    59                             if(response.getStatusLine().getStatusCode()==200)
    60                             {
    61                                 //获得下载后的图片的字节数据
    62                                 byte b[] = EntityUtils.toByteArray(response.getEntity());
    63                                 bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
    64                                  //下载完成,将图片发送给主线程
    65                                 //Handler.post(Runnable r)方法
    66                                  handler.post(new Runnable() {
    67                                     
    68                                     @Override
    69                                     public void run() {
    70                                         // TODO Auto-generated method stub
    71                                         showImage.setImageBitmap(bitmap);
    72                                     }
    73                                 });
    74                             }
    75                             
    76                             
    77                         } catch (ClientProtocolException e) {
    78                             // TODO Auto-generated catch block
    79                             e.printStackTrace();
    80                         } catch (IOException e) {
    81                             // TODO Auto-generated catch block
    82                             e.printStackTrace();
    83                         }
    84                         
    85                         
    86                     }
    87                 }).start();//不要忘记开启线程
    88             }
    89         });
    90         
    91     }
    92     
    93     
    94 }
    Handler.post(Runnable r)

    最后因为下载网络图片,不要忘记在清单文件中 添加网络访问权限

        <uses-permission android:name="android.permission.INTERNET"/>

    效果图:

    下载前:

    下载后:

    2、主线程向子线程发送消息

    布局还是上面的那个,就不贴代码了

     1 package com.xqx.handle;
     2 
     3 import android.app.Activity;
     4 import android.graphics.Color;
     5 import android.os.Bundle;
     6 import android.os.Handler;
     7 import android.os.Looper;
     8 import android.os.Message;
     9 import android.view.View;
    10 import android.view.View.OnClickListener;
    11 import android.widget.Button;
    12 import android.widget.ImageView;
    13 import android.widget.Toast;
    14 
    15 public class Handler3 extends Activity{
    16     
    17     private Button changeImage;
    18     private ImageView showImage;
    19     private Handler handler;
    20     
    21     @Override
    22     protected void onCreate(Bundle savedInstanceState) {
    23         // TODO Auto-generated method stub
    24         super.onCreate(savedInstanceState);
    25         setContentView(R.layout.activity_main);
    26         
    27         changeImage = (Button) findViewById(R.id.down_image);
    28         showImage = (ImageView) findViewById(R.id.show_image);
    29         MyThread mt = new MyThread();
    30         Thread h = new Thread(mt);
    31         h.start();
    32         changeImage.setOnClickListener(new OnClickListener() {
    33             
    34             @Override
    35             public void onClick(View v) {
    36                 // TODO Auto-generated method stub
    37                 //主线程发送消息
    38                 Message msg = Message.obtain();
    39                 msg.what = 1;
    40                 handler.sendEmptyMessage(1);
    41             }
    42         });
    43         
    44     }
    45     
    46     class MyThread implements Runnable
    47     {
    48 
    49         @Override
    50         public void run() {
    51             // TODO Auto-generated method stub
    52             Looper.prepare();
    53             handler = new Handler(){
    54                 @Override
    55                 public void handleMessage(Message msg) {
    56                     // TODO Auto-generated method stub
    57                     super.handleMessage(msg);
    58                     int number = msg.what;
    59                     Toast.makeText(getApplicationContext(), "子线程接收到了主线程的消息,消息内容为:"+number, 1).show();
    60                 }
    61             };
    62             Looper.loop();
    63         }
    64         
    65     }
    66 
    67 }
    主线程项子线程发送消息

    效果图:

  • 相关阅读:
    冒泡 希尔 快速 插入 堆 基数
    排序总结
    软件工程(齐治昌-谭庆平-宁洪)
    Java简单计算器
    插入排序
    Android中theme.xml与style.xml的区别
    activity theme parent 属性浅析
    xml中不能直接添加ViewGroup
    Java中对象的上转型对象
    Android原理View、ViewGroup
  • 原文地址:https://www.cnblogs.com/xqxacm/p/4806644.html
Copyright © 2011-2022 走看看