android源码怎么运行(android项目实例源码)
2022-01-12 18:30:05

Android消息机制其实指的就是Handler的消息机制。

Android消息机制,以及handler源码分析

以上模型的解释:

1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。

2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。

3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。 这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler, Message, MessageQueue,Looper。

ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。

我们看下ThreadLocal是如何存储数据的:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
在源码里面我们可以看出  ThreadLocal在存储数据的时候,会先拿到当前线程,然后根据当前线程会拿到一个叫做ThreadLocalMap 的Map数组;

那么ThreadLocalMap 又是什么呢?

我们可以看到在CreateMap 里面是创建了ThreadLocalMap ,并且把我们当前线程当作Key,传递过去的 Value就是我们在调用ThreadLocal.set(T)传过来的值

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

Android消息机制,以及handler源码分析

ThreadLocal是如何获取数据的

   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
//会先根据当前线程找到对应的ThreadLocalMap,如果没有就创建
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
//如果ThreadLocalMap 就会去创建ThreadLocalMap
   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;
    }
Android消息机制,以及handler源码分析

通过以上代码我们可以看出ThreadLocal是如何保证数据存储以后,只有再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据的了。

我们如何保证Acticity的默认线程是主线程的呢

在Acticity 中我们用到的线程是ActivityThread这个线程,在这个线程的

main(String[] args)方法里面我们可以看到下面代码
  public static void main(String[] args) {

        Looper.prepareMainLooper();


        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
Android消息机制,以及handler源码分析

//上面的代码里面我们可以看到创建 ActivityThread的 Looper.prepareMainLooper(); Looper.loop(); 保证了 ActivityThread为主线程。

创建全局唯一Looper对象和全局唯一MessageQueue消息对象

Android消息机制,以及handler源码分析

Activity中创建Handler

Android消息机制,以及handler源码分析

Android消息机制,以及handler源码分析

消息发送

Android消息机制,以及handler源码分析
Android消息机制,以及handler源码分析

消息处理

Android消息机制,以及handler源码分析
Android消息机制,以及handler源码分析

消息阻塞和延时

Looper 的阻塞主要是靠 MessageQueue 来实现的,在next()@MessageQuese 进行阻塞,在 enqueueMessage()@MessageQueue 进行唤醒。主要依赖 native 层的 Looper 依靠 epoll 机制进行的。

  Message next() {
     
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
//阻塞和延时,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)调用naive方法操作管道
            nativePollOnce(ptr, nextPollTimeoutMillis);

        }
 }
Android消息机制,以及handler源码分析

阻塞和延时,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)调用naive方法操作管道,由nextPollTimeoutMillis决定是否需要阻塞nextPollTimeoutMillis为0的时候表示不阻塞,为-1的时候表示一直阻塞直到被唤醒,其他时间表示延时。

唤醒

主要是指enqueueMessage()@MessageQueue 进行唤醒。

    boolean enqueueMessage(Message msg, long when) {
  //在这里唤醒阻塞的方法
            if (needWake) {
                nativeWake(mPtr);
            }
        
    }
Android消息机制,以及handler源码分析

简单理解阻塞和唤醒 就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。 这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。 从阻塞到唤醒,消息切换

Android消息机制,以及handler源码分析

延时入队

Android消息机制,以及handler源码分析

主要指enqueueMessage()消息入列是,上图代码对message对象池的重新排序,遵循规则(when从小到大)。 此处for死循环退出情况分两种 第一种:p==null表示对象池中已经运行到了最后一个,无需再循环。 第二种:碰到下一个消息when小于前一个,立马推出循环(不管对象池中所有message是否遍历完),进行重新排序。

Android消息机制其实指的就是Handler的消息机制。

Android消息机制,以及handler源码分析

以上模型的解释:

1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。

2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。

3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。 这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler, Message, MessageQueue,Looper。

ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。

我们看下ThreadLocal是如何存储数据的:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
在源码里面我们可以看出  ThreadLocal在存储数据的时候,会先拿到当前线程,然后根据当前线程会拿到一个叫做ThreadLocalMap 的Map数组;

那么ThreadLocalMap 又是什么呢?

我们可以看到在CreateMap 里面是创建了ThreadLocalMap ,并且把我们当前线程当作Key,传递过去的 Value就是我们在调用ThreadLocal.set(T)传过来的值

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

Android消息机制,以及handler源码分析

ThreadLocal是如何获取数据的

   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
