上述就是android开发分享Android开发App启动流程与消息机制详解的全部内容,如果对大家有所用处且需要了解更多关于Android学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
引言
相信很多人对这个问题不陌生,但是大家回答的都比较简单,如谈到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("<pre-initialized>"); 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 < 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启动流程消息机制的资料请关注<计算机技术网(www.ctvol.com)!!>其它相关文章!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/addevelopment/1209183.html