面试时候经常被问到 handler是什么,说说你的理解...被问到这些心里就发毛,因为不知道从什么深度来说,说的深了,自己也没读过源码,细节的东西说不清反而不好,
我们可以看到handlerthread就是把looper给loop了,具体的干活的都是在looper里面了.不过从这个简单的类里面咱们可以复习一下java多线程的知识,看代码的注释..
messagequeue就不贴了,使用epoll的nio技术
看一下构造函数,如果我们在activity也就是主线程使用new handler(),那么这个handler的handlemessage函数就是运行在主线程,就是UI线程
就是把message往messagequeue里面enqueue一下.
说的浅了,这问题也没啥意义了..
从java层的代码来看看,handler和相关的一系列的类到底是怎么回事
先从handlerthread来看,handler也是作用在thread上的,看看handlerthread有啥不一样的
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}//同下面的wait块,创建好了looper,notify一下wait的那边
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}//java里面典型的wait块,wait的时候会把thread moniter放弃,直到looper创建好了,执行notify.
return mLooper;
}
}
我们可以看到handlerthread就是把looper给loop了,具体的干活的都是在looper里面了.不过从这个简单的类里面咱们可以复习一下java多线程的知识,看代码的注释..
看looper这个类
先要prepare,就是要创建looper的类,用到了threadlocal变量,因为是线程独有的.
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
loop的话 会调用messagequeue.next来得到下一个message,得到的话 会调用message包含的target,也就是handler的dispatchmessage函数.
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
messagequeue就不贴了,使用epoll的nio技术
看看handler的
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
看一下构造函数,如果我们在activity也就是主线程使用new handler(),那么这个handler的handlemessage函数就是运行在主线程,就是UI线程
而如果是在其他handlerthread的话,那么就是这个线程的looper.否则的话 就需要注明参数具体是哪个looper了
在看一下发送消息的函数
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
就是把message往messagequeue里面enqueue一下.
还有经常会问的问题就是handler和asynctask的区别.
aysnctask的默认的executor是串行执行的,也就是说会一个任务一个任务执行,如果一个app里面有N多图片要加载,而每个图片都是运行一个asynctask的话,那么就会非常的慢.
当然也可以使用并行的executor来.当然如果doinbackground之后有需要往UI线程写点东西,那么asynctask当然很方便了
可以看一下这个博客,图很清楚 http://www.cnblogs.com/anee/archive/2012/09/24/2699829.html