Handler机制原理推荐看这篇博客:http://blog.csdn.net/jiayi_yao/article/details/51082073
实例,请看本文。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cctvjiatao.handlerdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SendMsgAct"></activity> <activity android:name=".PostDelayedAct"></activity> <activity android:name=".SendMsgProgressbarAct"></activity> <activity android:name=".IsSameThreadAct"></activity> <activity android:name=".SendMsgLooperAct"></activity> </application> </manifest>
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; /** * Handler机制原理详见:http://blog.csdn.net/jiayi_yao/article/details/51082073 */ public class MainActivity extends Activity { private final String TAG = getClass().getSimpleName(); private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); context = this; setContentView(R.layout.activity_main); initView(); } private void initView() { Button btn1 = (Button) findViewById(R.id.btn1); Button btn2 = (Button) findViewById(R.id.btn2); Button btn3 = (Button) findViewById(R.id.btn3); Button btn4 = (Button) findViewById(R.id.btn4); Button btn5 = (Button) findViewById(R.id.btn5); btn1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(context, SendMsgAct.class)); } }); btn2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(context, PostDelayedAct.class)); } }); btn3.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(context, SendMsgProgressbarAct.class)); } }); btn4.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(context, IsSameThreadAct.class)); } }); btn5.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(context, SendMsgLooperAct.class)); } }); } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.cctvjiatao.handlerdemo.MainActivity" > <Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="sendMsg" /> <Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="PostDelayedAct" /> <Button android:id="@+id/btn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="SendMsgProgressbarAct" /> <Button android:id="@+id/btn4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="IsSameThreadAct" /> <Button android:id="@+id/btn5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="SendMsgLooperAct" /> </LinearLayout>
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.Button; /** * @作者: jiatao * @修改时间:2016-4-10 下午10:55:26 * @包名:com.cctvjiatao.handlerdemo * @文件名:SendMsgAct.java * @版权声明:www.cctvjiatao.com * @功能: 不断变化的按钮 */ public class SendMsgAct extends Activity { private final String TAG = getClass().getSimpleName(); private MyHandler mMyHandler; private Button btn_variable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_sendmsg); btn_variable = (Button) findViewById(R.id.btn_variable); mMyHandler = new MyHandler(); MyThread m = new MyThread(); new Thread(m).start(); } class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.e(TAG, "handleMessage..."); Bundle b = msg.getData(); String btnStr = b.getString("name"); btn_variable.append(btnStr); } } class MyThread implements Runnable { @Override public void run() { while (true) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Message msg = new Message(); Bundle b = new Bundle(); b.putString("name", "Monkey"); msg.setData(b); SendMsgAct.this.mMyHandler.sendMessage(msg); Log.e(TAG, "sendMessage..."); } } } }
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; /** * @作者: jiatao * @修改时间:2016-4-10 下午11:55:26 * @包名:com.cctvjiatao.handlerdemo * @文件名:PostDelayedAct.java * @版权声明:www.cctvjiatao.com * @功能: Handler.postDelayed + Runnable * 这个例子是最简单的介绍handler的使用:是将handler绑定到它所建立的线程中. */ public class PostDelayedAct extends Activity { private final String TAG = getClass().getSimpleName(); private TextView tv_msg; private Button btn_start, btn_end; Handler handler = new Handler(); Runnable rb = new Runnable(){ public void run() { //线程每次执行时输出"UpdateThread..."文字,且自动换行 tv_msg.append("\nUpdateThread..."); //延时3s后又将线程加入到线程队列中 handler.postDelayed(rb, 3000);//可以尝试注释本行代码,观察变化 }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_postdelayed); initView(); } private void initView() { tv_msg = (TextView) findViewById(R.id.tv_msg); btn_start = (Button) findViewById(R.id.btn_start); btn_end = (Button) findViewById(R.id.btn_end); btn_start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //将线程接口立刻送到线程队列中 handler.post(rb); Log.e(TAG, "start..."); } }); btn_end.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //将线程接口从线程队列中移除 handler.removeCallbacks(rb); Log.e(TAG, "end..."); } }); } }
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; /** * @作者: jiatao * @修改时间:2016-4-10 下午11:55:26 * @包名:com.cctvjiatao.handlerdemo * @文件名:SendMsgProgressbarAct.java * @版权声明:www.cctvjiatao.com * @功能: 例子中用到了handler的消息队列机制, * 即通过handler中一个线程向消息队列中用sendMessage方法发送消息,发送的消息当然可以用来传递参数。 * 在handler中用handleMessage来处理消息,处理方法是获得消息队列中的消息参数,用这些参数来完成另外一些功能。 */ public class SendMsgProgressbarAct extends Activity { private final String TAG = getClass().getSimpleName(); private ProgressBar pb_handler; private Button btn_start; //创建一个handler,内部完成处理消息方法 Handler handler = new Handler(){ public void handleMessage(Message msg) { Log.e(TAG, "sendMessage..."); //显示进度条 pb_handler.setProgress(msg.arg1); //重新把进程加入到进程队列中 handler.post(rb);//注释本行代码,观察变化 }; }; Runnable rb = new Runnable(){ int i = 0; public void run() { i += 10; //首先获得一个消息结构 Message msg = handler.obtainMessage(); //给消息结构的arg1参数赋值 msg.arg1 = i; //延时1s,java中的try+catch用来排错处理 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //把消息发送到消息队列中 handler.sendMessage(msg); Log.e(TAG, "sendMessage..."); if(i == 100){ //把线程从线程队列中移除 handler.removeCallbacks(rb); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_progressbar); initView(); } private void initView() { pb_handler = (ProgressBar) findViewById(R.id.pb_handler); btn_start = (Button) findViewById(R.id.btn_start); btn_start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { pb_handler.setVisibility(View.VISIBLE); //将线程接口立刻送到线程队列中 handler.post(rb); Log.e(TAG, "start..."); } }); } }
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; /** * @作者: jiatao * @修改时间:2016-4-10 下午11:55:26 * @包名:com.cctvjiatao.handlerdemo * @文件名:IsSameThreadAct.java * @版权声明:www.cctvjiatao.com * @功能: 验证仅使用handler的post方法是否处于同一个线程 * 例子PostDelayedAct和例子SendMsgProgressbarAct表面上看handler使用了post方法启动了runnbale, * 其实启动的线程和activity主线程是同一个线程,因为它只是运行了线程的run方法,而不是start方法。 */ public class IsSameThreadAct extends Activity { private final String TAG = getClass().getSimpleName(); //新建一个handler Handler handler = new Handler(); Runnable rb = new Runnable(){ public void run() { //打印新建线程信息 Log.e(TAG, "handler_id---->"+Thread.currentThread().getId()); Log.e(TAG, "handler_name---->"+Thread.currentThread().getName()); //延时10s,为了观察主界面中内容出现的时间 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //将runnable加载到handler的线程队列中去 handler.post(rb); /*Thread t = new Thread(rb); t.start();*/ setContentView(R.layout.act_postdelayed); //打印activtiy线程信息 Log.e(TAG, "activity_id---->"+Thread.currentThread().getId()); Log.e(TAG, "activity_name---->"+Thread.currentThread().getName()); } } /** * 结果说明这两个线程确实是同一线程,并且可以看出主界面中的文字大概过了10s才显示出来, * 因为语句setContentView(R.layout.activity_main);放在了handler的post启动语句后面, * 而handler绑定的线程中又延时了10s,所以同时也证明了只有是同一个线程才会出现这种情况。 */ /** * 如果把语句: * handler.post(rb); * 换成: * Thread t = new Thread(rb); * t.start(); * 其它的不变,则程序运行时主界面内容立刻就显示出来了,且打印日志为。。。 * 这两者都说明这样绑定的线程与它所在的activity线程就不是同一个线程了。 */
package com.cctvjiatao.handlerdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; /** * @作者: jiatao * @修改时间:2016-4-10 下午11:55:26 * @包名:com.cctvjiatao.handlerdemo * @文件名:SendMsgLooperAct.java * @版权声明:www.cctvjiatao.com * @功能: 学会使用怎样在新线程中处理消息的方法 * 1)这个例子将学会怎样不使用runnable来启动一个线程,而是用HandlerThread的looper来构造一个handler, * 然后该handler自己获得消息,并传递数据,然后又自己处理消息,当然这是在另一个线程中完成的。 * 2)消息结构中传递简单的整型可以采用它的参数arg1和arg2,或者传递一些小的其它数据, * 可以用它的object,该object可以是任意的对象。 * 当需要传送比较大的数据是,可以使用消息的setData方法,该方法需要传递一个Bundle的参数。 * Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已。 */ public class SendMsgLooperAct extends Activity { private final String TAG = getClass().getSimpleName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_postdelayed); Log.e(TAG, "activity_ID---->" + Thread.currentThread().getId()); Log.e(TAG, "activity_Name---->" + Thread.currentThread().getName()); // 新建一个HanderThread对象,该对象实现了用Looper来处理消息队列的功能 HandlerThread handler_thread = new HandlerThread("handler_thread"); handler_thread.start(); // MyHandler类是自己继承的一个类,这里采用hand_thread的Looper来初始化它 MyHandler my_handler = new MyHandler(handler_thread.getLooper()); // 获得一个消息msg Message msg = my_handler.obtainMessage(); // 采用Bundle保存数据,Bundle中存放的是键值对的map,只是它的键值类型和数据类型比较固定而已 Bundle b = new Bundle(); b.putString("whether", "晴天"); b.putInt("temperature", 34); msg.setData(b); // 将msg发送到自己的handler中,这里指的是my_handler,调用该handler的HandleMessage方法来处理该mug msg.sendToTarget(); } class MyHandler extends Handler { // 空的构造函数 public MyHandler() { } // 以Looper类型参数传递的函数,Looper为消息泵,不断循环的从消息队列中得到消息并处理, // 因此,每个消息队列都有一个Looper,因为Looper是已经封装好了的消息队列和消息循环的类 public MyHandler(Looper looper) { // 调用父类的构造函数 super(looper); } @Override public void handleMessage(Message msg) { Log.e(TAG, "Handler_ID---->" + Thread.currentThread().getId()); Log.e(TAG, "Handler_Name---->" + Thread.currentThread().getName()); // 将消息中的bundle数据取出来 Bundle b = msg.getData(); String whether = b.getString("whether"); int temperature = b.getInt("temperature"); Log.e(TAG, "Handler_ID---->" + "whether= " + whether + " ,temperature= " + temperature); } } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.cctvjiatao.handlerdemo.SendMsgAct" > <Button android:id="@+id/btn_variable" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="多变的按钮" /> </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tv_msg" android:layout_width="fill_parent" android:layout_height="400dip" android:text="@string/hello_world"/> <Button android:id="@+id/btn_start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="开始" /> <Button android:id="@+id/btn_end" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="结束" /> </LinearLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/btn_start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="开始" /> <ProgressBar android:id="@+id/pb_handler" style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent" android:layout_height="100dip" android:layout_alignParentTop="true" android:visibility="gone" /> </RelativeLayout>