android面试 handler,Android面试常客Handler详解

一、什么是Handler

Handler是Android提供的用来更新UI的一套机制,也是一套消息处理机制,我们可以通过它发送消息,也可以通过它处理消息。

二、为什么要使用Handler

Android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没有办法更新UI信息,就会抛出异常。

三、怎么使用Handler

在非UI线程借助Handler.post(Runnable)更新UI

public class MainActivity extends AppCompatActivity {

private Handler handler = new Handler();

private TextView textView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

textView = (TextView) findViewById(R.id.textView);

new Thread(){

@Override

public void run() {

handler.post(new Runnable() {

@Override

public void run() {

textView.setText("Hello Handler");

}

});

}

}.start();

}

}

借助Handler.postDelay(Runnable, DelayTime)定时执行相关动作

public class MainActivity extends AppCompatActivity {

private Handler handler = new Handler();

private MyRunnable runnable = new MyRunnable();

private class MyRunnable implements Runnable{

@Override

public void run() {

// 执行动作

handler.postDelayed(runnable, 1000);

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

handler.postDelayed(runnable, 1000);

}

}

自定义Handler和Message实现自己的操作处理

public class MainActivity extends AppCompatActivity {

private Handler handler = new Handler(){

@Override

public void handleMessage(Message msg) {

switch (msg.what){ // 判断消息类型

// 根据消息类型对消息进行处理

// 可以接收 msg.arg1 , msg.arg2 , msg.obj

}

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new Thread(){

@Override

public void run() {

Message message = new Message();

// 设置message传递参数

message.what = 0;

message.arg1 = 0;

message.arg2 = 0;

message.obj = null;

// 发送消息

handler.sendMessage(message);

// 或

// message.setTarget(handler);

// message.sendToTarget();

}

}.start();

}

}

ps:Handler消息拦截(不接收消息)

public class MainActivity extends AppCompatActivity {

private Handler handler = new Handler(new Callback(){

@Override

public boolean handleMessage(Message msg) {

return true; // 设置true拦截消息

}

}){

@Override

public void handleMessage(Message msg) {

switch (msg.what){ // 判断消息类型

// 根据消息类型对消息进行处理

// 可以接收 msg.arg1 , msg.arg2 , msg.obj

}

}

};

}

四、为什么Android要设计只能通过Handler机制更新UI?

最根本的目的就是解决多线程并发问题

假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,那么会产生什么样的问题?(更新界面错乱)如果对更新UI的操作都进行加锁处理,又会产生什么样的问题?(性能下降)

基于对以上目的的考虑,android给我们提供了一套更新UI的机制,我们只需遵循这样的机制,无需考虑多线程问题。

五、Handler的原理是什么?

Handler封装了消息的发送:内部会跟Looper关联

Looper(消息封装的载体):内部包含一个消息队列(MessageQueue),所有Handler发送的消息都会走向这个消息队列;Looper.Looper方法是一个死循环,不断的从MessageQueue取消息,如果有消息就处理消息,没有消息就阻塞

MessageQueue(消息队列):可以添加消息,并处理消息

总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己(handleMessage),MessageQueue就是一个存储消息的容器。

dc1e66ce7c70

Handler原理图解

六、Handler异步消息处理(HandlerThread)

这里只简单讲一下使用方法,想要仔细了解可以看一下这篇博文

Android HandlerThread 完全解析

public class MainActivity extends AppCompatActivity {

private Handler handler;

private HandlerThread thread;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

thread = new HandlerThread("Handler Thread");

thread.start();

handler = new Handler(thread.getLooper()){

@Override

public void handleMessage(Message msg) {

// 处理耗时操作

}

};

handler.sendEmptyMessage(1);

}

}

七、非UI线程真的不能更新UI吗?

相信大家在日常开发中可能会遇到这种情况:

以下代码运行时抛出异常

public class MainActivity extends Activity {

private TextView tvText;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tvText = (TextView) findViewById(R.id.main_tv);

new Thread(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

tvText.setText("OtherThread");

}

}).start();

}

}

以下代码运行正常

public class MainActivity extends Activity {

private TextView tvText;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tvText = (TextView) findViewById(R.id.main_tv);

new Thread(new Runnable() {

@Override

public void run() {

tvText.setText("OtherThread");

}

}).start();

}

}

一脸懵逼了吧,两部分代码的区别就是是否执行了Thread.sleep(200),追究原因,我们会发现其实在每个View的操作时都会执行ViewRootImpl的成员方法checkThread(),如果更新UI的当前线程不是主线程,则会抛出异常。

那么这里第二部分没有抛出异常是因为在setText操作是在onCreate里面进行的,然后在onResume方法被执行后我们的ViewRootImpl才会被生成,所以并未执行相应的checkThread()操作,而当进程执行sleep操作后,ViewRootImpl已经被创建完毕,故执行checkThread(),然后抛出异常

详细原因可阅读:为什么我们可以在非UI线程中更新UI —— AlgeStudio

哈哈,Handler的基础知识介绍就到这里了,希望对大家有所帮助。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值