Android多线程

捋一遍比较重要的知识点···

UI线程与非UI线程

  • UI线程也俗称主线程,因为UI线程主要负责界面的刷新与管理,并且onKeyDown()这样的系统回调也都在UI线程中(主线程)中被执行。不能在其他线程对UI进行操作。
  • ActivityThread这个类就是主线程的类,里面的Main()方法就是主线程入口。
  • 主线程中创建 Handler 时不用 papare Looper,因为在主线程中系统默认创建了 Looper,它在不停地调度分发消息,因此四大组件的调度、我们的输入事件、绘制请求才能得到处理。
  • 在UI线程中不能做一些阻塞线程的操作(网络请求等),会引起ANR。阻塞它的后果是很严重的,可能需要加班。。

举个代码例子

	//主线程和其他线程通过handler传递消息
    Handler mHandler = new Handler() {
    	//接收到其他线程发过来的消息
        @Override
        public void handleMessage(@NonNull Message msg) {
        //what判断是哪里来的消息
            switch (msg.what) {
                case 888:
                    Bitmap bitmap = (Bitmap) msg.obj;
                    imageView.setImageBitmap(bitmap);
                    break;
            }
            super.handleMessage(msg);
        }
    };

    private void requstBitmap() {
		//启动新的线程做网络操作
        final Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
				//随便照一张网络图片
                String urlStr = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1586353267485&di=27e4c85d938fe922d47e8baacae986ee&imgtype=0&src=http%3A%2F%2Fdingyue.nosdn.127.net%2FE53Ia6av3P5yTY6QiweHTg19T6KIKfSk5UwBsRPMuqVg%3D1528903463421.jpg";
                try {
                    URL url = new URL(urlStr);
                    URLConnection urlConnection = url.openConnection();
                    InputStream inputStream = urlConnection.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
					//通知主线程做ui更新
                    Message message = new Message();
                    message.what = 888;
                    message.obj = bitmap;
                    mHandler.sendMessage(message);

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        };

        thread.run();
    }

相关的组件及其关联

具体作用

Handler

发送消息和处理消息,一般是重写handleMessage方法进行消息处理。Handler 所做的就是 “线程切换”。

Message

一条消息里面有各种属性。记录几个常用的属性:

  • what:消息来源
  • when:消息的处理时间,可以是现在或者是将来的某个时间
  • arg:如果只有简单的int型数据,可以直接用arg1、arg2参数存储
  • obj:传递一个Object对象,这个在Messenger跨进程通信中传递数据(我没用过),一般场景都是用bundle
  • bundle:也是存数据的
  • replyTo:负责回复消息的 Messenger,有的场景下(比如接受者、发送者模型)需要使用它
  • handle:当前与之关联的handle
  • flags:当前这条消息的状态,判断是否处理、是否正在处理、是否回收等状态
  • sPool:回收消息链表,简单来说就是消息被回收的时候,如果sPool存在就从复用消息链表头部取一个消息赋值给它,然后重置它的标志位;如果不存在复用消息链表就新建一个消息

MessageQueue

消息队列,可以添加删除一些消息,就是存放消息的容器。MessageQueue虽然叫“消息队列”,但它里面的mMessages持有的其实是一个消息链表的节点。

Looper

一个轮询装置,接收到Handler发送过来的消息,然后塞到MessageQueue中。等到消息要处理的时候又从队列中取出消息(如果队列没有退出,并且有消息存在,那么这个步骤是一直循环的)。线程中默认没有 Looper,我们需要调用 Looper.prepare() 方法为当前线程创建一个 Looper,然后就可以调用 loop() 方法调度消息。

工作原理

为什么要使用Message机制

主要是为了保证线程之间操作安全,同时不需要关心具体的消息接收者,使消息本身和线程剥离开,这样就可以方便的实现定时、异步等操作。

大致步骤

每一个Handler对应一个线程,每个Handler内都有一个Looper,每个Looper和一个queue关联。实现Message机制需要Handler、Message、Looper三个之间的互相作用来实现:

  1. handler创建一个消息,让消息进入队列
  2. 如果消息队列没有退出,并且有消息存在,那么looper就一直查询messageQueue取出能够处理的消息(源码中判断when规定的处理时间)
  3. 从queue中拿到消息后,拿给handler处理

在这里插入图片描述

HandlerThread

为了避免 ANR,我们常常需要在线程中做耗时操作,然后把结果抛到主线程进行处理。Android 提供了多种用于这种场景的组件,HandlerThread就是其中之一。不要问为什么用它而不用上面的一大串,系统封装好的东西,总是比上面的好用。HandlerThread 就是为了帮我们免去写上面那样的代码而生的。

  • 官方介绍:HandlerThread 是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler。

大致原理

HandlerThread继承了Thread,所以在star的时候调用了run方法,在run中又调用了Looper的prepare,我们要做的就是在子类中重写 onLooperPrepared,做一些初始化工作。

使用场景

在子线程中执行耗时的、可能有多个任务的操作的时候。
这里有实例

IntentService

IntentService 是一个抽象类,继承了 Service 。

  • 由于是一个 Service,IntentService 的优先级比较高,在后台不会轻易被系统杀死;它可以接收 Intent 请求,然后在子线程中按顺序执行。
  • 官方介绍:IntentService 使用工作线程逐一处理所有启动请求。如果你不需要在 Service 中执行并发任务,IntentService 是最好的选择。
  • IntentService 中除了 onHandleIntent 方法其他都是运行在主线程的
  • IntentService 也是 Service,需要在 AndroidManifest 中注册

大致原理

  • 创建了一个 HandlerThread 默认的工作线程
  • 使用 HandlerThread 的 Looper 创建了一个 Handler,这个 Handler 执行在子线程
  • 在 onStartCommand() 中调用 onStart(),然后在 onStart() 中将 intent 和 startId 以消息的形式发送到 Handler
  • 在 Handler 中将消息队列中的 Intent 按顺序传递给 onHandleIntent() 方法
  • 在处理完所有启动请求后自动停止服务,不需要我们调用 stopSelf()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值