Android Handler 的必修课一

程序之美

在这里插入图片描述

前言

handler 一個人們熟知的词汇,做Android开发的小伙伴们肯定真的是再熟悉不过了,Handler 是一个消息分发对象。handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理机制,我们可以发消息,也可以通过它处理消息。

handler 的作用

1、解决多线程更新UI
举个例子来说就,如下图所示:

package com.example.handlerdemo;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView tvInfo;

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

        tvInfo = findViewById(R.id.tvShow);
        tvInfo.setText("我是主线程");

        ShowThread showThread = new ShowThread();
        showThread.start();
    }

    class ShowThread extends Thread{
        @Override
        public void run() {
            super.run();
            tvInfo.setText("我是子线程");
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

运行结果:
在这里插入图片描述
运行成功了,这个能说明子线程可以更新UI么?
我们进一步验证一下:
修改代码如下,我们加入了一个Button,按钮触发更新TextView,如下:

package com.example.handlerdemo;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView tvInfo;
    private Button btnClick;

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

        tvInfo = findViewById(R.id.tvShow);
        tvInfo.setText("我是主线程");

        btnClick = findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ShowThread showThread = new ShowThread();
                showThread.start();
            }
        });
    }

    class ShowThread extends Thread{
        @Override
        public void run() {
            super.run();
            tvInfo.setText("我是子线程");
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

发现点击 button 后 textview 的内容实际上发生了更改的,然后程序崩溃了。抛出如下异常:


AndroidRuntime: FATAL EXCEPTION: Thread-176
                     Process: com.example.handlerdemo, PID: 11201
                     android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
                              at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357)
                              at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:874)

由上可知,子线程是不可以更新UI的,为什么子线程中不能更新UI,这是因为在子线程中更新UI不是线程安全的,在Android源码ViewRootImpl的checkThread方法中也对UI做了验证。

void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

那么handler的原理是什么呢?
下面我们就说下Handler 的原理。

Handler的原理

1、handler封装消息的发送体(主要包括消息接受者,消息内容等)
2、Looper——消息封装的载体。(1)内部包含一个MessageQueue,所有的Handler发送的消息都会进入到这个消息队列;(2)Looper.Looper方法,就是一个死循环,不停地从MessageQueue获取消息,如果有消息便处理消息,没有消息就阻塞等待。
3、MessageQueue,一个消息队列,存储消息的容器,可以实现添加消息,便于处理消息
4、handler内部与Looper相关联,在handler内部可以找到Looper,handler->Looper->MessageQueue,handler发送消息就是向MessageQueue队列发送消息。
总结:handler负责发送消息,Looper负责接收handler发送的消息,并把消息回传给handler的接收者。

handler 用法

1、post(Runnable);
2、postDelayed(Runnable ,long);
3、sentMessage
4、sentMessageDelayed

这里就不详细介绍了,就说下,小伙伴们一定都知道,post和send的用法,post是异步的消息发送,send是同步的消息发送。细心的小伙伴一定可以发现,post和postDelayed内部都是一个线程Runnable,所以会开启一个线程执行任务。所以它是异步的,不阻塞队列的。因为异步,所以任务不会马上执行,排入消息队列,由系统调度执行。而sendMessage是同步的,调用则会马上执行。

结束语

好了,今天就先介绍个大概吧,小伙伴们可以先了解下,有条件的小伙伴可以实践下相关的handler的用法,体验下他们的用处和差异,后续我会进一步展开,进一步深入讲解handler的运行机制。也希望小伙伴们能够多提宝贵建议,共同进步,共同成长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值