Android开发App启动流程与消息机制详解

目录
  • 引言
  • 1、第一步了解 ThreadLocal
  • 2、App的启动流程
  • 3、Activity中创建Handler

引言

相信很多人对这个问题不陌生,但是大家回答的都比较简单,如谈到app启动流程有人就会是app的生命周期去了,谈到消息机制有人就会说looper循环消息进行分发,如果是面试可能面试官不会满意,今天我们搞一篇完善的源码解析来进行阐述上面的问题

1、第一步了解 ThreadLocal

什么是ThreadLocal呢,专业的来讲,ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据,是共享数据变量存储,通俗的来讲,就是保存每个线程的数据,肯定大家都没听懂,没事的,接下来我们通过代码来解释ThreadLocal的具体作用

首先看一个例子

public static void main(String[] args) throws InterruptedException {
        ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
            @Override
            protected String initialValue() {
                return "data--1";
            }
        };
        System.out.println("1主线程-->  "+threadLocal.get());
        Thread t1 = new Thread(()->{
        });
        t1.start();
        threadLocal.set("data--2");
        System.out.println("2主线程-->  "+threadLocal.get());
        Thread t2 = new Thread(()->{
            System.out.println("线程2--->  "+threadLocal.get());
        });
        t2.start();
        Thread t3 = new Thread(()->{
            threadLocal.set("data-->3");
            System.out.println("线程3--->  "+threadLocal.get());
        });
        t3.start();
        System.out.println("3主线程-->  "+threadLocal.get());
        Thread.sleep(1000);
    }

打印结果

1主线程-->  data--1
2主线程-->  data--2
线程2--->  data--1
3主线程-->  data--2
线程3--->  data-->3

从上面的例子我们可以看到,ThreadLocal保存一个String这个变量,这个变量初始化会有一个值,在接下来的线程种,每个线程都会拥有一个初始值,这个初始值在主线程中,一旦这个初始值发生改变,如果是在主线程种改变如进行set,则后面的子线程获取的都是这个改变后的值,但是如果子线程种也改变了这个值,则只在当前子线程种有此值 没其子线程还是获取的主线程种那个值,我们来简单画个图给大家

ThreadLocal种的三个重要方法

//默认情况下initialValue是返回为空的
    protected T initialValue() {
        return null;
    }
//在get的时候如果没有调用set方法  getMap(t);是返回为空的,所以,返回的是setInitialValue(),这些方法请看后面的介绍,而setInitialValue方法返回的其实就是初始值
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    //这个方法在在调用的时候实际上getMap(t)是为空的,所以就会调用createMap,这个方法会把当前的线程作为值,保证getMap再调用就不会为空
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
         public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
         ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
        void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

简单来讲,就是自己有的,用自己的,自己没有就用初始化的,初始化改变了,后面的也改变,但是自己设置的,还是用自己的,就这么简单,好了,接下来进行下一步

2、App的启动流程

我们看下Android的源码

//这是main函数的入口
 public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());
        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        Process.setArgV0("&lt;pre-initialized&gt;");
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

我们重点看下 Looper.prepareMainLooper();这个方法

 /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

我们再点击去看,myLooper

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

很惊讶的看见了 sThreadLocal,这里是调用get方法

  // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

这里我们可以看到ThreadLocal保存的是Looper这个对象

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

这里调用了set方法,创建了一个全局唯一的Looper

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

创建了一个全局唯一的主线程消息队列

3、Activity中创建Handler

  • 创建一个handler,重写handleMessage方法
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };
  • 发送消息
        Message message = new Message();
        handler.sendMessage(message);
	//点击去
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
	//点击去
	    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis &lt; 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
//继续看sendMessageAtTime
    public boolean sendMessageAtTime(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(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    //我们看到了enqueueMessage,我们看这个queue在哪里获取的
        public Handler(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());
            }
        }
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

到这里我们明白了,也就是再app启动后那个唯一的Queue,好了我们整理下Handler的消息机制

hander发送消息的时候,调用sendMessage方法,handler种会讲消息放到全局的消息队列中queue.enqueueMessage(msg, uptimeMillis)接着就会在MessageQueue种赋值全局消息

消息处理

