一、Handler的用法
- post(Runnable)方法:使Runnable添加到消息队列。
利用这个方法可以在Runnable线程里更新UI。
handler.post(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
textView.setText("我不好");
}
});
2.postDelayed(Runnable r, long delayMillis):延迟一段时间
//handler轮播
public class MainActivity extends Activity {
private int images[] = {R.drawable.account1, R.drawable.account2, R.drawable.account3};
private int index;
private ImageView imageView;
private Handler handler = new Handler();
private MyThread myThread = new MyThread();
class MyThread extends Thread {
@Override
public void run() {
index++;
index = index % 3;
imageView.setImageResource(images[index]);
//放在run方法里面便会不断循环操作
handler.postDelayed(myThread, 1000);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.imageview);
//初始启动mythread内的方法
handler.post(myThread);
//下面这种方法也是一样的
//myThread.start();
}
}
3.removeCallbacks(Runnable r):在消息队列里移除一个runnable
4.构造函数里面有Callbacks
private Handler handler2 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
}){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
如果返回为true,则会拦截返回值为Void的hangleMessage.
二、与Looper、MessageQueue、Message的关系。
在创建ActivityThread主线程的时候,
一
会创建Looper对象,而在创建Looper对象时候,内部又会创建Messagequeue。这样主线程和Looper关联了,Looper又和MessageQueue相关联,并且一个线程里只有一个Looper,一个MessageQueue.
二
会调用Looper.loop()不断的取出消息,开启消息循环,并用handler分发。
通过prepareMainLooper()方法再调用prepare()方法,
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));
}
可以看到最后一行new出了一个Looper。
loop方法:
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();
}
}
loop中确实存在一个死循环,而唯一退出该循环的方式就是消息队列返回的消息为空。然后我们通过消息队列的next()方法获得消息。msg.target是发送消息的Handler,通过Handler中的dispatchMessage方法又将消息交由Handler处理。
在创建Handler的时候
通过创建Handler的构造方法里面的Looper.myLooper()获取了当前线程保存的Looper实例,
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
ThreadLocal这个类,ThreadLocal它实现了本地变量存储,我们将当前线程的数据存放在ThreadLocal中,若是有多个变量共用一个ThreadLocal对象,这时候在当前线程只能获取该线程所存储的变量,而无法获取其他线程的数据。
在Prepare方法中可以看到通过sThreadLocal.set(new Looper(quitAllowed));保存了一个Looper.
这样Handler就和Looper、MessageQueue关联了。
在Handler子线程发送消息时候:
通过post和send方式,最终都是通过sendMessageAtTime方法的入队方法enqueueMessage在消息队列中插入一条消息。然后交由Handler中的dispatchMessage方发进行消息分发处理。
由上面的loop方法可以看出来。
下面我们来看一下dispatchMessage方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
例子:通过主线程发送消息给子线程,然后由子线程接收消息并进行处理
public class MyActivity extends AppCompatActivity {
private final String TAG = "MyActivity";
public Handler mHandler;
public Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.send_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mHandler != null){
mHandler.obtainMessage(0,"你好,我是从主线程过来的").sendToTarget();
}
}
});
new Thread(new Runnable() {
@Override
public void run() {
//在子线程中创建一个Looper对象
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 0){
Log.d(TAG,(String)msg.obj);
}
}
};
//开启消息循环
Looper.loop();
}
}).start();
}
}
总结:
在主线程创建时,一、创建了一个Looper,创建Looper的时候在Looper内部创建一个消息队列二、调用了Looper.loop()方法写了一个死循环。不断的取出消息。而在创建Handler对象的时候,取出当前线程的Looper,并通过Looper获取消息队列,这样Handler就和消息队列关联起来了。然后Handler在子线程发送消息,通过enqueueMessage在消息队列中插入一条消息。通过程序启动时的Looper.loop()方法消息循环取得这条消息并交由handler处理。
参考:Android Handler 机制实现原理分析
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系