前面二篇都是关于 Handler message Thread runnable 文章,大概从源代码和流程机制 三者的关系。接下来谈谈应用场景。Handler 就是为了实现多线程的问题,前面一篇文章也讲过,多线程并发有一定的缺陷,android 引入message机制就很好的解决了多线程并发问题了。假设在一个activity里面有多个线程去更新UI,并且都没有加锁机制,那就会造成更新UI错乱。如果对更新UI的操作都进行加锁处理,就会造成性能下降。使用消息机制,根本不用关系多线程的问题,因为更新UI的操作,都是在主线程的消息队列当中去轮询处理的。这里也特别强调下,在UI Thread 更新UI。
Handler既然是android只带的消息机制,那我们就可以通过handler 来发消息和处理消息。下面来讲讲Handler应用场景。
应用场景一:刷新UI界面。
<pre name="code" class="java">public class HandlerActivity extends Activity implements OnClickListener {
private static final String TAG = "stvelzhang";
private TextView tv_activity_test_update_ui ;
private Button btn_handler1, btn_handler2,btn_handler3,btn_handler4;
private static final int SUCCESS_GET_DATA = 1;
private static final int SUCCESS_GET_DATA_OBJ = 2;
private static final int SUCCESS_GET_DATA_BUNDLE = 3;
private Handler mHandler = new Handler();
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_GET_DATA:
Log.d(TAG,"myhandler thread_id :: " + Thread.currentThread().getId()
+ " myhandler thread_name :: "
+ Thread.currentThread().getName());
//打印显示 myhandler thread_id :: 1 myhandler thread_name :: main
tv_activity_test_update_ui.setText("使用handler.sendMessage()更新");
break;
case SUCCESS_GET_DATA_OBJ:
tv_activity_test_update_ui.setText("使用handler.sendMessage()更新" + msg.obj);
break;
case SUCCESS_GET_DATA_BUNDLE:
Bundle date = msg.getData();
tv_activity_test_update_ui.setText("使用handler.sendMessage()更新" + " :: " + date.getInt("year") + " :: " + date.getString("where"));
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv_activity_test_update_ui = (TextView) findViewById(R.id.tv_update_ui);
initview();
Log.d(TAG,"activity thread_id :: " + Thread.currentThread().getId()
+ " activity thread_name :: "
+ Thread.currentThread().getName());
}
public void initview(){
btn_handler1 = (Button) findViewById(R.id.btn_1);
btn_handler1.setOnClickListener(this);
btn_handler2 = (Button) findViewById(R.id.btn_2);
btn_handler2.setOnClickListener(this);
btn_handler3 = (Button) findViewById(R.id.btn_3);
btn_handler3.setOnClickListener(this);
btn_handler4 = (Button) findViewById(R.id.btn_4);
btn_handler4.setOnClickListener(this);
}
@Override
public void onClick(View vid) {
switch(vid.getId()){
case R.id.btn_1:
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable(){
@Override
public void run() {
tv_activity_test_update_ui.setText("调用runOnUIThread方法更新");
}
});
}
}).start();
/*
new Thread(new Runnable(){
@Override
public void run() {
Log.d(TAG,"btn1 thread_id :: " + Thread.currentThread().getId()
+ " btn1 thread_name :: "
+ Thread.currentThread().getName());
tv_activity_test_update_ui.setText("调用runOnUIThread方法更新");
}
}).start();
*上面的代码运行会报错 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
*说明只能在程序的主线程(也就是ui Thread)线程中进行更新界面显示的工作
*
*/
break;
case R.id.btn_2:
tv_activity_test_update_ui.post(new Runnable(){
@Override
public void run() {
Log.d(TAG,"btn2 thread_id :: " + Thread.currentThread().getId()
+ " btn2 thread_name :: "
+ Thread.currentThread().getName());
//打印出来是 btn2 thread_id :: 1 btn2 thread_name :: main
//说明是Ui线程,所以可以更新UI。
tv_activity_test_update_ui.setText("使用View的post()更新UI");
}
});
break;
case R.id.btn_3:
new Thread(new Runnable(){
@Override
public void run() {
Log.d(TAG,"btn3 thread_id :: " + Thread.currentThread().getId()
+ " btn3 thread_name :: "
+ Thread.currentThread().getName());
//打印出来 btn3 thread_id :: 682 btn3 thread_name :: Thread-682
//说明线程是用了new thread。这也符合情况。
mHandler.post(new Runnable(){
@Override
public void run() {
tv_activity_test_update_ui.setText("Handler的post()更新UI");
Log.d(TAG,"getcurrent thread_id :: " + Thread.currentThread().getId()
+ " getcurrent thread_name :: "
+ Thread.currentThread().getName());
//打印出来 getcurrent thread_id :: 1 getcurrent thread_name :: main
//mHandler 是在主线程定义声明的。handler 和 线程是绑定在一起的。
//这个例子也正好证明了,可以在子线程通过handler 对UI 进行刷新。
}
});
}
}).start();
break;
case R.id.btn_4:
new Thread(new Runnable(){
@Override
public void run() {
myHandler.sendEmptyMessage(SUCCESS_GET_DATA);
/*
* 上面send empty message,没有带数据的。下面带上数据
* (1) Message 对象
* message 对象携带数据,通常用 arg1 arg2 来传递消息数据,也可以使用obj参数,也可以使用 bundle数据。
* Message msg = handler.obtainMessage();
* (2) Bundle 对象
* Bundle 是一个类,可以看着map一样的东西,有key 有数据。key 必须是String 类型。
Message msg = myHandler.obtainMessage();
//华丽的分割线
msg.obj = "tiger is here";
msg.what = SUCCESS_GET_DATA_OBJ;
myHandler.sendMessage(msg);
//华丽的分割线
msg.what = SUCCESS_GET_DATA_BUNDLE;
Bundle bud = new Bundle();
bud.putInt("year", 2016);
bud.putString("where", "北方的狼");
msg.setData(bud);
msg.sendToTarget();
*/
Log.d(TAG,"btn4 thread_id :: " + Thread.currentThread().getId()
+ " btn4 thread_name :: "
+ Thread.currentThread().getName());
//打印显示 btn4 thread_id :: 691 btn4 thread_name :: Thread-691
//如果在这里直接写 tv_activity_test_update_ui.setText("使用handler.sendMessage()更新");
//肯定是要报错的。因为是子线程了
}
}).start();
break;
}
}
}
应用场景二:自定义与线程相关的handler。
在一个子线程中去创建一个Handler,然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行
new Thread()
{
private Handler handler;
public void run()
{
Looper.prepare();
handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
Log.d(TAG,Thread.currentThread().getName());
};
};
Looper.loop();
}
}
public class ThreadDemo extends Activity {
private static final String TAG = "ThreadDemo";
private static final int UI_HANDLER_MSG = 1;
private static final int THREAD_HANDLER_MSG = 2;
private MyThread myThread;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case UI_HANDLER_MSG:
Log.d(TAG, "mHandler threadid :: " +
Thread.currentThread().getId() +
" mHandler threadname :: " +
Thread.currentThread().getName());
Log.d(TAG, " I am come UI handler done message");
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lay_thread);
myThread = new MyThread();
myThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(UI_HANDLER_MSG);
myThread.myHandler.sendEmptyMessage(THREAD_HANDLER_MSG);
}
class MyThread extends Thread{
private Handler myHandler;
@Override
public void run() {
super.run();
Looper.prepare();
myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//we can do something ......
Log.d(TAG,"getcurrent threadid :: " +
Thread.currentThread().getId() +
" getcurrent threadname :: " +
Thread.currentThread().getName());
switch(msg.what){
case THREAD_HANDLER_MSG:
Log.d(TAG, " I am come myhandler done message");
break;
}
}
};
Looper.loop();
}
}
}
打印显示 :
D/ThreadDemo(29475): getcurrent threadid :: 936 getcurrent threadname :: Thread-936
D/ThreadDemo(29475): I am come myhandler done messageD/ThreadDemo(29475): mHandler threadid :: 1 mHandler threadname :: main
D/ThreadDemo(29475): I am come UI handler done message
不同的线程handler 消息处理是不一样的。
应用场景三:定时器。
private static final int LOAD_DISPLAY_TIME = 3000; // 延迟3s
new Handler().postDelayed(new Runnable() {
public void run() {
// 时间到时,执行的代码
}
}, LOAD_DISPLAY_TIME);
关闭此定时器:handler.removeCallbacks(runnable);
一个activity 延时 然后跳转到 其他activity,引导应用首页
private void startThreadDemo() {
mHandler.postDelayed(new Runnable(){
@Override
public void run() {
Intent mintent = new Intent(HandlerActivity.this, ThreadDemo.class);
startActivity(mintent);
HandlerActivity.this.finish();
}
}, 1000);
}
应用场景四:拦截Handler传递的消息。
public class CallBackDemo extends Activity implements OnClickListener {
private Button btn1, btn2;
private TextView tv_1, tv_2;
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message arg0) {
Toast.makeText(CallBackDemo.this, R.string.hello_callback,
Toast.LENGTH_SHORT);
Log.d("CallBackDemo", "handleMessage msg :: " + arg0.what);
tv_1.setText("callback handlermessage msg :: " + arg0.what);
tv_2.setText("callback handlermessage msg :: " + arg0.what);
if(arg0.what == 0x01){
return false;
}
else{
return true;
}
}
}){
@Override
public void handleMessage(Message msg) {
Toast.makeText(CallBackDemo.this, R.string.hello_callback_ui,
Toast.LENGTH_LONG);
tv_2.setText("handlermessage msg :: " + msg.what);
tv_1.setText(R.string.dont_intercept_msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lay_callback);
initview();
}
public void initview(){
tv_1 = (TextView) findViewById(R.id.tv_dont_ui);
tv_2 = (TextView) findViewById(R.id.tv_done_ui);
btn1 = (Button) findViewById(R.id.btn_dont);
btn2 = (Button) findViewById(R.id.btn_done);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.btn_dont:
Log.d("CallBackDemo", "onclick btn_dont");
mHandler.sendEmptyMessage(0x01);
break;
case R.id.btn_done:
Log.d("CallBackDemo", "onclick btn_done");
mHandler.sendEmptyMessage(0x02);
break;
}
}
}
最后附上代码参考学习下。