//会先根据当前线程找到对应的ThreadLocalMap,如果没有就创建
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
//如果ThreadLocalMap 就会去创建ThreadLocalMap
   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;
    }
Android消息机制,以及handler源码分析

通过以上代码我们可以看出ThreadLocal是如何保证数据存储以后,只有再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据的了。

我们如何保证Acticity的默认线程是主线程的呢

在Acticity 中我们用到的线程是ActivityThread这个线程,在这个线程的

main(String[] args)方法里面我们可以看到下面代码
  public static void main(String[] args) {

        Looper.prepareMainLooper();


        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
Android消息机制,以及handler源码分析

//上面的代码里面我们可以看到创建 ActivityThread的 Looper.prepareMainLooper(); Looper.loop(); 保证了 ActivityThread为主线程。

创建全局唯一Looper对象和全局唯一MessageQueue消息对象

Android消息机制,以及handler源码分析

Activity中创建Handler

Android消息机制,以及handler源码分析

Android消息机制,以及handler源码分析

消息发送

Android消息机制,以及handler源码分析
Android消息机制,以及handler源码分析

消息处理

Android消息机制,以及handler源码分析
Android消息机制,以及handler源码分析

消息阻塞和延时

Looper 的阻塞主要是靠 MessageQueue 来实现的,在next()@MessageQuese 进行阻塞,在 enqueueMessage()@MessageQueue 进行唤醒。主要依赖 native 层的 Looper 依靠 epoll 机制进行的。

  Message next() {
     
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
//阻塞和延时,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)调用naive方法操作管道
            nativePollOnce(ptr, nextPollTimeoutMillis);

        }
 }
Android消息机制,以及handler源码分析

阻塞和延时,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)调用naive方法操作管道,由nextPollTimeoutMillis决定是否需要阻塞nextPollTimeoutMillis为0的时候表示不阻塞,为-1的时候表示一直阻塞直到被唤醒,其他时间表示延时。

唤醒

主要是指enqueueMessage()@MessageQueue 进行唤醒。

    boolean enqueueMessage(Message msg, long when) {
  //在这里唤醒阻塞的方法
            if (needWake) {
                nativeWake(mPtr);
            }
        
    }
Android消息机制,以及handler源码分析

简单理解阻塞和唤醒 就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。 这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。 从阻塞到唤醒,消息切换

Android消息机制,以及handler源码分析

延时入队

Android消息机制,以及handler源码分析

主要指enqueueMessage()消息入列是,上图代码对message对象池的重新排序,遵循规则(when从小到大)。 此处for死循环退出情况分两种 第一种:p==null表示对象池中已经运行到了最后一个,无需再循环。 第二种:碰到下一个消息when小于前一个,立马推出循环(不管对象池中所有message是否遍历完),进行重新排序。

未解决
您可能还需要
天天领红包,单单有红包
android状态栏透明代码(android设置状态栏颜色)
android日期选择器全屏显示(js日历插件日期选择器)
2020结婚证照片要求,最新结婚登记全攻略
河小象联系方式是什么?
「必看报告」华帝i11134和i11116的区别哪个性价比高、质量更好
阿里邮箱网盘如何预览文件?
通过钉钉企业应用网关访问时会导致访问时延增加吗_
项目群没有群汇报插件吗?
钉邮邮件可以导出吗?
我领到的券为什么和同事不一样(员工优惠天天领)?
app初期怎么推广有效,推广app的方法及经验分享
app初期上线该怎么做,谷歌应用商店刷排名方法
app创业要考虑的因素有哪些,最热创业app平台推荐
app创业步骤有哪些,最热创业app软件推荐
app内容运营是做什么的,内容运营岗位职责
app内容营销模式有哪些,做好营销推广的9大手段
app关键词排名怎么优化(分享app关键词优化方)
app关键词排名怎么优化(4种优化方法及注意事项)
app做广告怎么收费(app打广告的收费及3大流程)
app优化的内容及策略(最值推荐的5大策略)
app优化方案,快速提高app应用市场排名的五个方法
app付费推广渠道有哪些(常用的7种推广渠道)
app付费推广有哪些形式,五种app付费推广方法
app产品运营模式有哪些(附淘客app的4种运营模式)
app产品运营模式有哪些(浅谈这5大运营模式)
app产品设计的思路和方法(全面了解app产品设计)
app产品设计包括哪些方面(app产品设计最核心的5大方面)
app产品经理需要的技能(必须掌握的5项技能)
app产品经理做什么(必须具备的13个基本职责)
app产品经理主要做什么(最主要的6大工作职责)
正在加载...