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 }
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 }
-
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 }
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 }
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 }
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
- Create a thread for receving message and handling message
- 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
-
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 }
- Create a handler object which will be used in different thread, and this handler object will has its thread's looper and message queue.
- Two threads can communicte with each other using handler to send message.
- 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