这篇文章主要为大家介绍了Android开发App启动流程与消息机制详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
引言
相信很多人对这个问题不陌生,但是大家回答的都比较简单,如谈到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启动流程消息机制的资料请关注编程学习网其它相关文章!
本文标题为:Android开发App启动流程与消息机制详解
基础教程推荐
- Flutter进阶之实现动画效果(三) 2022-10-28
- iOS中如何判断当前网络环境是2G/3G/4G/5G/WiFi 2023-06-18
- MVVMLight项目Model View结构及全局视图模型注入器 2023-05-07
- Android实现短信验证码输入框 2023-04-29
- Android Compose自定义TextField实现自定义的输入框 2023-05-13
- iOS开发 全机型适配解决方法 2023-01-14
- Android开发Compose集成高德地图实例 2023-06-15
- iOS Crash常规跟踪方法及Bugly集成运用详细介绍 2023-01-18
- IOS获取系统相册中照片的示例代码 2023-01-03
- iOS开发使用XML解析网络数据 2022-11-12