消息消费

以上就是Android开发App启动流程与消息机制详解的详细内容,更多关于Android App启动流程消息机制的资料请关注我们其它相关文章!

(0)

相关推荐

  • 一文带你看懂Android Application启动流程是怎样的

    基于Android11-API30 总览 获取applicationThread,AMS这两个Binder2.attach时,将获取applicationThread对象也传递到AMS进程,请求远程调用通知AMS应用进程想要创建Application,此时AMS为服务端 AMS收到消息,请求调用applicationThread的远程接口,此时AMS为客户端 applicationThread收到AMS的请求,通过Handler发起创建Application的处理任务,后面就没有远程接口调用了

  • Android消息机制Handler用法总结

    1.简述 Handler消息机制主要包括: MessageQueue. Handler. Looper.Message. Message:需要传递的消息,可以传递数据: MessageQueue:消息队列,但是它的内部实现并不是用的队列,而是通过单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势.主要功能是向消息池投递消息( MessageQueue.enqueueMessage)和取走消息池的消息( MessageQueue.next).  Handler:消息辅助类,主要功能

  • android异步消息机制 从源码层面解析(2)

    AsyncTask 什么是AsyncTask AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和结果传递给主线程并在主线程中更新UI. AsyncTask这个类的声明如下 public abstract class AsyncTask<Params, Progress, Result> 它提供了Params, Progress和 Result三个泛型参数,在下面会仔细分析这三个泛型参数的具体含义. AsyncTask提供了四个核心方法 onPreExe

  • 掌握Android Handler消息机制核心代码

    目录 一.handler基本认识 1.基本组成 2.基本使用方法 3.工作流程 二.发送消息 三.消息进入消息队列 1.入队前的准备工作 2.将消息加入队列 四.从消息队列里取出消息 1.准备工作 2.loop中的操作 2.1 MessageQueue的next方法 五.消息的处理 六.其他关键点 1. Loop的创建 2.Handler的创建 3.Message的创建.回收和复用机制 4. IdleHandler 5.Handler在Framework层的应用 阅读前需要对handler有一些

  • android异步消息机制 源码层面彻底解析(1)

    Handler.Message.Loopler.MessageQueen 首先看一下我们平常使用Handler的一个最常见用法. Handler handler =new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //这里进行一些UI操作等处理 } new Thread(new Runnable() { @Override public void run() {

  • Android APP启动方式、启动流程及启动优化分析

    本文章向大家介绍Android app应用启动的一些相关知识,包括app启动方式.app启动流程和app启动优化等知识!  app应用启动方式 1.冷启动 当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动.冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量.布局.绘制),最后显示在界面上. 2.热启动 当启动应用时,后台已有该应用的进程(例:按

  • Android开发App启动流程与消息机制详解

    目录 引言 1.第一步了解 ThreadLocal 2.App的启动流程 3.Activity中创建Handler 引言 相信很多人对这个问题不陌生,但是大家回答的都比较简单,如谈到app启动流程有人就会是app的生命周期去了,谈到消息机制有人就会说looper循环消息进行分发,如果是面试可能面试官不会满意,今天我们搞一篇完善的源码解析来进行阐述上面的问题 1.第一步了解 ThreadLocal 什么是ThreadLocal呢,专业的来讲,ThreadLocal 是一个线程内部的数据存储类,通过

  • java开发分布式服务框架Dubbo原理机制详解

    目录 前言 Dubbo框架有以下部件 Consumer Provider Registry Monitor Container 架构 高可用性 框架设计 服务暴露过程 服务消费过程 前言 在介绍Dubbo之前先了解一下基本概念: Dubbo是一个RPC框架,RPC,即Remote Procedure Call(远程过程调用),相对的就是本地过程调用,在分布式架构之前的单体应用架构和垂直应用架构运用的都是本地过程调用.它允许程序调用另外一个地址空间(通常是网络共享的另外一台机器)的过程或函数,并且

  • Android开发高仿课程表的布局实例详解

    先说下这个demo,这是一个模仿课程表的布局文件,虽然我是个菜鸟,但我还是想留给学习的人一些例子,先看下效果 然后再来看一下我们学校的app 布局分析 先上一张划分好了的布局图 首先整个页面放在一个LinearLayout布局下面,分为上面和下面两个部分,下面一个是显示课程表的详细信息 1:这个没什么好讲的,就是直接一个LinearLayout布局,然后将控件一个TextView用来显示年份,一个View用来当作竖线,一个Spinner用来显示选择周数 2:这个是显示星期几的部件,是我自定义的V

  • Android开发基础实现音频文件的播放详解

    目录 前言 实现方法 最终效果 总结 前言 上一篇(安卓开发基础——实现最简单的视频播放我们简单的实现了一个播放视频的功能,这一节我们来实现App对音频文件的播放功能,本文主要是依靠MediaPlayer类去实现Android播放音乐的. 实现方法 和上一篇的播放功能实现类似,我们首先需要一个文件夹去放我们的音频文件,我们在main文件夹下新建一个assets文件夹放入我们的音频文件 然后我们在布局中添加一张图片,下面加上三个处理播放控制的按钮,播放,暂停(暂停播放),停止(正在播放就停止播放,

  • Android开发两个activity之间传值示例详解

    目录 使用Inten的putExtra传递 使用Intention的Bundle传递 使用Activity销毁时传递数据 SharedPreferences传递数据 使用序列化对象Seriazable 使用静态变量传递数据 handler 使用Inten的putExtra传递 第一个Activity中 //创建意图对象 Intent intent = new Intent(this,MainActivity2.class); //设置传递键值对 intent.putExtra("name&quo

  • iOS开发系列--通知与消息机制详解

    概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地通知:另一类是推送通知,也叫远程通知.两种通知在iOS中的表现一致,可以通过横幅或者弹出提醒两种形式告诉用户,并且点击通知可以会打开应用程序,但是实现原理却完全不同.今天就和大家一块去看一下如何在iOS中实现这两种机制,并且在文章后面会补充通知中心的内容避免初学者对两种概念的混淆. 本地通知 本地通

  • Android异步消息机制详解

    Android中的异步消息机制分为四个部分:Message.Handler.MessageQueue和Looper. 其中,Message是线程之间传递的消息,其what.arg1.arg2字段可以携带整型数据,obj字段可以携带一个Object对象. Handler是处理者,主要用于发送消息和处理消息.发送消息的方法是sendMessage:处理消息的方法是handleMessage(),Message字段携带的信息在该方法中用作判别. MessageQueue是消息队列,存放所有Handle

  • Android 消息机制详解及实例代码

    Android 消息机制 1.概述 Android应用启动时,会默认有一个主线程(UI线程),在这个线程中会关联一个消息队列(MessageQueue),所有的操作都会被封装成消息队列然后交给主线程处理.为了保证主线程不会退出,会将消息队列的操作放在一个死循环中,程序就相当于一直执行死循环,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数(handlerMessage),执行完成一个消息后则继续循环,若消息队列为空,线程则会阻塞等待.因此不会退出.如下图所示: Handl

  • Android开发使用Message对象分发必备知识点详解

    目录 Message的创建 消息分发执行的三种方式 总结 Message的创建 消息Message一般不支持大家直接通过new的方式进行创建的,因为Message作为Android系统中使用频率非常高的一个对象,如果每次都泛滥的直接创建一个新的,对性能是有一定影响的,而通过对象池的方式进行复用 ,则是非常好的一种方式. Message中就提供了这样的一个对象池(最大缓存消息数量为50): 通过链表的形式将一个个待复用的缓存Message连接起来.并且提供了obtain()方法负责从对象池中获取一

  • Android开发-之环境的搭建(图文详解)

    关于Android开发可以使用的工具有eclipse和Android studio等,这两个工具都各有各的好处和不足.studio是谷歌推出的一款开发工具,而我们都知道Android就是谷歌公司的,所以相对于eclipse来说会好一点推荐开发使用,但是大家都知道的Google在国内是被拦截的也就是说不可以去到官网下载studio.在大家学习之初呢推荐大家使用eclipse,在国内很多企业还是用的eclipse开发的.但是学习到后面呢大家也要掌握studio的开发.那么今天我就来说一下关于如何使用

随机推荐