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启动流程消息机制的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读

    阿虎医考电脑版|阿虎医考app免费版

    阿虎医考电脑版|阿虎医考app免费版,,阿虎医考app免费版历年实践技能通过率在60%左右,并且每年呈下降趋势。也就是说,实践技能的考试越来越难

    如何免费注册appid

    如何免费注册appid,右下角,应用程序,如何免费注册appid1.打开Appstore2.任意点开一个免费应用程序,并点击下载。3.从弹出的对话框中,选择“

    抢购手机 逸享生活APP下载抢购手机

    抢购手机 逸享生活APP下载抢购手机,抢购手机,自从华为荣耀系列从华为独立出来,荣耀手机的关注度与日俱增,华为商城也像小米一样成了广大网友

    扇贝新闻电脑版|扇贝新闻app

    扇贝新闻电脑版|扇贝新闻app,,1. 扇贝新闻app扇贝单词好。笔者没有用过这款英语学习软件,但当年的经济学老师为我们推荐了此款英语学习软件

    小米理财app|小米理财定期可靠吗

    小米理财app|小米理财定期可靠吗,,小米理财app我觉得小米金融理财还是很不错的,我自己在里面就放了一点钱而已。我觉得还是很靠谱的呀! 小米

    apple电脑键盘快捷键|苹果快捷键键盘

    apple电脑键盘快捷键|苹果快捷键键盘,,1. 苹果快捷键键盘具体步骤如下:1、先点击苹果电脑左上角的苹果标记,选择“系统偏好设置”2、然后选

    appdata是什么文件夹可以删除

    appdata是什么文件夹可以删除,文件夹,文件,本文目录appdata是什么文件夹可以删除windows7里面的appdata可以删除吗appdata文件夹有什么用