您的位置:首页 > 移动开发 > Android开发

android handler学习

2016-08-17 16:56 477 查看

什么是handler

首先要理解安卓的UI操作不是线程安全的,这就是决定了一个子线程无法直接更新UI。我们的安卓应用启动时,首先启来的是我们看到的activity,这是一个UI主线程。

这个UI主线程有个问题,我们不能在这个线程里做一些太耗时的工作,这样的会使得看到的界面体验很卡。所以这样耗时的操作要放到子线程去做。但是前面讲到子线程又不能更新主线程中的UI,怎么办呢?handler就是用来处理这种情况的

当我们在子线程中完成了一个耗时的操作后,通过handler向主线程发送消息,主线程就更新UI显示。这个消息还可以传递一些数据。看个例子:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}

Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
Log.i(TAG, "got some message:" + b.getString("data"));
super.handleMessage(msg);
}
};

//线程类,这里发送通过handler发送消息给主线程(UI线程)
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.i(TAG, "this is a child thread running....");
Message msg = new Message();
//还可以带上一些数据
Bundle b = new Bundle();
b.putString("data", "test data");
msg.setData(b);

myHandler.sendMessage(msg);
}
}

程序很简单,主线程启动时开启一个子线程,子线程处理完事情(就是打印一


条调试信息)通过handler发送消息,主线程中的myHandler通过handleMessage可以接收到消息处理。程序输出:

I/MainActivity: this is a child thread running….

I/MainActivity: got some message:test data

控制消息类型

如果子线程中想要不同的状态发送不同的消息,该如何处理呢?也很简单,message对象有一些成员可以用:

Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what)
{
case 1:
Bundle b = msg.getData();
Log.i(TAG, "got some message:" + b.getString("data"));
break;
case 0:
break;
default:
break;
}
super.handleMessage(msg);
}
};

//线程类,这里发送通过handler发送消息给主线程(UI线程)
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.i(TAG, "this is a child thread running....");

Message msg = new Message();
if(true)
{
msg.what = 1;
}
else
{
msg.what = 0;
}

//还可以带上一些数据
Bundle b = new Bundle();
b.putString("data", "test data");
msg.setData(b);
myHandler.sendMessage(msg);
}
}


dispatchMessage与sendMessage区别

简单来讲,调用sendMessage会把Message对象放入一个MessageQueue队列,该队列属于某个Looper对象,个Looper对象属于主线程。Looper对象会不断的从这个消息队列中获取消息执行。而最终handler的执行是调用dispatchMessage方法。

从上面的描述可以提取如下几个信息:

1. sendMessage最终会调用dispatchMessage。

2. sendMessage发出的消息,handler处理时运行在主线程内(因为looper是主线程的),而dispatchMessage发出的消息,handler处理时运行子线程内的(因为相当于子线程直接调用)。

可以验证一下,把代码稍作修改:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Log.i(TAG, "main thread id:"+Thread.currentThread().getId());
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}

Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {

Log.i(TAG, "got some message by dispatchMessage:" + b.getString("data"));
Log.i(TAG, "handler thread:" + Thread.currentThread().getId());

super.handleMessage(msg);
}
};

//线程类,这里发送通过handler发送消息给主线程(UI线程)
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.i(TAG, "this is a child thread running....");
Log.i(TAG, "thread id:"+Thread.currentThread().getId());

Message msg = new Message();
myHandler.dispatchMessage(msg);
}
}


输出结果:

I/MainActivity: main thread id:1

I/MainActivity: this is a child thread running….

I/MainActivity: thread id:4264

I/MainActivity: got some message by dispatchMessage:test data

I/MainActivity: handler thread:4264

如果改成sendMessage,结果会看到handler thread id值为1。

obtainMessage什么时候用

把线程的处理函数修改下:

//线程类,这里发送通过handler发送消息给主线程(UI线程)
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.i(TAG, "this is a child thread running....");
Log.i(TAG, "thread id:"+Thread.currentThread().getId());

Message msg = myHandler.obtainMessage();
msg.sendToTarget();
}
}


发现运行结果其实是一样的,也就是说这种方法同样能达到在不同线程传递消息的效果,那么区别呢?

obtainmessage是从消息池中拿来一个msg,不需要另开辟空间,new需要重新申请,效率低,obtianmessage可以循环利用。

还有POST也可以说说

POST作用是通过handler把子线程加到主线程的处理队列中,看个示例:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Log.i(TAG, "main thread id:"+Thread.currentThread().getId());
MyThread thread = new MyThread();
myHandler.post(thread);

}

//线程类,这里发送通过handler发送消息给主线程(UI线程)
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

Log.i(TAG, "this is a child thread running....");
Log.i(TAG, "thread id:"+Thread.currentThread().getId());
}
}


输出:

I/MainActivity: main thread id:1

I/MainActivity: this is a child thread running….

I/MainActivity: thread id:1

运行结果很明显,子线程的id和主线程是一样的,说明确实在主线程中运行。post因为可以使子线程运行在主线程内,所以可以直接在run函数里直接更新UI
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: