一、Handle & Message概述
概述:Handler與Message共同構建起了Android的消息處理模塊,經常被用于更新主線程(界面)。
Handler
官方API鏈接:https://developer.android.com/reference/android/os/Handler.html
這里直譯有關于Handler的英文介紹就沒意思了,我嘗試概述一下吧:
??Handler的主要作用:在非主線程任務執行完成后,返回結果通過Handler與主線程接觸(可能是顯示結果之類的)。
??Handler有兩種工作方式,一種是執行Runnable對象(執行時間可操控),另一種是發送來自不同線程的Message對象并執行對應操作。Runnable以及Message將會進入Handler的信息隊列然后在指定的時間完成處理。
????Tip:其中執行Runnable對象的方法名都是帶有post字樣的,而發送Message對象的方法名都是帶有sendMessage字樣的
Message
官方API鏈接:https://developer.android.com/reference/android/os/Message.html
官方的介紹比較簡單,大概意思是Message是個包含一些數據的,并且能發送到Handler的對象。接下來建議使用者在多次復用同一個Message對象時每次都調用Message.obtain()或者Habdler.obtainMessage()為其重新賦值,而不是直接new Message。
包含數據這并發送給Handler這點容易懂,但是為啥建議不直接new Message()呢,現在就去翻源碼看看:
由上面兩張Message類中的方法源碼圖可知,只有在sPool為空的時候,obtain方法才會申請創建新的對象,其他時候都是直接取sPool.next使用的。現在疑問又來了,sPool.next是什么東西呢?我們再看看源碼:
看看備注,備注里說用鏈表存儲這些Message,哦就是說從回收池中拿對象?回想起Message的官方API介紹:
還真是這樣哼~好吧那我就勉為其難地用著兩個方法來實例化對象咯以后。
二、簡單使用示范
先上界面代碼:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_thread_async"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.qixi.m303tool.activity.ThreadAsyncActivity">
<Button
android:id="@+id/btn_thread"
android:text="Thread -1s"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"/>
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/btn_thread"
android:visibility="gone"/>
</RelativeLayout>
ThreadActivity.class代碼如下:
public class ThreadActivity extends AppCompatActivity implements View.OnClickListener {
private final static String TAG = "ThreadAsyncActivity";
private Button btn_thread;
private TextView tv_result;
private Handler mHandler;
private Message msg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread);
btn_thread = (Button)findViewById(R.id.btn_thread);
btn_thread.setOnClickListener(this);
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
tv_result.setText((String)msg.obj);
btn_thread.setEnabled(true);
break;
}
}
};
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_thread:
btn_thread.setEnabled(false);
new Thread(){
@Override
public void run() {
try {
sleep(1000);
//TODO:send msg(include timestamp) to mHandler
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
break;
}
}
}
很簡單的Demo,就是一個Button和一個TextView,點擊Button之后sleep一秒,然后將message發送到handler中,執行顯示當前時間戳。咦具體發送部分呢po主你騙人只寫了個TODO!好啦好啦不要緊張現在來填坑b( ̄▽ ̄)d,之前看Message官方API中的對象賦值的介紹時建議用Message.obtain()或者Handler.obtainMessage(),那我們就用這兩種來實現咯:
1、Message.obtain()
//TODO:send msg(include timestamp) to mHandler
msg = mHandler.obtainMessage();
msg.what=0;
msg.obj = System.currentTimeMillis()+". Here is Thread -1s result.";
//msg = mHandler.obtainMessage(0,System.currentTimeMillis()+". Here is Thread -1s result.");
mHandler.sendMessage(msg);
TODO之后的三行與被屏蔽的第四行意思相同。實現的流程是先取得一個Message對象,然后放置一些data進入Message對象,最終發送給mHandler。
2、Handler.obtainMessage()
//TODO:send msg(include timestamp) to mHandler
msg= msg.obtain();
msg.setTarget(mHandler);
msg.what=0;
msg.obj=System.currentTimeMillis()+". Here is Thread -1s result.";
//msg=msg.obtain(mHandler,0,System.currentTimeMillis()+". Here is Thread -1s result.");
msg.sendToTarget();
TODO之后的四行與被屏蔽的第五行意思相同。實現的流程是用Message.obtain獲取一個Message對象,然后放置一些data進入Message對象(包括目標Handler),最后sendToTarget發送到目標。
上面這兩種寫法其實源碼的實現是一樣的:
這是Handler類的方法obtainMessage(),看到這里應該都懂了,我去!
Message.obtain()&&Handler.obtainMessage()不就是同一個嗎!obtian()和obtainMessage()雖然都有多個類似的方法但是最終都是指向同一個的實現,目的也都是填充Message而已。然后
下面沒有了hhh~