handler是什么?
handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。在android的framework中Activity的生命周期中的处理函数都是系统通过handler消息处理回调的。
为什么要用handler?
android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没有办法更新UI信息,就会抛出异常。android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
handler怎么用呢?
1、利用handler.post(Runnable)方法实现在异步线程更新UI,本身这个函数是在主线程被调用
2、 //利用handler实现定时刷新
3、//利用Callback类实现对发来的信息的拦截
4、//利用handler的sendMessage(Message)来从子线程发送消息给主线程
5、//移除handler中的Runnable
demo代码:
package com.example.handler; import android.os.Bundle; import android.os.Handler; import android.os.Handler.Callback; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.os.Message; public class MainActivity extends Activity implements OnClickListener{ private TextView textView; private ImageView imageView; private Button button; private int[] image = {R.drawable.img1, R.drawable.img2, R.drawable.img3}; private int index=0; //利用handler实现定时刷新 Handler handler = new Handler(); MyRunnable myRunnable = new MyRunnable(); class MyRunnable implements Runnable { @Override public void run() { // TODO Auto-generated method stub imageView.setImageResource(image[index]); index++; index %= image.length; //实现定时刷新(每隔2秒刷新一次) handler.postDelayed(myRunnable, 2000); } } //利用Handler处理子线程发来的消息来更新UI Handler handler1 = new Handler() { @Override public void handleMessage(Message msg) { textView.setText("" + msg.arg1 + "-" + msg.arg2 + " " + msg.obj.toString()); } }; class Person { public String name; public int age; @Override public String toString() { // TODO Auto-generated method stub return "name=" + name + " " + "age=" + age; } } //利用Callback类实现对发来的信息的拦截 private Handler handler2 = new Handler(new Callback() { @Override public boolean handleMessage(Message arg0) { // TODO Auto-generated method stub Toast.makeText(getApplicationContext(), "信息拦截", 3000).show(); //当返回值为false时不对信息进行拦截,为true时拦截Message信息, //handler的handleMessage就接受不到信息了 return true; } }){ //@Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "信息未被拦截", 3000).show(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView1); imageView = (ImageView) findViewById(R.id.imageView1); button = (Button) findViewById(R.id.button1); button.setOnClickListener(this); // 利用 handler.post(Runnable)方法实现在异步线程更新UI,本身这个函数是在主线程被调用 // new Thread() { // public void run() { // try { // Thread.sleep(1000); // handler.post(new Runnable() { // public void run() { // textView.setText("你好。。。"); // } // }); // // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // // } // }.start(); // 利用handler的postDelayed(Runnable,time)实现每个time时间对图片的刷新 new Thread() { public void run() { //实现定时刷新(每隔2秒刷新一次) handler.postDelayed(myRunnable, 2000); } }.start(); //利用handler的sendMessage(Message)来从子线程发送消息给主线程 new Thread() { public void run() { Message msg = new Message(); //msg 对象也可以利用以下语句创建 //Message msg = handler1.obtainMessage(); //利用msg.sndToTarget();发送该消息给对应的handler msg.arg1 = 8; msg.arg2 = 10; Person person = new Person(); person.name = "tom"; person.age = 19; msg.obj = person; handler1.sendMessage(msg); } }.start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void onClick(View arg0) { // TODO Auto-generated method stub //移除handler中的Runnable(本利用停止图片定时刷新) //handler.removeCallbacks(myRunnable); //发送一个空消息 handler2.sendEmptyMessage(1); } }
android为什么要设计只能通过Handler机制更新UI?
最根本的目的就是解决对线程并发问题,
假如在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,那么会产生什么样的问题呢?
更新界面错乱
如果对更新UI的操作都进行加锁处理的话又会产生什么样子的问题?
性能下降
出于对以上目的问题的考虑,android给我们提供了一套更新UI的机制(Handler处理机制),我们只需要知道遵循这样的机制就可以了。
根本不用去关心多线程问题,所以更新UI的操作,都是在主线程的消息队列当中去轮询处理的。
在线程中使用Handler
demo代码
package com.example.handler; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.TextView; public class SecondActivity extends Activity { private Handler handler1 = new Handler() { public void handleMessage(Message msg) { System.out.print("UI----->" + Thread.currentThread()); } }; //实现一个与线程相关的Handler class MyThread extends Thread { public Handler handler; public Looper looper; @Override public void run() { // TODO Auto-generated method stub Looper.prepare();//创建Looper对象 looper = Looper.myLooper(); handler = new Handler() { public void handleMessage(Message msg) { System.out.println("currentThread" + Thread.currentThread()); } }; //死循环,不断取出消息队列中的消息,并交给Handler处理 Looper.loop(); } } private MyThread thread; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setText("你好。。"); setContentView(textView); thread = new MyThread(); thread.start(); // try { // Thread.sleep(500); // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } //thread.handler.sendEmptyMessage(1); //handler1.sendEmptyMessage(1); //把handler和相应的线程绑定(这样会因为线程同步问题导致空指针异常) //可以通过HandlerThread来实现外部Handler和线程的绑定(详见ThreadActivity) Handler handler = new Handler(thread.looper) { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub System.out.println("Thread---->" + Thread.currentThread()); } }; handler.sendEmptyMessage(1); } }利用HandlerThread实现Handler通过Looper实现和子线程的关联
demo代码:
package com.example.handler; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.widget.Button; import android.widget.TextView; public class ThreeActivity extends Activity { /** * 利用HandlerThread实现Handler通过Looper实现 * 和子线程的关联 */ private HandlerThread thread; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setText("你好。。"); setContentView(textView); thread = new HandlerThread("handler thread"); thread.start(); handler = new Handler(thread.getLooper()) { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub System.out.println("Thread--->" + Thread.currentThread()); } }; handler.sendEmptyMessage(1); } }
demo代码
package com.example.handler; import android.app.Activity; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class CommThreadActivity extends Activity implements OnClickListener { private Button button1; private Button button2; //定义一个子线程的Handler private Handler threadHandler; //创建主线程的Handler private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { System.out.println(msg.arg1); Message message = new Message(); message.arg1 = 2; //向子线程发送消息 threadHandler.sendMessageDelayed(message, 1000); } }; @Override protected void onCreate(android.os.Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button1 = (Button) findViewById(R.id.button1); button2 = (Button) findViewById(R.id.button2); button1.setOnClickListener(this); button2.setOnClickListener(this); //利用HandlerThread创建子线程 HandlerThread thread = new HandlerThread("thread handler"); thread.start(); //子线程的Handler threadHandler = new Handler(thread.getLooper()) { @Override public void handleMessage(Message msg) { System.out.println(msg.arg1); Message message = new Message(); message.arg1 = 1; //向主线程发送消息 handler.sendMessageDelayed(message, 1000); }; }; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()) { case R.id.button1: //向主线程发送一个消息 handler.sendEmptyMessage(1); break; case R.id.button2: //移除一个消息 handler.removeMessages(1); break; } } }
1、利用Handler的post方法
2、利用Handler的sendMessage方法
3、利用Activity的runOnUiThread方法
4、利用View的post方法
demo 代码:
package com.example.handler; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.TextView; public class UpdateUIActivity extends Activity { private TextView textView; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { textView.setText("你好。。"); }; }; //利用handler的post()函数更新UI public void update1() { handler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub textView.setText("你好。。"); } }); } //利用handler的sengMessage更新UI public void update2() { handler.sendEmptyMessage(1); } //Activity自己提供的在子线程中更新UI public void update3() { runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub textView.setText("你好。。"); } }); } //利用View提供的子线程更新UI的方法 public void update4() { textView.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub textView.setText("你好。。"); } }); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.updateui); textView = (TextView) findViewById(R.id.textView1); new Thread() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //更新UI update1(); } }.start(); }; }
Handler常出现的异常有
1、android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.ViewRootImp对象初始化后在子线程中更新UI。
2、在子线程中handler传入Looper对象时(线程同步导致的)