Android 学习笔记 二十二 之Handler

Handler的定义:

主要接受子线程发送的数据,并用此数据配合主线程更新UI

解释:当应用程序第一次启动时,Android首先会开启一个主线程(Main Thread),主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所有主线程通常又被叫做UI线程。

Android的消息传递机制是另一种形式的”事件处理”,这种机制主要是为了解决Android应用的多线程问题--Android平台只允许UI线程修改Activity里的UI组件,这样就会导致新启动的线程无法动态改变界面组件的属性值。但在实际Android应用开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程周期性地改变界面组件的属性值,有三种方式可以实现。使用异步任务AsyncTaskAsyncTaskLoaderServiceBroadCast后台加载或者Handler来实现。

Handler类的两个作用:

1.MainThreadWorkerThread发送消息,让WorkerThread进行后台数据操作

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
 
public class HandlerActivity extends Activity {
//主线程向WorkerThread发送消息
private Handler handler;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
new MyThread().start();	 //开启WorkerThread
}
//简述Message MessageQueue Handler Loop  之间的关系
//主线程向WorkerThread发送消息:
//在WorkerThread中一开始需要添加Loop.prepare()   结束需要使用Loop.looper() 
//主线程中:WorkerThread向MainThread发送消息:
//系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就通过Handler来发送消息、处理消息
class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Looper.prepare();   //
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println(msg.arg1);
 
}
};
Looper.loop();	 //  只有在调用了Looper的prepare()方法和loop()方法之后才会去调用handleMessage(Message msg)方法
}
}
 
public void onBtnClick(View v) {
Message message = handler.obtainMessage(); 	 //创建消息对象
message.arg1 = 1;	 //设置消息的值
handler.sendMessage(message);	 //发送消息
}
 
}
 


2.WorkerThreadMainThread发送消息使主线程能够实时更新UI

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
 
public class Handler1Activity extends Activity {
private TextView tv;
private int count = 10;
private Handler handler;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler1);
tv = (TextView) findViewById(R.id.tv);
handler = new Handler();
}
 
public void onBtnClick(View v) {
new MyThread().start();
 
}
 
class CountThread implements Runnable {
 
@Override
public void run() {
 
tv.setText(count + "");
// Handler将一个WorkThread强制转换成了一个MainThread
System.out.println(Thread.currentThread().getName() + "count===>"
+ count);// .....主线程中更新UI
}
 
}
 
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 10 && count != 0; i++) {
try {
Thread.sleep(1000);
Message message = Message
.obtain(handler, new CountThread());
// handler.sendMessage(message);//每个1s执行一次CountThread,该线程在主线程中执行
handler.sendMessageDelayed(message, 5 * 1000);
// SystemClock.uptimeMillis() 当前系统毫秒数 +5*1000相当于延时五秒
// handler.sendMessageAtTime(message,
// SystemClock.uptimeMillis()+5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
}
}
}
}


 

Handler中分发消息的一些方法:

1.强制推送一个WorkerThread对象到主线程队列中,用于更新UI

post(Runnable ) //即时发送

postAtTime(Runnable,long)   //给定一个时间毫秒数。一般为当前系统时间毫秒数(SystemClock.uptimeMillis())加上一个偏移毫秒数.相当于延迟发送

postDelayed(Runnable,long)   //延迟发送,给定一个时间毫秒数。为当前系统时间向后偏移的偏移量。

2.允许安排一个带数据的Message对象到主线程队列中。

sendEmptyMessage(int) //发送一个空的消息

sendMessage(Message) //即时发送消息

sendMessageAtTime(Message,long) // //给定一个时间毫秒数。一般为当前系统时间毫秒数(SystemClock.uptimeMillis())加上一个偏移毫秒数.相当于延迟发送消息

sendMessageDelayed(Message,long)    延迟发送消息,给定一个时间毫秒数。为当前系统时间向后偏移的偏移量。

Message的实例化方法:

//使用Handler实现类调用obtainMessage()方法来实例化Message

Message msg = mHandler.obtainMessage();

//接收一个Handler实现类的对象,和一个用于更新UIWorkerThread

Message message =Message.obtain(handlernew CountThread());

例如:

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
 
public class Handler1Activity extends Activity {
private TextView tv;
private int count = 10;
private Handler handler;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler1);
tv = (TextView) findViewById(R.id.tv);
handler = new Handler();
}
 
public void onBtnClick(View v) {
new MyThread().start();
 
}
 
class CountThread implements Runnable {
 
@Override
public void run() {
 
tv.setText(count + "");
// Handler将一个WorkThread强制转换成了一个MainThread
System.out.println(Thread.currentThread().getName() + "count===>"
+ count);// .....主线程中更新UI
}
 
}
 
class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 10 && count != 0; i++) {
try {
Thread.sleep(1000);
Message message = Message
.obtain(handler, new CountThread());
// handler.sendMessage(message);//每个1s执行一次CountThread,该线程在主线程中执行
handler.sendMessageDelayed(message, 5 * 1000);
// SystemClock.uptimeMillis() 当前系统毫秒数 +5*1000相当于延时五秒
// handler.sendMessageAtTime(message,
// SystemClock.uptimeMillis()+5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
}
}
}
}


 

Handler处理消息的方法:

final boolean hasMessages(int what):检查消息队列中是否包含what属性为指定值的消息。

final boolean hasMessages(int what,Object object):检查消息队列中是否包含what属性为指定值且Object属性为指定对象的消息。

void handleMessage(Message msg) :处理消息的方法。需要子类进行重写。

 

 为了,更好的了解Handler的机制,我们应该首先,Android系统整个运行进程都要烂熟于心,下面是android 进程运行图:

 

从图中我们可以看到,当我们从外部调用组件的时候,Service 和 ContentProvider 是从线程池那里获取线程,Activity BroadcastReceiver是直接在主线程运行

 

因为,我们当我们的主线程队列,如果处理一个消息超过5,android 就会抛出一个 ANP(无响应)的消息,所以,我们需要把一些要处理比较长的消息,放在一个单独线程里面处理,把处理以后的结果,返回给主线程运行,就需要用的Handler来进行线程建的通信,关系如下图;


     

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值