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