Handler
跟应用程序交互的,从网络上取得图片,怎么更新我们UI上面呢?
这里就用到了Handler机制,如何不用直接从子线程给予一个图片更新到UI当中,会得到calss异常,不能在非Ui线程中直接更新UI。
标题内容:
handler是什么
handler怎么用呢
为什么要用handler
handler的原理是什么
如何实现一个线程相关的Handler
HandlerThread又是什么呢
如何在主线程给子线程发送消息呢
android 中更新UI的几种方式
非UI线程真的不能更新UI吗
使用handler时候遇到的问题
android为什么要设计只能用过Handler机制更新UI呢
1、handler是什么
handler是android给我们提供用来更新UI的一套机制,也是一套消息处理机制,我们可以发送消息,也可以通过它处理消息
所有的activity生命周期的回调方法,都是通过Handler机制去发送消息。
fragment 的 activity的生命周期,大多数都是用AMS做处理。
2、为什么要用handler , 不用行不行?
是不行的。
Android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不循环这样的机制的就没有办法更新UI信息的,就会抛出异常信息(不能在一个非UI线程当中,去直接更新UI)。
3、handler怎么用呢?
来看看官网文档:国内文档(无翻墙) 国外文档(已经翻墙)
在Handler当中有两个用途:
(1)定时的去发送一个Messges 或 runnables对象
(2)可以在线程当中处理并执行一个动作
举例:
sendMessags
MainActivity----这里我举例了,一个两秒后更新内容,利用常常我们需要JSON解析,返回来的东西,更新UI
import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.TextView; public class MainActivity extends Activity { private TextView textView; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg){ //从子线程中更新一个文本信息 textView.setText(""+msg.obj); }; }; //常常Json解析当中拿的数据比较多,是同过这样的方法更新的 class Person{ public int age; public String name; public String toString(){ return "age"+age+"name"+name; } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textview); new Thread(){ public void run(){ try { Thread.sleep(2000); //发送Message Message message = handler.obtainMessage(); Person pSource = new Person(); pSource.age = 23; pSource.name = "yiyiyiyi"; message.obj = pSource; //将数据发送出去方法一: // handler.sendMessage(message); //方法二: message.sendToTarget(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }.start(); } }
sendMessagsDelayed
post(Runnable)
MainActivity ------这里我举了,利用Handler中的post(Runnable)
package com.example.handler_01; import android.os.Bundle; import android.os.Handler; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity { private TextView textView;//activity_main---布局只要定义一个id private Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //找到ID textView = (TextView) findViewById(R.id.textview); //线程 new Thread(){ public void run(){ try { //延迟两秒后更新 Thread.sleep(2000); //使用Handler中的post (Runnable)方法 handler.post(new Runnable() { public void run() { textView.setText("update thread"); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } }
postDelayed(Runnable,long)
MainActivity-----为了体现出这个,这里是,每2秒从线程中更换图片
import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.ImageView; public class MainActivity extends Activity { private ImageView imageView;//定义一个图片id而已 private Handler handler = new Handler(); //建一个图片数组 private int images[] = {R.drawable.image1,R.drawable.image2,R.drawable.image3}; //创建一个数,为了了解图片在当前位置 private int index; //定义runnable private MyRunnable myRunnable = new MyRunnable(); class MyRunnable implements Runnable{ @Override public void run() { index++; index = index%3;//让它在3张图片中不断循环 imageView.setImageResource(images[index]);//把当前图片应用到图片当中 //第一要求传入Runnable对象-----第二个是,时间。多久执行一次 handler.postDelayed(myRunnable, 1500); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView1); //需要在主线程当中调用 handler.postDelayed(myRunnable, 1500); } }
4、android为什么要设计只能用过Handler机制更新UI呢
最根本的目的就是解决多线程并发问题。
假如如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,那么会产生什么样子的问题?
更新界面错乱
如果对更新UI的操作都进行加锁处理的话又会产生什么样子的问题?
性能下降
处于对以上目的问题的考虑,android 给我们提供了一套更新UI的Handler机制,我们只需遵循这样Handler的机制就可以了。
根本不用去关心多线程问题,所以的更新UI的操作,都是在主线程的消息队列当中去轮询处理的
----所以官方给我们提供这个是有道理的----
5、handler的原理是什么
一、Handler封装了消息的发送,(主要包括消息发送给谁)
Looper---消息封装的载体
1.内部包含一个消息队列就是MessageQueue,所有的Handler发送的消息都走这个消息队列。
2.Looper.Looper方法,就是一个死循环,不断的从MessageQueue取消息,如有有消息就
处理消息,没有消息就阻塞
二、MessageQueue,就是一个消息队列,可以添加消息,并处理消息
三、Handler也很简单,内部会跟Looper进行关联,也就是说在Handler内部可以找到Looper,找到了Looper也就是找到了,MessageQueue,在Handler 中发送消息,其实就是向
MessageQueue队列中发送消息
总结:handler负责发送消息,Looper负责接收Handler 发送的消息,并直接把消息回传给Handler自己,
MessageQueue就是一个存储消息的容器。
6、如何实现一个线程相关的Handler
import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.widget.TextView; public class MainActivity extends Activity { private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { System.out.println("Ui-------"+Thread.currentThread()); }; }; class MyThread extends Thread { public Handler handler; public void run() { Looper.prepare(); handler = new Handler(){ public void handleMessage(android.os.Message msg){ System.out.println("currentTherad:"+Thread.currentThread()); }; }; Looper.loop();//循环 } } private MyThread thread; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = new TextView(this); textView.setText("hello handler"); setContentView(textView); thread = new MyThread(); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } thread.handler.sendEmptyMessage(1); handler.sendEmptyMessage(1); } }
7、HandlerThread又是什么呢
这里我是参考慕课网的:点击打开链接(下载的)
8、如何在主线程给子线程发送消息呢--主线程与子线程之间的信息交互
9、android 中更新UI的几种方式
常见的大概有四种:runOnUiThread、handler post、handler sendMessage、view post
import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.TextView; public class FiveActivity extends Activity { // 只是在布局布置一个 TextView private TextView textView; // 通过Handler来更新一下UI Handler handler = new Handler() { // 实现一下Handler里面的handleMessage方法 public void handleMessage(android.os.Message msg) { // 第二个方法是从外边拿到数据然后返回到里面 textView.setText("第二种方法handlerEmptyMessags"); } }; /** * 第一方法 Handler post */ public void handler1() { handler.post(new Runnable() { @Override public void run() { // 这里弄个文本消息 textView.setText("第一种方法Handler post"); } }); } /** * 第二种方法 sendEmptyMessage */ public void handler2() { handler.sendEmptyMessage(1); } /** * 第三种方法 runOnUiThread */ public void handler3() { runOnUiThread(new Runnable() { @Override public void run() { textView.setText("第三个方方法runOnUiThread"); } }); } /** * 第四种方法view * post----它会判断当前是不是UI线程,默认情况下,会通过Handler.post发送一个action。如果是UI线程的话执行run()方法 */ public void handler4() { textView.post(new Runnable() { @Override public void run() { textView.setText("第四种方法 view post"); } }); } protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); // 将布局,引用到这个类---因为为了方便我弄多了一个类 setContentView(R.layout.five); // 找到ID textView = (TextView) findViewById(R.id.textview); // 更新UI 创建一个线程,后台处理。 new Thread() { // 实现线程Thread 中的run方法 public void run() { try { //休息两秒后再执行,因为本地网络速递较快,为了看效果。如果网络的话就去掉 Thread.sleep(2000); // handler1(); // handler2(); // handler3(); handler4(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }.start(); } }
总结:其实这常见的四种方式来更新UI都差不多,都是同Handler来更新,只是代码上的本质而已。
10、非UI线程真的不能更新UI吗
可以的。但是不推荐这样,有些时候会进行报错
例子:举例子,是上面的9、的方法
new Thread() { // 实现线程Thread 中的run方法 public void run() { // try { // //休息两秒后再执行,因为本地网络速递较快,为了看效果。如果网络的话就去掉 // Thread.sleep(2000); // textView.setText("第几种方法");//这个时候是成功的 //如果将代码休眠2秒--注释去掉---,将报错,因为系统会认为失败,直接返回错误,不能在UI线程中更新UI // // handler1(); // // handler2(); // // handler3(); // // handler4(); // // } catch (InterruptedException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } }; }.start();
11、使用handler时候遇到的问题
android.view.ViewRootImpl$CalledFromWrongThreadExcetion:Only the original thread that created a view hierarchy can touch its views.
----不能在子 线程中更新Ui----()
不懂请分析源码:
Can't create handler inside thread that has not called Looper.prepare()
----原因:我们在子线程创建一个Handler当中,在程序运行的时候called 了。----
当创建Handler handler = new Handler()时候没有关联handler(也就是创建不使用),就会出现。
不懂的话看看源码,因为从源码当中了解到,从Looper.myLooper对象中拿到对象,当拿不到的时候就会出现这样的问题。
总结:所以当你创建一个Handler handler = new Handler();时,handler需要用到,不然就会出错,没有拿到Looper对象,就是等于空null的。不指定,就不给你使用Handler 机制。
转载自:http://blog.csdn.net/a873282620/article/details/53308593