您的位置:首页 > 其它

Handler和Message

2017-12-19 09:07 190 查看
当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响应用户并分发事件等。所以一般在主线程中不要执行比较耗时的操作,如联网下载数据等,否则出现ANR错误。所以就将这些操作放在子线程中,但是由于AndroidUI线程是不安全的,所以只能在主线程中更新UI。Handler就是用来
子线程和创建Handler的线程进行通信的。

Handler实例实现的两种方式

一部分是创建Handler实例,重载handleMessage方法,来处理消息。

1.mProgressHandler = new Handler()  
2.        {  
3.            public void handleMessage(Message msg)  
4.            {  
5.                super.handleMessage(msg);  
6.            }  
7.        };  

 当然,也可继承自Handler,同样要实现handleMessage(Message msg)

1.class MyHandler extends Handler {  
2.        public MyHandler() {  
3.        }  
4.  
5.        // 子类必须重写此方法,接受数据  
6.        @Override  
7.        public void handleMessage(Message msg) {  
8.            // TODO Auto-generated method stub  
9.            Log.d("MyHandler", "handleMessage......");  
10.            super.handleMessage(msg);  
11.  
12.        }  
    } 


另一部分是分发Message或者Runable对象到Handler所在的线程中,一般Handler在主线程中。
          Handler中分发消息的一些方法post(Runnable)

          postAtTime(Runnable,long)

第二个参数表示一个精确的时间的毫秒数,如果从当前时间算起,需要使用android.os.SystemClock.uptimeMillis()获得基准时间。

          postDelayed(Runnable,long)
          sendEmptyMessage(int what)
          sendMessage(Message)
          sendMessageAtTime(Message,long)
          sendMessageDelayed(Message,long)

             handler本身不仅可以发送消息,还可以用post的方式添加一个实现Runnable接口的匿名对象到消息队列中,在目标收到消息后就可以回调的方式在自己的线程中执行run的方法体。

sendMessage与sendEmptyMessage的异同

public final boolean sendEmptyMessage(int what)
{
   return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}




Message

定义一个包含任意类型的描述数据对象,此对象可以发送给Handler。对象包含两个额外的int字段和一个额外的对象字段,这样可以使得在很多情况下不用做分配工作。

尽管Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。

1.Message message = Message.obtain();  
2.message.arg1 = 1;  
3.message.arg2 = 2;  
4.message.obj = "Demo"; 
5.message.what = 3; 
6.Bundle bundleData = new Bundle();  
7.bundleData.putString("Name", "Lucy");  
message.setData(bundleData); 


Message
可以传递的参数有:

1. arg1 arg2
整数类型,是setData的低成本替代品。传递简单类型

2. Object
类型 obj,发送给接收器的任意对象。当使用Message对象在线程间传递消息时,如果它包含一个Parcelable的结构类(不是由应用程序实现的类),此字段必须为非空(non-null)。其他的数据传输则使用setData(Bundle)方法。

注意Parcelable对象是从FROYO版本以后才开始支持的。

3. what  用户自定义的消息代码,这样接受者可以了解这个消息的信息。每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突。

4.其他的可以通过Bundle进行传递

     Message可以通过new Message构造来创建一个新的Message,但是这种方式很不好,不建议使用。最好使用Message.obtain()来获取Message实例,它创建了消息池来处理的。

5.public Messenger replyTo

指明此message发送到何处的可选Messenger对象。具体的使用方法由发送者和接受者决定

Message一些方法介绍

公共构造器       public
     Message()       
  构造器(但是获取Message对象的最好方法是调用Message.obtain())。
公共方法
public void copyFrom (Message
o)
使此message跟参数o相似。浅拷贝数据域。不拷贝源message的链表字段,时间戳和目标/回调。
 
public int describeContents ()
描述了包含在Parcelable对象排列信息中的特殊对象的类型。

返回值

         一个标志位,表明Parcelable对象特殊对象类型集合的排列。

 
public Runnable getCallback ()
获取回调对象,此对象会在message处理时执行。此对象必须实现Runnable接口。回调由接收此消息并分发的目标handler调用。如果没有设置回调,此消息会分发到接收handler的handleMessage(Message)。
 
public Bundle getData ()
获取附加在此事件上的任意数据的Bundle对象,需要时延迟创建。通过调用setData(Bundle)来设置Bundle的值。需要注意的是,如果通过Messenger对象在进程间传递数据时,需要调用Bundle类的Bundle.setClassLoader()方法来设置ClassLoader,这样当接收到消息时可以实例化Bundle里的对象。
 public
Bundle peekData ()
与getData()相似,但是并不延迟创建Bundle。如果Bundle对象不存在返回null。
public void setData (Bundle
data)

设置一个任意数据值的Bundle对象。如果可以,使用arg1和arg2域发送一些整型值以减少消耗。 
  
public Handler getTarget ()
获取将接收此消息的Handler对象。此对象必须要实现Handler.handleMessage()方法。每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突。 
public long getWhen ()
返回此消息的传输时间,以毫秒为单位。
 
 
如下这些通过Message.obtain方式获取Message实例,参数中传递了Handler,发送该消息时不再使用handler.sendMessage这种方式。使用message.sendToTarget();不过归根到底都是调用Handler.sendMessage进行发送消息。Message类中保存Handler实例。
public static Message obtain (Handler
h, int what, int arg1, int arg2, Object obj)
与obtain()一样,但是设置了target,
what, arg1, arg2和obj的值。
         参数
                   h                设置的target值
                   what         设置的what值
                   arg1          设置的arg1值
                   arg2          设置的arg2值
                   obj             设置的obj值
         返回值
                   从全局池中分配的一个Message对象。
 
public static Message obtain (Handler
h, int what, Object obj)
public static Message obtain (Handler
h, int what)
public static Message obtain (Handler
h)
public static Message obtain (Handler
h, Runnable callback)
与obtain(Handler)一样,但是设置回调函数,在Message返回时调用。
public static Message obtain ()
从全局池中返回一个新的Message实例。在大多数情况下这样可以避免分配新的对象。
public static Message obtain (Handler
h, int what, int arg1, int arg2) 
public static Message obtain (Message
obj)
同obtain(),但是从一个已存在的消息中拷贝值(包括它的目标)。
         参数
                   orig           要拷贝的源消息
         返回值
                   从全局池中分配的一个Message对象。
 
public void recyle ()
向全局池中返回一个Message实例。一定不能在调用此函数后再使用Message——它会立即被释放。
 
public void sendToTarget ()
向Handler发送此消息,getTarget()方法可以获取此Handler。如果这个字段没有设置会抛出个空指针异常。
public void setTarget (Handler
target)
设置将接收此消息的Handler对象。
 
public String toString ()
返回一个Message对象简单的,可读懂的描述信息。鼓励子类重写此方法,实现时最好把对象的类型的数据考虑进去。默认的实现等同与以下表达式:
      
如果需要实现toString方法,参考Writing
a useful toString method。
                   返回值
                            一个代表此对象的可打印字符串
 
public void writeToParcel (Parcel
dest, int flags)
将类的数据写入外部提供的Parcel中

参数
                            dest   对象被写入的Parcel
                            flags 对象如何被写入的附加标志,可能是0或PARCELABLE_WRITE_RETURN_VALUE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息