【Android】App通信基础架构相关类源码解析

news/2024/7/7 5:30:14 标签: android, java, handler, looper, thread, 通信

应用通信基础架构相关类源码解析

这里主要对Android App开发时,常用到的一些通信基础类进行一下源码的简单分析,包括:

  • Handler:处理器,与某个Looper(一个线程对应一个Looper)进行关联。用于接收消息,并在关联的Looper,处理消息。
  • Looper:驱动器,驱动基于事件的消息系统(通信架构的核心)其实现在Native层,基于epoll机制(感兴趣的可自行了解)。
  • Runnable: 表示“可执行的代码”,本质是Interface,规定了Run这个接口。
  • MessageQueue: 消息队列,提供了入队、出队等操作。一个线程,只能有一个MessageQueue。
  • Thread: 线程类,封装了线程相关操作。

基于Android12代码。

类图:
在这里插入图片描述

Handler

常见用法

java">private Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
		// 处理消息
    }
};

private void sendMessage() {
    // 发送消息
    Message msg = mHandler.obtainMessage();
	// 填充msg
    mHandler.sendMessage(msg);
}

private void postRunnable() {
	// 告知Handler一段可执行的代码(Runnable)
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            // do something
        }
    });
}

通过上述代码中,可以看出。创建Handler时需要绑定Looper,也就是绑定到运行的线程上。如过不指定looper,使用创建handler时所在线程的Looper。
源码定义在 frameworks/base/core/java/android/os/Handler.java

java">public Handler() {
    this(null, false);
}

public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

public Handler(@Nullable Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

	// 获取当前线程对应的Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 使用Looper中的MessageQueue
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

调用Handler的sendMessage,到Handler处理(handleMessage)这个Message。Handler会将这个Message,入队到绑定的Looper的MessageQueue(消息队列中)。

java">public final boolean sendMessage(@NonNull Message msg) {
	 // 没有延时 
     return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    // 记录一下UID
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 消息入队MessageQueue
    return queue.enqueueMessage(msg, uptimeMillis);
}

Looper从MessageQueue中依次取出Message,并告知Handler的handleMessage处理消息(想要看懂looper,涉及到其Native实现,这里不分析,可自行了解)

Looper

Looper类基于epoll机制,提供了一套事件驱动机制。Java层的实现在frameworks/base/core/java/android/os/Looper.java,该类中的sMainLooper变量存储了 主线程(或者叫UI线程)对应的Looper,可以通过getMainLooper取得。

java">public final class Looper {
    private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
    // 省略
    public static Looper getMainLooper() {
       synchronized (Looper.class) {
           return sMainLooper;
       }
   }
}

常见的用法,比如在自定义的线程中。

java">public class MyThread extends Thread {  
  
    private Handler mHandler;  
  
    @Override  
    public void run() {  
        Looper.prepare(); // 准备Looper  
  
        mHandler = new Handler() {  
            @Override  
            public void handleMessage(Message msg) {  
                // 处理消息  
                }  
            }  
        };  
  
        Looper.loop(); // 开始循环,等待消息  
    }
}

Looper的实现这里就不分析了,路径在**/frameworks/base/core/java/android/os/Looper.java**,可自行了解(建议先掌握epoll)

Thread

Android Thread类提供线程功能,其定义在 libcore/ojluni/src/main/java/java/lang/Thread.java

java">public
class Thread implements Runnable {
   public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
}

调用start方法,可以启动线程,比如上面定义的MyThread类。

java">MyThread thr = new MyThread();
thr.start();

其提供了一些方法,用于控制线程,比如

  • sleep: 让线程等待一段时间
  • jion:等待线程退出(或者叫执行完成)
  • interrupt:打断线程。

注意:Thread和Looper是两个事情,其关系是一对一。 Thread就是常规意义上的线程,程序代码最小的运行单位(先不考虑协程),Looper是一套基于消息(事件)的驱动机制。

Runnable是一个接口类,规定了Run这个方法。MessageQueue是一个消息队列。这个类功能比较单一。其源码路径如下,感兴趣的可自行了解。

再贴一遍类图,加深理解。
在这里插入图片描述


http://www.niftyadmin.cn/n/5471888.html

相关文章

Kali Linux汉化教程

以下是Kali Linux的汉化教程&#xff1a; 打开终端&#xff0c;并切换为root用户。可以使用命令“sudo su root”来切换到root用户。 更新源。使用命令“apt-get update”来更新系统的软件包列表。 安装中文字体。可以使用命令“apt install ttf-wqy-zenhei”来安装中文字体。…

MSF(Metasploit Framework)详细介绍及用法【新手篇】

简介 Metasploit Framework 简称MSF&#xff0c;是一款开源的安全漏洞检测工具。可以收集信息、探测系统漏洞、执行漏洞利用测试等&#xff0c;为渗透测试、攻击编码和漏洞研究提供了一个可靠平台&#xff0c;集成数千个漏洞利用、辅助测试模块 核心组件 msfconsole&#xf…

Git入门实战教程之创建版本库

一、Git简介 Git是一个分布式版本控制系&#xff0c;分层结构如下&#xff1a; Git分为四层&#xff1a; 1、工作目录 当前正在工作的项目的实际文件目录&#xff0c;我们执行命令git init时所在的地方&#xff0c;也就是我们执行一切文件操作的地方。 2、暂存区 暂存区是…

训练营十六天(二叉树part03)

104.二叉树的最大深度 力扣题目链接(opens new window) 题目 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&…

Django - 视图和模板

视图 视图 - 是具体的业务代码 在 app 下的 views.py 文件中编写代码 from django.http import HttpResponsedef index(request):return HttpResponse("这里是我的站点")为了调用该视图&#xff0c;我们还需要编写urlconf&#xff0c;也就是路由配置。在polls目录中…

SketchUp Pro 2024 for mac 草图大师 专业的3D建模软件

SketchUp Pro 2024 for Mac是一款功能强大的三维建模软件&#xff0c;适用于Mac电脑。其简洁易用的界面和强大的工具集使得用户可以轻松创建复杂的3D模型。 软件下载&#xff1a;SketchUp Pro 2024 for mac v24.0.483 激活版下载 SketchUp Pro 2024 for Mac支持导入和导出多种文…

控制器通过Profinet转Modbus网关接压力计的案例

由于现场控制器无法正常连接压力计&#xff0c;咨询了解后我们通过使用兴达易控的Profinet转Modbus网关把连接压力计和控制器&#xff0c;顺利连接并通讯上&#xff0c;实现Modbus协议与Profinet协议之间的数据转换和传输&#xff0c;使得压力计能够无缝集成到基于Profinet的工…

蓝桥杯第十一届c++大学B组详解

目录 1.字符串排序 2.门牌制作 3.即约分数 4.蛇型填数 5.跑步锻炼 6.七段码 7.成绩统计 8.回文日期 9.字串分值和 10.平面切分 1.字符串排序 题目解析&#xff1a;这个题目真没搞懂。有会的大佬教我一下谢谢。 2.门牌制作 题目解析&#xff1a;出过超级多这类题目&am…