Android Handler

 

  • Message Class
  •   1 package android.os;
      2 import android.os.Bundle;
      3 import android.os.Parcel;
      4 import android.os.Parcelable;
      5 import android.util.TimeUtils;
      6 public final class Message implements Parcelable {
      7     public int what;
      8     public int arg1; 
      9     public int arg2;
     10     public Object obj;
     11     public Messenger replyTo;
     12     /** If set message is in use */
     13     /*package access*/ static final int FLAG_IN_USE = 1;
     14     /** Flags reserved for future use (All are reserved for now) */
     15     /*package access*/ static final int FLAGS_RESERVED = ~FLAG_IN_USE;
     16     /** Flags to clear in the copyFrom method */
     17     /*package access*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAGS_RESERVED | FLAG_IN_USE;
     18     /*package access*/ int flags;
     19     /*package access*/ long when;    
     20     /*package access*/ Bundle data;    
     21     /*package access*/ Handler target;  
     22     /*package access*/ Runnable callback;  
     23     // sometimes we store linked lists of these things
     24     /*package access*/ Message next;
     25     private static final Object sPoolSync = new Object();
     26     private static Message sPool;
     27     private static int sPoolSize = 0;
     28     private static final int MAX_POOL_SIZE = 10;
     29     
     30     public static Message obtain() {
     31         synchronized (sPoolSync) {
     32             if (sPool != null) {
     33                 Message m = sPool;
     34                 sPool = m.next;
     35                 m.next = null;
     36                 sPoolSize--;
     37                 return m;
     38             }
     39         }
     40         return new Message();
     41     }
     42     public static Message obtain(Message orig) {
     43         Message m = obtain();
     44         m.what = orig.what;
     45         m.arg1 = orig.arg1;
     46         m.arg2 = orig.arg2;
     47         m.obj = orig.obj;
     48         m.replyTo = orig.replyTo;
     49         if (orig.data != null) {
     50             m.data = new Bundle(orig.data);
     51         }
     52         m.target = orig.target;
     53         m.callback = orig.callback;
     54 
     55         return m;
     56     }
     57     public static Message obtain(Handler h) {
     58         Message m = obtain();
     59         m.target = h;
     60 
     61         return m;
     62     }
     63     public static Message obtain(Handler h, Runnable callback) {
     64         Message m = obtain();
     65         m.target = h;
     66         m.callback = callback;
     67 
     68         return m;
     69     }
     70     public static Message obtain(Handler h, int what) {
     71         Message m = obtain();
     72         m.target = h;
     73         m.what = what;
     74 
     75         return m;
     76     }
     77     public static Message obtain(Handler h, int what, Object obj) {
     78         Message m = obtain();
     79         m.target = h;
     80         m.what = what;
     81         m.obj = obj;
     82 
     83         return m;
     84     }
     85     public static Message obtain(Handler h, int what, int arg1, int arg2) {
     86         Message m = obtain();
     87         m.target = h;
     88         m.what = what;
     89         m.arg1 = arg1;
     90         m.arg2 = arg2;
     91         return m;
     92     }
     93     public static Message obtain(Handler h, int what, 
     94             int arg1, int arg2, Object obj) {
     95         Message m = obtain();
     96         m.target = h;
     97         m.what = what;
     98         m.arg1 = arg1;
     99         m.arg2 = arg2;
    100         m.obj = obj;
    101         return m;
    102     }
    103     public void recycle() {
    104         clearForRecycle();
    105 
    106         synchronized (sPoolSync) {
    107             if (sPoolSize < MAX_POOL_SIZE) {
    108                 next = sPool;
    109                 sPool = this;
    110                 sPoolSize++;
    111             }
    112         }
    113     }
    114     public void copyFrom(Message o) {
    115         this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
    116         this.what = o.what;
    117         this.arg1 = o.arg1;
    118         this.arg2 = o.arg2;
    119         this.obj = o.obj;
    120         this.replyTo = o.replyTo;
    121 
    122         if (o.data != null) {
    123             this.data = (Bundle) o.data.clone();
    124         } else {
    125             this.data = null;
    126         }
    127     }
    128     public long getWhen() {
    129         return when;
    130     }
    131     
    132     public void setTarget(Handler target) {
    133         this.target = target;
    134     }
    135     public Handler getTarget() {
    136         return target;
    137     }
    138     public Runnable getCallback() {
    139         return callback;
    140     }
    141     public Bundle getData() {
    142         if (data == null) {
    143             data = new Bundle();
    144         }
    145         
    146         return data;
    147     }
    148     public Bundle peekData() {
    149         return data;
    150     }
    151     public void setData(Bundle data) {
    152         this.data = data;
    153     }
    154     public void sendToTarget() {
    155         target.sendMessage(this);
    156     }
    157     /*package access*/ void clearForRecycle() {
    158         flags = 0;
    159         what = 0;
    160         arg1 = 0;
    161         arg2 = 0;
    162         obj = null;
    163         replyTo = null;
    164         when = 0;
    165         target = null;
    166         callback = null;
    167         data = null;
    168     }
    169 
    170     /*package access*/ boolean isInUse() {
    171         return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    172     }
    173     /*package access access*/ void markInUse() {
    174         flags |= FLAG_IN_USE;
    175     }
    176     public Message() {
    177     }
    178     public String toString() {
    179         return toString(SystemClock.uptimeMillis());
    180     }
    181 
    182     String toString(long now) {
    183         StringBuilder   b = new StringBuilder();
    184         
    185         b.append("{ what=");
    186         b.append(what);
    187 
    188         b.append(" when=");
    189         TimeUtils.formatDuration(when-now, b);
    190 
    191         if (arg1 != 0) {
    192             b.append(" arg1=");
    193             b.append(arg1);
    194         }
    195 
    196         if (arg2 != 0) {
    197             b.append(" arg2=");
    198             b.append(arg2);
    199         }
    200 
    201         if (obj != null) {
    202             b.append(" obj=");
    203             b.append(obj);
    204         }
    205 
    206         b.append(" }");
    207         
    208         return b.toString();
    209     }
    210 
    211     public static final Parcelable.Creator<Message> CREATOR
    212             = new Parcelable.Creator<Message>() {
    213         public Message createFromParcel(Parcel source) {
    214             Message msg = Message.obtain();
    215             msg.readFromParcel(source);
    216             return msg;
    217         }
    218         
    219         public Message[] newArray(int size) {
    220             return new Message[size];
    221         }
    222     };
    223         
    224     public int describeContents() {
    225         return 0;
    226     }
    227 
    228     public void writeToParcel(Parcel dest, int flags) {
    229         if (callback != null) {
    230             throw new RuntimeException(
    231                 "Can't marshal callbacks across processes.");
    232         }
    233         dest.writeInt(what);
    234         dest.writeInt(arg1);
    235         dest.writeInt(arg2);
    236         if (obj != null) {
    237             try {
    238                 Parcelable p = (Parcelable)obj;
    239                 dest.writeInt(1);
    240                 dest.writeParcelable(p, flags);
    241             } catch (ClassCastException e) {
    242                 throw new RuntimeException(
    243                     "Can't marshal non-Parcelable objects across processes.");
    244             }
    245         } else {
    246             dest.writeInt(0);
    247         }
    248         dest.writeLong(when);
    249         dest.writeBundle(data);
    250         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
    251     }
    252 
    253     private final void readFromParcel(Parcel source) {
    254         what = source.readInt();
    255         arg1 = source.readInt();
    256         arg2 = source.readInt();
    257         if (source.readInt() != 0) {
    258             obj = source.readParcelable(getClass().getClassLoader());
    259         }
    260         when = source.readLong();
    261         data = source.readBundle();
    262         replyTo = Messenger.readMessengerOrNullFromParcel(source);
    263     }
    264 }
    Message

    Variables in Message

  •  1    public int what;
     2     public int arg1; 
     3     public int arg2;
     4     public Object obj;
     5     public Messenger replyTo;
     6     /** If set message is in use */
     7     /*package access*/ static final int FLAG_IN_USE = 1;
     8     /** Flags reserved for future use (All are reserved for now) */
     9     /*package access*/ static final int FLAGS_RESERVED = ~FLAG_IN_USE;
    10     /** Flags to clear in the copyFrom method */
    11     /*package access*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAGS_RESERVED | FLAG_IN_USE;
    12     /*package access*/ int flags;
    13     /*package access*/ long when;    
    14     /*package access*/ Bundle data;    //pass much more data
    15     /*package access*/ Handler target; //message's handler
    16     /*package access*/ Runnable callback; //customized message handler,not be handled by message target
    17     // sometimes we store linked lists of these things
    18     /*package access*/ Message next;
    19     private static final Object sPoolSync = new Object();
    20     private static Message sPool;

     Constructor methods to new a message

  •  1 public static Message obtain() {
     2         synchronized (sPoolSync) {
     3             if (sPool != null) {
     4                 Message m = sPool;
     5                 sPool = m.next;
     6                 m.next = null;
     7                 sPoolSize--;
     8                 return m;
     9             }
    10         }
    11return new Message();
    12 }
  •  1 public static Message obtain(Message orig) {
     2         Message m = obtain();
     3         m.what = orig.what;
     4         m.arg1 = orig.arg1;
     5         m.arg2 = orig.arg2;
     6         m.obj = orig.obj;
     7         m.replyTo = orig.replyTo;
     8         if (orig.data != null) {
     9             m.data = new Bundle(orig.data);
    10         }
    11         m.target = orig.target;
    12         m.callback = orig.callback;
    13         return m;
    14     }
    15 public static Message obtain(Handler h) {
    16         Message m = obtain();
    17         m.target = h;
    18         return m;
    19     }
    20 public static Message obtain(Handler h, Runnable callback) {
    21         Message m = obtain();
    22         m.target = h;
    23         m.callback = callback;
    24         return m;
    25     }
    26 ... ...........

    Implementation of Parcelable

  •  1 public static final Parcelable.Creator<Message> CREATOR
     2             = new Parcelable.Creator<Message>() {
     3         public Message createFromParcel(Parcel source) {
     4             Message msg = Message.obtain();
     5             msg.readFromParcel(source);
     6             return msg;
     7         }        
     8         public Message[] newArray(int size) {
     9             return new Message[size];
    10         }
    11     };        
    12     public int describeContents() {
    13         return 0;
    14     }
    15     public void writeToParcel(Parcel dest, int flags) {
    16         if (callback != null) {
    17             throw new RuntimeException(
    18                 "Can't marshal callbacks across processes.");
    19         }
    20         dest.writeInt(what);
    21         dest.writeInt(arg1);
    22         dest.writeInt(arg2);
    23         if (obj != null) {
    24             try {
    25                 Parcelable p = (Parcelable)obj;
    26                 dest.writeInt(1);
    27                 dest.writeParcelable(p, flags);
    28             } catch (ClassCastException e) {
    29                 throw new RuntimeException(
    30                     "Can't marshal non-Parcelable objects across processes.");
    31             }
    32         } else {
    33             dest.writeInt(0);
    34         }
    35         dest.writeLong(when);
    36         dest.writeBundle(data);
    37         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
    38     }
    39     private final void readFromParcel(Parcel source) {
    40         what = source.readInt();
    41         arg1 = source.readInt();
    42         arg2 = source.readInt();
    43         if (source.readInt() != 0) {
    44             obj = source.readParcelable(getClass().getClassLoader());
    45         }
    46         when = source.readLong();
    47         data = source.readBundle();
    48         replyTo = Messenger.readMessengerOrNullFromParcel(source);
    49     }
    Parcelable
  • MessageQueue

  •   1 package android.os;
      2 import android.util.AndroidRuntimeException;
      3 import android.util.Log;
      4 import java.util.ArrayList;
      5 public class MessageQueue {
      6     Message mMessages;
      7     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
      8     private IdleHandler[] mPendingIdleHandlers;
      9     private boolean mQuiting;
     10     boolean mQuitAllowed = true;
     11     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
     12     private boolean mBlocked;
     13     @SuppressWarnings("unused")
     14     private int mPtr; // used by native code    
     15     private native void nativeInit();
     16     private native void nativeDestroy();
     17     private native void nativePollOnce(int ptr, int timeoutMillis);
     18     private native void nativeWake(int ptr);
     19     public static interface IdleHandler {
     20         boolean queueIdle();
     21     }
     22     public final void addIdleHandler(IdleHandler handler) {
     23         if (handler == null) {
     24             throw new NullPointerException("Can't add a null IdleHandler");
     25         }
     26         synchronized (this) {
     27             mIdleHandlers.add(handler);
     28         }
     29     }
     30     public final void removeIdleHandler(IdleHandler handler) {
     31         synchronized (this) {
     32             mIdleHandlers.remove(handler);
     33         }
     34     }    
     35     MessageQueue() {
     36         nativeInit();
     37     }
     38     
     39     @Override
     40     protected void finalize() throws Throwable {
     41         try {
     42             nativeDestroy();
     43         } finally {
     44             super.finalize();
     45         }
     46     }
     47     final Message next() {
     48         int pendingIdleHandlerCount = -1; // -1 only during first iteration
     49         int nextPollTimeoutMillis = 0;
     50 
     51         for (;;) {
     52             if (nextPollTimeoutMillis != 0) {
     53                 Binder.flushPendingCommands();
     54             }
     55             nativePollOnce(mPtr, nextPollTimeoutMillis);
     56             synchronized (this) {
     57                 // Try to retrieve the next message.  Return if found.
     58                 final long now = SystemClock.uptimeMillis();
     59                 final Message msg = mMessages;
     60                 if (msg != null) {
     61                     final long when = msg.when;
     62                     if (now >= when) {
     63                         mBlocked = false;
     64                         mMessages = msg.next;
     65                         msg.next = null;
     66                         if (false) Log.v("MessageQueue", "Returning message: " + msg);
     67                         msg.markInUse();
     68                         return msg;
     69                     } else {
     70                         nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
     71                     }
     72                 } else {
     73                     nextPollTimeoutMillis = -1;
     74                 }
     75 
     76                 // If first time, then get the number of idlers to run.
     77                 if (pendingIdleHandlerCount < 0) {
     78                     pendingIdleHandlerCount = mIdleHandlers.size();
     79                 }
     80                 if (pendingIdleHandlerCount == 0) {
     81                     // No idle handlers to run.  Loop and wait some more.
     82                     mBlocked = true;
     83                     continue;
     84                 }
     85 
     86                 if (mPendingIdleHandlers == null) {
     87                     mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
     88                 }
     89                 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
     90             }
     91 
     92             // Run the idle handlers.
     93             // We only ever reach this code block during the first iteration.
     94             for (int i = 0; i < pendingIdleHandlerCount; i++) {
     95                 final IdleHandler idler = mPendingIdleHandlers[i];
     96                 mPendingIdleHandlers[i] = null; // release the reference to the handler
     97 
     98                 boolean keep = false;
     99                 try {
    100                     keep = idler.queueIdle();
    101                 } catch (Throwable t) {
    102                     Log.wtf("MessageQueue", "IdleHandler threw exception", t);
    103                 }
    104 
    105                 if (!keep) {
    106                     synchronized (this) {
    107                         mIdleHandlers.remove(idler);
    108                     }
    109                 }
    110             }
    111 
    112             // Reset the idle handler count to 0 so we do not run them again.
    113             pendingIdleHandlerCount = 0;
    114 
    115             // While calling an idle handler, a new message could have been delivered
    116             // so go back and look again for a pending message without waiting.
    117             nextPollTimeoutMillis = 0;
    118         }
    119     }
    120     final boolean enqueueMessage(Message msg, long when) {
    121         if (msg.isInUse()) {
    122             throw new AndroidRuntimeException(msg
    123                     + " This message is already in use.");
    124         }
    125         if (msg.target == null && !mQuitAllowed) {
    126             throw new RuntimeException("Main thread not allowed to quit");
    127         }
    128         final boolean needWake;
    129         synchronized (this) {
    130             if (mQuiting) {
    131                 RuntimeException e = new RuntimeException(
    132                     msg.target + " sending message to a Handler on a dead thread");
    133                 Log.w("MessageQueue", e.getMessage(), e);
    134                 return false;
    135             } else if (msg.target == null) {
    136                 mQuiting = true;
    137             }
    138             msg.when = when;
    139             //Log.d("MessageQueue", "Enqueing: " + msg);
    140             Message p = mMessages;
    141             if (p == null || when == 0 || when < p.when) {
    142                 msg.next = p;
    143                 mMessages = msg;
    144                 needWake = mBlocked; // new head, might need to wake up
    145             } else {
    146                 Message prev = null;
    147                 while (p != null && p.when <= when) {
    148                     prev = p;
    149                     p = p.next;
    150                 }
    151                 msg.next = prev.next;
    152                 prev.next = msg;
    153                 needWake = false; // still waiting on head, no need to wake up
    154             }
    155         }
    156         if (needWake) {
    157             nativeWake(mPtr);
    158         }
    159         return true;
    160     }
    161     final boolean removeMessages(Handler h, int what, Object object,
    162             boolean doRemove) {
    163         synchronized (this) {
    164             Message p = mMessages;
    165             boolean found = false;
    166 
    167             // Remove all messages at front.
    168             while (p != null && p.target == h && p.what == what
    169                    && (object == null || p.obj == object)) {
    170                 if (!doRemove) return true;
    171                 found = true;
    172                 Message n = p.next;
    173                 mMessages = n;
    174                 p.recycle();
    175                 p = n;
    176             }
    177 
    178             // Remove all messages after front.
    179             while (p != null) {
    180                 Message n = p.next;
    181                 if (n != null) {
    182                     if (n.target == h && n.what == what
    183                         && (object == null || n.obj == object)) {
    184                         if (!doRemove) return true;
    185                         found = true;
    186                         Message nn = n.next;
    187                         n.recycle();
    188                         p.next = nn;
    189                         continue;
    190                     }
    191                 }
    192                 p = n;
    193             }
    194             
    195             return found;
    196         }
    197     }
    198     final void removeMessages(Handler h, Runnable r, Object object) {
    199         if (r == null) {
    200             return;
    201         }
    202 
    203         synchronized (this) {
    204             Message p = mMessages;
    205 
    206             // Remove all messages at front.
    207             while (p != null && p.target == h && p.callback == r
    208                    && (object == null || p.obj == object)) {
    209                 Message n = p.next;
    210                 mMessages = n;
    211                 p.recycle();
    212                 p = n;
    213             }
    214 
    215             // Remove all messages after front.
    216             while (p != null) {
    217                 Message n = p.next;
    218                 if (n != null) {
    219                     if (n.target == h && n.callback == r
    220                         && (object == null || n.obj == object)) {
    221                         Message nn = n.next;
    222                         n.recycle();
    223                         p.next = nn;
    224                         continue;
    225                     }
    226                 }
    227                 p = n;
    228             }
    229         }
    230     }
    231     final void removeCallbacksAndMessages(Handler h, Object object) {
    232         synchronized (this) {
    233             Message p = mMessages;
    234 
    235             // Remove all messages at front.
    236             while (p != null && p.target == h
    237                     && (object == null || p.obj == object)) {
    238                 Message n = p.next;
    239                 mMessages = n;
    240                 p.recycle();
    241                 p = n;
    242             }
    243 
    244             // Remove all messages after front.
    245             while (p != null) {
    246                 Message n = p.next;
    247                 if (n != null) {
    248                     if (n.target == h && (object == null || n.obj == object)) {
    249                         Message nn = n.next;
    250                         n.recycle();
    251                         p.next = nn;
    252                         continue;
    253                     }
    254                 }
    255                 p = n;
    256             }
    257         }
    258     }
    259 }
    MessageQueue

    Variables in messagequeue

  • 1 /*package access*/
    2 Message mMessages;
    3 private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    4     private IdleHandler[] mPendingIdleHandlers;
    5     private boolean mQuiting;
    6     boolean mQuitAllowed = true;
    7     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    8     private boolean mBlocked;

    Package Access Methods in MessageQueue

  • final boolean removeMessages(Handler h, int what, Object object, boolean doRemove)
    {....... }
    final void removeMessages(Handler h, Runnable r, Object object)
    {.............}
    final void removeCallbacksAndMessages(Handler h, Object object)
    {............}
    final Message next()
    {............}
    
     final boolean enqueueMessage(Message msg, long when) {
            if (msg.isInUse()) {
                throw new AndroidRuntimeException(msg
                        + " This message is already in use.");
            }
            if (msg.target == null && !mQuitAllowed) {
                throw new RuntimeException("Main thread not allowed to quit");
            }
            final boolean needWake;
            synchronized (this) {
                if (mQuiting) {
                    RuntimeException e = new RuntimeException(
                        msg.target + " sending message to a Handler on a dead thread");
                    Log.w("MessageQueue", e.getMessage(), e);
                    return false;
                } else if (msg.target == null) {
                    mQuiting = true;
                }
                msg.when = when;
                //Log.d("MessageQueue", "Enqueing: " + msg);
                Message p = mMessages;
                if (p == null || when == 0 || when < p.when) {
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked; // new head, might need to wake up
                } else {
                    Message prev = null;
                    while (p != null && p.when <= when) {
                        prev = p;
                        p = p.next;
                    }
                    msg.next = prev.next;
                    prev.next = msg;
                    needWake = false; // still waiting on head, no need to wake up
                }
            }
            if (needWake) {
                nativeWake(mPtr);
            }
            return true;
        }
  • Handler Class
  •   1 package android.os;
      2 import android.util.Log;
      3 import android.util.Printer;
      4 import java.lang.reflect.Modifier;
      5 public class Handler {
      6     final MessageQueue mQueue;
      7     final Looper mLooper;
      8     final Callback mCallback;
      9     IMessenger mMessenger;
     10     private static final boolean FIND_POTENTIAL_LEAKS = false;
     11     private static final String TAG = "Handler";
     12     public interface Callback {
     13         public boolean handleMessage(Message msg);
     14     }
     15     
     16     /**
     17      * Subclasses must implement this to receive messages.
     18      */
     19     public void handleMessage(Message msg) {
     20     }
     21     
     22     /**
     23      * Handle system messages here.
     24      */
     25     public void dispatchMessage(Message msg) {
     26         if (msg.callback != null) {
     27             handleCallback(msg);
     28         } else {
     29             if (mCallback != null) {
     30                 if (mCallback.handleMessage(msg)) {
     31                     return;
     32                 }
     33             }
     34             handleMessage(msg);
     35         }
     36     }
     37     public Handler() {
     38         if (FIND_POTENTIAL_LEAKS) {
     39             final Class<? extends Handler> klass = getClass();
     40             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
     41                     (klass.getModifiers() & Modifier.STATIC) == 0) {
     42                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
     43                     klass.getCanonicalName());
     44             }
     45         }
     46 
     47         mLooper = Looper.myLooper();
     48         if (mLooper == null) {
     49             throw new RuntimeException(
     50                 "Can't create handler inside thread that has not called Looper.prepare()");
     51         }
     52         mQueue = mLooper.mQueue;
     53         mCallback = null;
     54     }
     55     public Handler(Callback callback) {
     56         if (FIND_POTENTIAL_LEAKS) {
     57             final Class<? extends Handler> klass = getClass();
     58             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
     59                     (klass.getModifiers() & Modifier.STATIC) == 0) {
     60                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
     61                     klass.getCanonicalName());
     62             }
     63         }
     64 
     65         mLooper = Looper.myLooper();
     66         if (mLooper == null) {
     67             throw new RuntimeException(
     68                 "Can't create handler inside thread that has not called Looper.prepare()");
     69         }
     70         mQueue = mLooper.mQueue;
     71         mCallback = callback;
     72     }
     73     public Handler(Looper looper) {
     74         mLooper = looper;
     75         mQueue = looper.mQueue;
     76         mCallback = null;
     77     }
     78     public Handler(Looper looper, Callback callback) {
     79         mLooper = looper;
     80         mQueue = looper.mQueue;
     81         mCallback = callback;
     82     }
     83     public String getMessageName(Message message) {
     84         if (message.callback != null) {
     85             return message.callback.getClass().getName();
     86         }
     87         return "0x" + Integer.toHexString(message.what);
     88     }
     89     public final Message obtainMessage()
     90     {
     91         return Message.obtain(this);
     92     }
     93     public final Message obtainMessage(int what)
     94     {
     95         return Message.obtain(this, what);
     96     }
     97     public final Message obtainMessage(int what, Object obj)
     98     {
     99         return Message.obtain(this, what, obj);
    100     }
    101     public final Message obtainMessage(int what, int arg1, int arg2)
    102     {
    103         return Message.obtain(this, what, arg1, arg2);
    104     }
    105     public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    106     {
    107         return Message.obtain(this, what, arg1, arg2, obj);
    108     }
    109     public final boolean post(Runnable r)
    110     {
    111        return  sendMessageDelayed(getPostMessage(r), 0);
    112     }
    113     public final boolean postAtTime(Runnable r, long uptimeMillis)
    114     {
    115         return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    116     }
    117     public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    118     {
    119         return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    120     }
    121     public final boolean postDelayed(Runnable r, long delayMillis)
    122     {
    123         return sendMessageDelayed(getPostMessage(r), delayMillis);
    124     }
    125     public final boolean postAtFrontOfQueue(Runnable r)
    126     {
    127         return sendMessageAtFrontOfQueue(getPostMessage(r));
    128     }
    129     public final void removeCallbacks(Runnable r)
    130     {
    131         mQueue.removeMessages(this, r, null);
    132     }
    133     public final void removeCallbacks(Runnable r, Object token)
    134     {
    135         mQueue.removeMessages(this, r, token);
    136     }
    137     public final boolean sendMessage(Message msg)
    138     {
    139         return sendMessageDelayed(msg, 0);
    140     }
    141     public final boolean sendEmptyMessage(int what)
    142     {
    143         return sendEmptyMessageDelayed(what, 0);
    144     }
    145     public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    146         Message msg = Message.obtain();
    147         msg.what = what;
    148         return sendMessageDelayed(msg, delayMillis);
    149     }
    150 
    151     /**
    152      * Sends a Message containing only the what value, to be delivered 
    153      * at a specific time.
    154      * @see #sendMessageAtTime(android.os.Message, long)
    155      *  
    156      * @return Returns true if the message was successfully placed in to the 
    157      *         message queue.  Returns false on failure, usually because the
    158      *         looper processing the message queue is exiting.
    159      */
    160     public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    161         Message msg = Message.obtain();
    162         msg.what = what;
    163         return sendMessageAtTime(msg, uptimeMillis);
    164     }
    165     public final boolean sendMessageDelayed(Message msg, long delayMillis)
    166     {
    167         if (delayMillis < 0) {
    168             delayMillis = 0;
    169         }
    170         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    171     }
    172     public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    173     {
    174         boolean sent = false;
    175         MessageQueue queue = mQueue;
    176         if (queue != null) {
    177             msg.target = this;
    178             sent = queue.enqueueMessage(msg, uptimeMillis);
    179         }
    180         else {
    181             RuntimeException e = new RuntimeException(
    182                 this + " sendMessageAtTime() called with no mQueue");
    183             Log.w("Looper", e.getMessage(), e);
    184         }
    185         return sent;
    186     }
    187     public final boolean sendMessageAtFrontOfQueue(Message msg)
    188     {
    189         boolean sent = false;
    190         MessageQueue queue = mQueue;
    191         if (queue != null) {
    192             msg.target = this;
    193             sent = queue.enqueueMessage(msg, 0);
    194         }
    195         else {
    196             RuntimeException e = new RuntimeException(
    197                 this + " sendMessageAtTime() called with no mQueue");
    198             Log.w("Looper", e.getMessage(), e);
    199         }
    200         return sent;
    201     }
    202     public final void removeMessages(int what) {
    203         mQueue.removeMessages(this, what, null, true);
    204     }
    205     public final void removeMessages(int what, Object object) {
    206         mQueue.removeMessages(this, what, object, true);
    207     }
    208     public final void removeCallbacksAndMessages(Object token) {
    209         mQueue.removeCallbacksAndMessages(this, token);
    210     }
    211     public final boolean hasMessages(int what) {
    212         return mQueue.removeMessages(this, what, null, false);
    213     }
    214     public final boolean hasMessages(int what, Object object) {
    215         return mQueue.removeMessages(this, what, object, false);
    216     }
    217     public final Looper getLooper() {
    218         return mLooper;
    219     }
    220     public final void dump(Printer pw, String prefix) {
    221         pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
    222         if (mLooper == null) {
    223             pw.println(prefix + "looper uninitialized");
    224         } else {
    225             mLooper.dump(pw, prefix + "  ");
    226         }
    227     }
    228     @Override
    229     public String toString() {
    230         return "Handler (" + getClass().getName() + ") {"
    231         + Integer.toHexString(System.identityHashCode(this))
    232         + "}";
    233     }
    234     
    235     final IMessenger getIMessenger() {
    236         synchronized (mQueue) {
    237             if (mMessenger != null) {
    238                 return mMessenger;
    239             }
    240             mMessenger = new MessengerImpl();
    241             return mMessenger;
    242         }
    243     }
    244     private final class MessengerImpl extends IMessenger.Stub {
    245         public void send(Message msg) {
    246             Handler.this.sendMessage(msg);
    247         }
    248     }
    249 
    250     private final Message getPostMessage(Runnable r) {
    251         Message m = Message.obtain();
    252         m.callback = r;
    253         return m;
    254     }
    255 
    256     private final Message getPostMessage(Runnable r, Object token) {
    257         Message m = Message.obtain();
    258         m.obj = token;
    259         m.callback = r;
    260         return m;
    261     }
    262 
    263     private final void handleCallback(Message message) {
    264         message.callback.run();
    265     }
    266 }
    Handler

    Variables in Handler

  • 1 final MessageQueue mQueue;
    2 final Looper mLooper;
    3 final Callback mCallback;
    4 IMessenger mMessenger;

        Callback Interface in Handler

  • 1 public interface Callback {
    2         public boolean handleMessage(Message msg);
    3  }

    Must be overridden message handler

  • 1 /*Subclasses must implement this to receive messages.*/
    2 public void handleMessage(Message msg) {
    3 }

    Constructors in Handler

  •  1 public Handler() {
     2     if (FIND_POTENTIAL_LEAKS) {
     3     final Class<? extends Handler> klass = getClass();//public final native Class<?> getClass(); defined in Object
     4         if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
     5                     (klass.getModifiers() & Modifier.STATIC) == 0) {
     6                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
     7                     klass.getCanonicalName());
     8             }
     9        }
    10 11 mLooper = Looper.myLooper();//get current thread's looper 12 if (mLooper == null) { 13 throw new RuntimeException( 14 "Can't create handler inside thread that has not called Looper.prepare()"); 15 } 16 mQueue = mLooper.mQueue;//get current thread's message queue 17 mCallback = null;//no customized callback, use handleMessage() implemented in subclass. 18 } 19 public Handler(Callback callback) { 20 if (FIND_POTENTIAL_LEAKS) { 21 final Class<? extends Handler> klass = getClass(); 22 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 23 (klass.getModifiers() & Modifier.STATIC) == 0) { 24 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 25 klass.getCanonicalName()); 26 } 27 } 28 29 mLooper = Looper.myLooper(); 30 if (mLooper == null) { 31 throw new RuntimeException( 32 "Can't create handler inside thread that has not called Looper.prepare()"); 33 } 34 mQueue = mLooper.mQueue; 35 mCallback = callback;//user customized callback to handle message 36} 37 public Handler(Looper looper) { 38 mLooper = looper; 39 mQueue = looper.mQueue; 40 mCallback = null; 41 } 42 public Handler(Looper looper, Callback callback) { 43 mLooper = looper; 44 mQueue = looper.mQueue; 45 mCallback = callback; 46 }

     Dispatch Message

  •  1 public void dispatchMessage(Message msg) {
     2         if (msg.callback != null) {
     3             handleCallback(msg); // == msg.callback.run();
     4         } else {
     5             if (mCallback != null) {
     6                 if (mCallback.handleMessage(msg)) { //user customized callback to handle message
     7                     return;
     8                 }
     9             }
    10             handleMessage(msg);//implemented in subclass
    11         }
    12  }

    Create new a message by handler

  • 1 public final Message obtainMessage()
    2 {
    3         return Message.obtain(this);//Call static method of message
    4 }

    Send message

  •  1 public final boolean post(Runnable r)
     2 {
     3        return  sendMessageDelayed(getPostMessage(r), 0);
     4 }
     5 public final boolean sendMessage(Message msg)
     6 {
     7         return sendMessageDelayed(msg, 0);
     8 }
     9 public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    10     {
    11         boolean sent = false;
    12         MessageQueue queue = mQueue;
    13         if (queue != null) {
    14             msg.target = this;//always set as sender
    15             sent = queue.enqueueMessage(msg, uptimeMillis);
    16         }
    17         else {
    18             RuntimeException e = new RuntimeException(
    19                 this + " sendMessageAtTime() called with no mQueue");
    20             Log.w("Looper", e.getMessage(), e);
    21         }
    22         return sent;
    23 }

    Messager or Sender

  • 1 private final class MessengerImpl extends IMessenger.Stub {
    2         public void send(Message msg) {
    3             Handler.this.sendMessage(msg);
    4         }
    5 }
     1IMessenger sender = handler.getIMessenger();
     2sender.send(msg);
     3 
     4 //
     5 final IMessenger getIMessenger() {
     6         synchronized (mQueue) {
     7             if (mMessenger != null) {
     8                 return mMessenger;
     9             }
    10             mMessenger = new MessengerImpl();
    11             return mMessenger;
    12         }
    13     }
  • Looper
  •   1 package android.os;
      2 import android.util.Log;
      3 import android.util.Printer;
      4 import android.util.PrefixPrinter;
      5 public class Looper {
      6     private static final String TAG = "Looper";
      7     // sThreadLocal.get() will return null unless you've called prepare().
      8     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
      9     final MessageQueue mQueue;
     10     final Thread mThread;
     11     volatile boolean mRun;
     12     private Printer mLogging = null;
     13     private static Looper mMainLooper = null;  // guarded by Looper.class
     14     public static void prepare() {
     15         if (sThreadLocal.get() != null) {
     16             throw new RuntimeException("Only one Looper may be created per thread");
     17         }
     18         sThreadLocal.set(new Looper());
     19     }
     20     public static void prepareMainLooper() {
     21         prepare();
     22         setMainLooper(myLooper());
     23         myLooper().mQueue.mQuitAllowed = false;
     24     }
     25     private synchronized static void setMainLooper(Looper looper) {
     26         mMainLooper = looper;
     27     }
     28     public synchronized static Looper getMainLooper() {
     29         return mMainLooper;
     30     }
     31     public static void loop() {
     32         Looper me = myLooper();
     33         if (me == null) {
     34             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
     35         }
     36         MessageQueue queue = me.mQueue;        
     37         // Make sure the identity of this thread is that of the local process,
     38         // and keep track of what that identity token actually is.
     39         Binder.clearCallingIdentity();
     40         final long ident = Binder.clearCallingIdentity();
     41         
     42         while (true) {
     43             Message msg = queue.next(); // might block
     44             if (msg != null) {
     45                 if (msg.target == null) {
     46                     // No target is a magic identifier for the quit message.
     47                     return;
     48                 }
     49 
     50                 long wallStart = 0;
     51                 long threadStart = 0;
     52 
     53                 // This must be in a local variable, in case a UI event sets the logger
     54                 Printer logging = me.mLogging;
     55                 if (logging != null) {
     56                     logging.println(">>>>> Dispatching to " + msg.target + " " +
     57                             msg.callback + ": " + msg.what);
     58                     wallStart = SystemClock.currentTimeMicro();
     59                     threadStart = SystemClock.currentThreadTimeMicro();
     60                 }
     61 
     62                 msg.target.dispatchMessage(msg);
     63 
     64                 if (logging != null) {
     65                     long wallTime = SystemClock.currentTimeMicro() - wallStart;
     66                     long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
     67 
     68                     logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
     69                     if (logging instanceof Profiler) {
     70                         ((Profiler) logging).profile(msg, wallStart, wallTime,
     71                                 threadStart, threadTime);
     72                     }
     73                 }
     74 
     75                 // Make sure that during the course of dispatching the
     76                 // identity of the thread wasn't corrupted.
     77                 final long newIdent = Binder.clearCallingIdentity();
     78                 if (ident != newIdent) {
     79                     Log.wtf(TAG, "Thread identity changed from 0x"
     80                             + Long.toHexString(ident) + " to 0x"
     81                             + Long.toHexString(newIdent) + " while dispatching to "
     82                             + msg.target.getClass().getName() + " "
     83                             + msg.callback + " what=" + msg.what);
     84                 }
     85                 
     86                 msg.recycle();
     87             }
     88         }
     89     }
     90     public static Looper myLooper() {
     91         return sThreadLocal.get();
     92     }
     93     public void setMessageLogging(Printer printer) {
     94         mLogging = printer;
     95     }
     96     public static MessageQueue myQueue() {
     97         return myLooper().mQueue;
     98     }
     99     private Looper() {
    100         mQueue = new MessageQueue();
    101         mRun = true;
    102         mThread = Thread.currentThread();
    103     }
    104     public void quit() {
    105         Message msg = Message.obtain();
    106         // NOTE: By enqueueing directly into the message queue, the
    107         // message is left with a null target.  This is how we know it is
    108         // a quit message.
    109         mQueue.enqueueMessage(msg, 0);
    110     }
    111     public Thread getThread() {
    112         return mThread;
    113     }
    114     public MessageQueue getQueue() {
    115         return mQueue;
    116     }
    117     public void dump(Printer pw, String prefix) {
    118         pw = PrefixPrinter.create(pw, prefix);
    119         pw.println(this.toString());
    120         pw.println("mRun=" + mRun);
    121         pw.println("mThread=" + mThread);
    122         pw.println("mQueue=" + ((mQueue != null) ? mQueue : "(null"));
    123         if (mQueue != null) {
    124             synchronized (mQueue) {
    125                 long now = SystemClock.uptimeMillis();
    126                 Message msg = mQueue.mMessages;
    127                 int n = 0;
    128                 while (msg != null) {
    129                     pw.println("  Message " + n + ": " + msg.toString(now));
    130                     n++;
    131                     msg = msg.next;
    132                 }
    133                 pw.println("(Total messages: " + n + ")");
    134             }
    135         }
    136     }
    137     public String toString() {
    138         return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
    139     }
    140 }
    Looper

    Variables in Looper

  • 1     private static final String TAG = "Looper";
    2     // sThreadLocal.get() will return null unless you've called prepare().
    3     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    4     final MessageQueue mQueue;
    5     final Thread mThread;
    6     volatile boolean mRun;
    7     private Printer mLogging = null;
    8     private static Looper mMainLooper = null;  // guarded by Looper.class

     Create a looper for thread when creating a thread

  •  1 public static void prepare() { //must call prepare() to create a looper in thread's run or somewhere else
     2         if (sThreadLocal.get() != null) {
     3             throw new RuntimeException("Only one Looper may be created per thread");
     4         }
     5         sThreadLocal.set(new Looper());
     6 }
     7 private Looper() { //default constructor is private
     8         mQueue = new MessageQueue();
     9         mRun = true;
    10mThread = Thread.currentThread();//Host thread,so have to ensure that the host thread has been start.
    11 }
  • Looping
  •  1 /**
     2      * Run the message queue in this thread. Be sure to call
     3      * {@link #quit()} to end the loop.
     4      */
     5 public static void loop() {
     6         Looper me = myLooper(); //current thread's looper
     7         if (me == null) {
     8             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
     9         }
    10         MessageQueue queue = me.mQueue;        
    11         // Make sure the identity of this thread is that of the local process,
    12         // and keep track of what that identity token actually is.
    13         Binder.clearCallingIdentity();
    14         final long ident = Binder.clearCallingIdentity();        
    15         while (true) {
    16             Message msg = queue.next(); // might block
    17             if (msg != null) {
    18                 if (msg.target == null) {
    19                     // No target is a magic identifier for the quit message.
    20                     return; //quit message when message has not target
    21                 }
    22                 long wallStart = 0;
    23                 long threadStart = 0;
    24                 // This must be in a local variable, in case a UI event sets the logger
    25                 Printer logging = me.mLogging;
    26                 if (logging != null) {
    27                     logging.println(">>>>> Dispatching to " + msg.target + " " +
    28                             msg.callback + ": " + msg.what);
    29                     wallStart = SystemClock.currentTimeMicro();
    30                     threadStart = SystemClock.currentThreadTimeMicro();
    31                 }
    32 
    33                msg.target.dispatchMessage(msg);//defined in message's target handler
    34 
    35                 if (logging != null) {
    36                     long wallTime = SystemClock.currentTimeMicro() - wallStart;
    37                     long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
    38 
    39                     logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    40                     if (logging instanceof Profiler) {
    41                         ((Profiler) logging).profile(msg, wallStart, wallTime,
    42                                 threadStart, threadTime);
    43                     }
    44                 }
    45 
    46                 // Make sure that during the course of dispatching the
    47                 // identity of the thread wasn't corrupted.
    48                 final long newIdent = Binder.clearCallingIdentity();
    49                 if (ident != newIdent) {
    50                     Log.wtf(TAG, "Thread identity changed from 0x"
    51                             + Long.toHexString(ident) + " to 0x"
    52                             + Long.toHexString(newIdent) + " while dispatching to "
    53                             + msg.target.getClass().getName() + " "
    54                             + msg.callback + " what=" + msg.what);
    55                 }
    56                 
    57                msg.recycle();
    58             }
    59         }
    60     }

    Methods in Looper

  •  1 public static void prepareMainLooper()
     2 {
     3         prepare();
     4         setMainLooper(myLooper());
     5         myLooper().mQueue.mQuitAllowed = false;
     6 }
     7 private synchronized static void setMainLooper(Looper looper) {
     8         mMainLooper = looper;
     9 }
    10 public synchronized static Looper getMainLooper() {
    11         return mMainLooper;
    12 }
    13 public static Looper myLooper() {
    14         return sThreadLocal.get();
    15 }
    16 public void quit() 
    17 {
    18         Message msg = Message.obtain();
    19         // NOTE: By enqueueing directly into the message queue, the
    20         // message is left with a null target.  This is how we know it is
    21         // a quit message.
    22         mQueue.enqueueMessage(msg, 0);
    23 }
  •  Create your messge handler

    1. Create a thread for receving message and handling message
    2. In thread's run() or somewhere else but ensuring thread has been start, create a looper using Looper.prepareMainLooper() for creating a looper for thread
    3.   1 /*
        2  * Copyright (C) 2006 The Android Open Source Project
        3  *
        4  * Licensed under the Apache License, Version 2.0 (the "License");
        5  * you may not use this file except in compliance with the License.
        6  * You may obtain a copy of the License at
        7  *
        8  *      http://www.apache.org/licenses/LICENSE-2.0
        9  *
       10  * Unless required by applicable law or agreed to in writing, software
       11  * distributed under the License is distributed on an "AS IS" BASIS,
       12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       13  * See the License for the specific language governing permissions and
       14  * limitations under the License.
       15  */
       16 
       17 package android.os;
       18 
       19 /**
       20  * Handy class for starting a new thread that has a looper. The looper can then be 
       21  * used to create handler classes. Note that start() must still be called.
       22  */
       23 public class HandlerThread extends Thread {
       24     int mPriority;
       25     int mTid = -1;
       26     Looper mLooper;
       27 
       28     public HandlerThread(String name) {
       29         super(name);
       30         mPriority = Process.THREAD_PRIORITY_DEFAULT;
       31     }
       32     
       33     /**
       34      * Constructs a HandlerThread.
       35      * @param name
       36      * @param priority The priority to run the thread at. The value supplied must be from 
       37      * {@link android.os.Process} and not from java.lang.Thread.
       38      */
       39     public HandlerThread(String name, int priority) {
       40         super(name);
       41         mPriority = priority;
       42     }
       43     
       44     /**
       45      * Call back method that can be explicitly over ridden if needed to execute some
       46      * setup before Looper loops.
       47      */
       48     protected void onLooperPrepared() {
       49     }
       50 
       51     public void run() {
       52         mTid = Process.myTid();
       53         Looper.prepare();
       54         synchronized (this) {
       55             mLooper = Looper.myLooper();
       56             notifyAll();
       57         }
       58         Process.setThreadPriority(mPriority);
       59         onLooperPrepared();
       60         Looper.loop();
       61         mTid = -1;
       62     }
       63     
       64     /**
       65      * This method returns the Looper associated with this thread. If this thread not been started
       66      * or for any reason is isAlive() returns false, this method will return null. If this thread 
       67      * has been started, this method will block until the looper has been initialized.  
       68      * @return The looper.
       69      */
       70     public Looper getLooper() {
       71         if (!isAlive()) {
       72             return null;
       73         }
       74         
       75         // If the thread has been started, wait until the looper has been created.
       76         synchronized (this) {
       77             while (isAlive() && mLooper == null) {
       78                 try {
       79                     wait();
       80                 } catch (InterruptedException e) {
       81                 }
       82             }
       83         }
       84         return mLooper;
       85     }
       86     
       87     /**
       88      * Ask the currently running looper to quit.  If the thread has not
       89      * been started or has finished (that is if {@link #getLooper} returns
       90      * null), then false is returned.  Otherwise the looper is asked to
       91      * quit and true is returned.
       92      */
       93     public boolean quit() {
       94         Looper looper = getLooper();
       95         if (looper != null) {
       96             looper.quit();
       97             return true;
       98         }
       99         return false;
      100     }
      101     
      102     /**
      103      * Returns the identifier of this thread. See Process.myTid().
      104      */
      105     public int getThreadId() {
      106         return mTid;
      107     }
      108 }
      HandlerThread
    4. Create a handler object which will be used in different thread, and this handler object will has its thread's looper and message queue.
    5. Two threads can communicte with each other using handler to send message.
    6. Three ways to handle with message
      • Overriden handleMessage() in subclass.
      • Set Callback object which implements Handler's Callback interface in handler object to handler message
      • Send a message with its Runnable object to run.

Reference:http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html

posted @ 2013-08-22 14:48  iDragon  阅读(957)  评论(0)    收藏  举报