android handler学习
2016-08-17 16:56
477 查看
什么是handler
首先要理解安卓的UI操作不是线程安全的,这就是决定了一个子线程无法直接更新UI。我们的安卓应用启动时,首先启来的是我们看到的activity,这是一个UI主线程。这个UI主线程有个问题,我们不能在这个线程里做一些太耗时的工作,这样的会使得看到的界面体验很卡。所以这样耗时的操作要放到子线程去做。但是前面讲到子线程又不能更新主线程中的UI,怎么办呢?handler就是用来处理这种情况的。
当我们在子线程中完成了一个耗时的操作后,通过handler向主线程发送消息,主线程就更新UI显示。这个消息还可以传递一些数据。看个例子:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start(); } Handler myHandler = new Handler(){ @Override public void handleMessage(Message msg) { Bundle b = msg.getData(); Log.i(TAG, "got some message:" + b.getString("data")); super.handleMessage(msg); } }; //线程类,这里发送通过handler发送消息给主线程(UI线程) class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "this is a child thread running...."); Message msg = new Message(); //还可以带上一些数据 Bundle b = new Bundle(); b.putString("data", "test data"); msg.setData(b); myHandler.sendMessage(msg); } } 程序很简单,主线程启动时开启一个子线程,子线程处理完事情(就是打印一
条调试信息)通过handler发送消息,主线程中的myHandler通过handleMessage可以接收到消息处理。程序输出:
I/MainActivity: this is a child thread running….
I/MainActivity: got some message:test data
控制消息类型
如果子线程中想要不同的状态发送不同的消息,该如何处理呢?也很简单,message对象有一些成员可以用:Handler myHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Bundle b = msg.getData(); Log.i(TAG, "got some message:" + b.getString("data")); break; case 0: break; default: break; } super.handleMessage(msg); } }; //线程类,这里发送通过handler发送消息给主线程(UI线程) class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "this is a child thread running...."); Message msg = new Message(); if(true) { msg.what = 1; } else { msg.what = 0; } //还可以带上一些数据 Bundle b = new Bundle(); b.putString("data", "test data"); msg.setData(b); myHandler.sendMessage(msg); } }
dispatchMessage与sendMessage区别
简单来讲,调用sendMessage会把Message对象放入一个MessageQueue队列,该队列属于某个Looper对象,个Looper对象属于主线程。Looper对象会不断的从这个消息队列中获取消息执行。而最终handler的执行是调用dispatchMessage方法。从上面的描述可以提取如下几个信息:
1. sendMessage最终会调用dispatchMessage。
2. sendMessage发出的消息,handler处理时运行在主线程内(因为looper是主线程的),而dispatchMessage发出的消息,handler处理时运行子线程内的(因为相当于子线程直接调用)。
可以验证一下,把代码稍作修改:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "main thread id:"+Thread.currentThread().getId()); MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start(); } Handler myHandler = new Handler(){ @Override public void handleMessage(Message msg) { Log.i(TAG, "got some message by dispatchMessage:" + b.getString("data")); Log.i(TAG, "handler thread:" + Thread.currentThread().getId()); super.handleMessage(msg); } }; //线程类,这里发送通过handler发送消息给主线程(UI线程) class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "this is a child thread running...."); Log.i(TAG, "thread id:"+Thread.currentThread().getId()); Message msg = new Message(); myHandler.dispatchMessage(msg); } }
输出结果:
I/MainActivity: main thread id:1
I/MainActivity: this is a child thread running….
I/MainActivity: thread id:4264
I/MainActivity: got some message by dispatchMessage:test data
I/MainActivity: handler thread:4264
如果改成sendMessage,结果会看到handler thread id值为1。
obtainMessage什么时候用
把线程的处理函数修改下://线程类,这里发送通过handler发送消息给主线程(UI线程) class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "this is a child thread running...."); Log.i(TAG, "thread id:"+Thread.currentThread().getId()); Message msg = myHandler.obtainMessage(); msg.sendToTarget(); } }
发现运行结果其实是一样的,也就是说这种方法同样能达到在不同线程传递消息的效果,那么区别呢?
obtainmessage是从消息池中拿来一个msg,不需要另开辟空间,new需要重新申请,效率低,obtianmessage可以循环利用。
还有POST也可以说说
POST作用是通过handler把子线程加到主线程的处理队列中,看个示例:protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "main thread id:"+Thread.currentThread().getId()); MyThread thread = new MyThread(); myHandler.post(thread); } //线程类,这里发送通过handler发送消息给主线程(UI线程) class MyThread implements Runnable{ @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "this is a child thread running...."); Log.i(TAG, "thread id:"+Thread.currentThread().getId()); } }
输出:
I/MainActivity: main thread id:1
I/MainActivity: this is a child thread running….
I/MainActivity: thread id:1
运行结果很明显,子线程的id和主线程是一样的,说明确实在主线程中运行。post因为可以使子线程运行在主线程内,所以可以直接在run函数里直接更新UI。
相关文章推荐
- Android Handler学习一
- android Handler 机制研究学习笔记
- Android Handler 深入学习(1)
- Android Handler使用方法(一) 学习笔记
- c++学习要点
- Microsoft Agent 学习笔记 (一)
- C++学习要点
- 《Mastering Delphi 6》学习笔记之七
- 自我学习之一:淡入淡出(抄)
- 对于初学者学习Java语言的建议[教学]
- <kingofark关于学习C++和编程的50个观点> 详解 - 预览版
- 乱弹语言的学习(答网友问)
- 对于(学习c++)的c程序员的建议
- kingofark关于学习C++和编程的另外35个观点
- dotNET和VS.NET 学习录像
- kingofark关于学习C++和编程的50个观点
- 2001 Microsoft Tech Ed (Beijing 2001/9/7 – 2001/9/9)学习总结
- 分享《21个项目玩转深度学习:基于TensorFlow的实践详解》PDF+源代码
- php学习 面向对象 课件第1/2页
- DOS命令初学者基础知识学习