目录:
基础知识:
1、Android的进程与线程模型
2、Android的UI主线程(或叫线程安全问题)
涉及知识点:
Handler的介绍
Handler使用方式一:子线程处理事务(后台干活),干完活后,在子线程中通过handler发消息,通知UI线程更新UI控件,由主线程中的handler的handleMessage处理UI更新动作。
Handler的使用方式二:Handler + HandlerThread
基础知识:
1、Android的进程与线程模型
Android的每个应用程序都运行在一个拥有独立用户ID的用户进程里,以保证每个应用的数据、程序都是互相隔离的。
参考:http://www.cnblogs.com/Hendy2014/articles/android_process_model.html
2、Android的UI主线程(或叫线程安全问题)
什么是UI主线程? 什么叫Android的单线程模型?什么叫Android的线程安全问题?
参考:
http://www.cnblogs.com/yaozhenfa/p/np_android_Handler.html
http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html
涉及知识点:
android.os.Handler 、 android.os.Handler.Callback
Looper、
Thread、Runnable
Message、Message queue
Handler的介绍
由于前述Android的进程模型与线程模型(UI主线程,线程安全问题),Android提供了一些解决机制,Handler就是其中一种。
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。(引用自:http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html)
Handler有两种消息方式,来解决线程间通信和操作问题,一是Handler.sendMessage()系列方法,二是Handler.post(Runnble)系列方法,但深入Handler源码,会发现是一回事。
Handler使用方式一:子线程处理事务(后台干活),干完活后,在子线程中通过handler发消息,通知UI线程更新UI控件,由主线程中的handler的handleMessage处理UI更新动作。
,handler的post是异步操作的
,两个队列,post线程对列,message消息队列
Handler使用方式一 模型图
public class HandlerTestActivity extends Activity { private TextView tv; private static final int UPDATE = 0; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO 接收消息并且去更新UI线程上的控件内容 if (msg.what == UPDATE) { // Bundle b = msg.getData(); // tv.setText(b.getString("num")); tv.setText(String.valueOf(msg.obj)); } super.handleMessage(msg); } }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.tv); new Thread() { @Override public void run() { // TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值 try { for (int i = 0; i < 100; i++) { Thread.sleep(500); Message msg = new Message(); msg.what = UPDATE; // Bundle b = new Bundle(); // b.putString("num", "更新后的值:" + i); // msg.setData(b); msg.obj = "更新后的值:" + i; handler.sendMessage(msg); } } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } }
另外,使用post()方式的示例
package android.handler;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class HandlerTest extends Activity { /** Called when the activity is first created. */ private Button startButton; private Button endButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //根据id获得控件对象 startButton = (Button)findViewById(R.id.startButton); endButton = (Button)findViewById(R.id.endButton); //为控件设置监听器 startButton.setOnClickListener(new StartButtonListener()); endButton.setOnClickListener(new EndButtonListener()); } class StartButtonListener implements OnClickListener{ public void onClick(View v) { //调用Handler的post()方法,将要执行的线程对象放到队列当中 handler.post(updateThread); } } class EndButtonListener implements OnClickListener{ public void onClick(View v) { //调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象 handler.removeCallbacks(updateThread); } } //创建Handler对象 Handler handler = new Handler(); //新建一个线程对象 Runnable updateThread = new Runnable(){ //将要执行的操作写在线程对象的run方法当中 public void run(){ System.out.println("updateThread"); //调用Handler的postDelayed()方法 //这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象 //第一个参数是Runnable类型:将要执行的线程对象 //第二个参数是long类型:延迟的时间,以毫秒为单位 handler.postDelayed(updateThread, 3000); } };}
Handler的使用方式二:Handler + HandlerThread
相当于借助封装好的HandlerThread去开启一个异步线程,它包含了自己的Looper对象,即有运行于异步线程中的MessageQueue消息机制,而创建Handler的时候,通过HandlerThread.getLooper()方法获得Looper,使用它作为handler创建的参数,让其与Handler绑定,这样,handler的消息处理(handleMessage或被post的runnable方法)便是在异步线程的handlerThread中了。
示例代码一:
public class ThreadDemo extends Activity { private static final String TAG = "bb"; private int count = 0; private Handler mHandler ; private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getId() + " " +count); count++; // setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { Log.e(TAG, "Main id "+Thread.currentThread().getId() + " " +count); super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 HandlerThread handlerThread = new HandlerThread("threadone"); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mHandler.post(mRunnable); } @Override protected void onDestroy() { //将线程与当前handler解除 mHandler.removeCallbacks(mRunnable); super.onDestroy(); } }
创建handler时,如未为其指定looper对象(new Handler(Looper)或setLooper(Looper)),则handler默认使用创建它的线程的looper,则handler的消息处理最终也运行在创建它的线程当中(post()中的runnable对象,sendMessage()后的handleMessage()代码),为证这一点,下面的例子,使用UI主线程创建handler,则其post()中的runnable对象,sendMessage()后的handleMessage()代码都将运行在UI主线程当中。
示例一:
public class ThreadDemo extends Activity { private static final String TAG = "bb"; private int count = 0; private Handler mHandler ; private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getId() + " " +count); count++; setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { Log.e(TAG, "Main id "+Thread.currentThread().getId() + " " +count); super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 mHandler = new Handler(); mHandler.post(mRunnable); //mRunnable最终运行于UI主线程 } @Override protected void onDestroy() { //将线程与当前handler解除绑定 //mHandler.removeCallbacks(mRunnable); super.onDestroy(); } }
----------------------
查缺补漏一下:java线程的复习
主线程里新建Thread并start(), 同样的runnable()会打印出不同的ThreadId, start后的thread是进入线程状态机的,cpu时间片轮到该thread的时候执行,而后进入开始、运行、暂停、停止等状态机中。(线程的生命周期,还记得吗?)
private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getId() + " " +count); count++; setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 Thread thread = new Thread (mRunnable); thread.start(); }
相关博文:
http://www.cnblogs.com/youxilua/archive/2011/11/25/2263825.html
http://www.cnblogs.com/yaozhenfa/p/np_android_Handler.html
其它参考:
Pro android 3 这本书,里面描述的Handler 说得非常的细致。