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

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

上述就是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,则后面的子线程获取的都是这个改变后的值,但是如果子线程种也改变了这个值,则只在当前子线程种有此值 没其子线程还是获取的主线程种那个值,我们来简单画个图给大家

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

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开发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

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

  • 创建一个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的消息机制

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

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

消息处理

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

消息消费

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

以上就是android开发app启动流程与消息机制详解的详细内容,更多关于android app启动流程消息机制的资料请关注<计算机技术网(www.ctvol.com)!!>其它相关文章!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/1209183.html

(0)
上一篇 2022年8月30日
下一篇 2022年8月30日

精彩推荐