Handler在android的学习当中应用是非常多的,我们就依次的来解决handler相关问题。其实在handler当中有很多问题比较难理解,比如我们在子线程中通过post的方法发送一条消息,然后就立即能够在handlemessage方法中接受到这条消息,在最初我们学习中都会比较困惑,那么今天我们通过handler的详细讲解,让大家了解handler的机制是什么,并且结合源码和大量的实例让大家更深的了解handler,通过今天的学习,相信大家对handler会有一定的掌握,handler对我们日后android的开发或者面试中都是非常重要的存在。
1. Handler是什么?
在我们学习一门技术和语言之前,一定要先了解以下这门技术和语言是什么,不要盲目的去学习,因为技术太多了,我们要把经历放在核心的技术当中。
Handler在我们android开发当中是一个非常重要的机制,那handler又是什么呢?handler是android提供用于更新ui的一套机制,也是消息处理的机制。
handler的主要作用有两个:
(1):在新启动的线程中发送信息。
(2):在主线程中获取,处理信息。
2. 为什么要是用handler?
如果我们不用handler去发送消息,更新ui可以么?
是不行的。 Android在设计的时候,就封装了一套消息创建,传递,处理机制,如果不遵循这样的机制,就没有办法更新ui信息的,就会抛出异常信息。
异常的描述:不能在非ui线程中去更新ui。
Only the original thread that created a view hierarchy can touch its views.
3.Handler怎么用呢?
想要了解handler怎么用,就需要去看一下api文档。
一个handler允许你发送和处理message和Runnable对象在相关联的MessageQueen。每个handler实例都与一个单独的线程绑定,该线程带有消息队列MessageQueen。当你创建一个新的handler时,它默认会绑定到创建线程的MessageQueen中,从这一点上,它将传递消息和runnable对象,在MessageQueen中执行这个消息。
Handler有两个主要用途:
1.合理调度安排消息和runnable对象,使它们在将来的某个点被执行。
2.将一个动作入队安排在非当前线程执行。
调度消息是通过一系列的post方法和sendMessage方法。
post方法允许你向消息队列中入队一些Runnable对象,在它们被接收到的时候会被调用.
sendMessage方法允许你入队一个消息对象(Message),包含一个bundle数据,之后将会被Handler的handleMessage(Message)方法所处理。
当为应用程序创建一个进程时,它的主线程专门负责运行一个消息队列,它负责管理顶级应用程序对象(活动、广播接收器等),以及它们所创建的任何窗口。您可以创建自己的线程,并通过一个处理程序与主应用程序线程进行通信。这是通过之前调用的post或SendMessage方法从新的线程。给定的runnable对象或消息将被安排在处理程序的消息队列,在适当时候进行处理。
实例一:handler的post基本用法
public class MainActivity extends Activity {
private TextView tv;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.tv);
new Thread(){
public void run() {
try {
Thread.sleep(2000);
handler.post(new Runnable() {
@Override
public void run() {
tv.setText("123456789");
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
实例二:仿照淘宝页面切换图片
布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/d_xiongmao" />
</RelativeLayout>
java逻辑代码:
package com.qf.handler_demo02;
import javax.crypto.spec.IvParameterSpec;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.view.Menu;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView img;
private int images[] = {R.drawable.d_xiongmao,R.drawable.d_xixi,R.drawable.d_xu,R.drawable.d_yinxian};
private int index = 0;
private Handler handler = new Handler();
private MyRunnable runnable = new MyRunnable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView)findViewById(R.id.img);
//每隔一秒,发送一条runnable对象。
handler.postDelayed(runnable, 1000);
}
class MyRunnable implements Runnable{
@Override
public void run() {
index++;
index=index%4;
img.setImageResource(images[index]);
handler.postDelayed(runnable, 1000);
}
}
}
实例三:显示倒计时效果
布局代码:
<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"
android:gravity="center" >
<TextView
android:id="@+id/tv_time"
android:layout_width="200dp"
android:layout_height="200dp"
android:textSize="60sp"
android:text="60"
android:gravity="center"/>
<ImageView
android:id="@+id/iv_time"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/d_doge"
android:visibility="gone"/>
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="stop"
android:text="停止倒计时" />
</LinearLayout>
java逻辑代码:
public class MainActivity extends Activity {
private ImageView iv;
private TextView tv;
private int times = 60; //定义一个最初的时间
private Handler handler = new Handler();
private MyRunnable runnable = new MyRunnable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.tv_time);
iv = (ImageView)findViewById(R.id.iv_time);
handler.postDelayed(runnable, 1000);
//一秒之后发送一条消息。
}
class MyRunnable implements Runnable{
@Override
public void run() {
times--; //每运行一次,当前的时间数就减去一;
tv.setText(times+""); //把时间设置在当前的textview中
if (times == 0){ //当时间等于0时,停止发送信息。
tv.setVisibility(View.GONE);
iv.setVisibility(View.VISIBLE);
}else { //否则继续发送信息
handler.postDelayed(runnable, 1000);
}
}
}
//移除正在调用的runnable对象
public void stop(View view){
handler.removeCallbacks(runnable);
}
}
以上三个例子是关于handler的post发送runnable对象的应用。
下面我们看一下关于handler是如何通过sendMessage发送信息。
首先给大家介绍一下Message的概念:
Message是线程之间传递信息的载体,包含了对消息的描述和任意的数据对象。
Message中包含了两个额外的 int字段和一个object字段,这样在大部分情况下,使用者就不需要再做内存分配工作了。
虽然Message的构造函数是public的,但是最好是使用Message.obtain( )或Handler.obtainMessage( )函数来获取Message对象,因为Message的实现中包含了回收再利用的机制,可以提供效率。
实例四:介绍message的arg1,arg2,obj字段
布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
逻辑代码:
public class Person {
String name;
int age;
String sex;
public Person() {
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
}
activity中的代码:
public class MainActivity extends Activity {
private TextView tv;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//能获取到msg.arg1和arg2的值。
tv.setText("msg.arg1:"+msg.arg1+"----msg.arg2="+msg.arg2);
//能够获取得到msg.obj当中的内容
tv.setText(msg.obj+"");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.tv);
new Thread(){
public void run() {
try {
Thread.sleep(2000);
//获得Message对象的三种方法
//1.new Message():使用构造方法
// Message msg = new Message();
//2.obtain方法,回收再利用的机制
// Message msg = Message.obtain();
//3.调用handler的obtainMessage方法,实质和obtain一样
Message msg = handler.obtainMessage();
msg.arg1 = 98;
msg.arg2 = 35;
Person person = new Person("jerry", 12, "男");
msg.obj = person;
handler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
以上代码能够看出由handler发送的信息,然后也由他自己来接受信息。这个就是handler对于消息处理的机制。同时当我们通过message.sendToTarget()的方法,也可以将信息发送给指定的handler对象。通过查看源码发现,还是调用了handler的sendMessage的方法。