本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Android架构进阶之深入理解AppStartup原理
追忆似水年华 · 310浏览 · 发布于2021-09-10 +关注

Android Startup提供一种在应用启动时能够更加简单、高效的方式来初始化组件。开发人员可以使用Android Startup来简化启动序列,并显式地设置初始化顺序与组件之间的依赖关系。

前言

Android Startup提供一种在应用启动时能够更加简单、高效的方式来初始化组件。开发人员可以使用Android Startup来简化启动序列,并显式地设置初始化顺序与组件之间的依赖关系;

今天我们就来聊聊

一、使用步骤简单介绍

使用 AndroidX App Startup 来运行所有依赖项的初始化有两种方式:

自动初始化;

手动初始化(也是延迟初始化);

1、自动初始化

在 build.gradle 文件内添加依赖;

implementation "androidx.startup:startup-runtime:1.0.0-alpha01"

    实现 Initializer 接口,并重写两个方法,来初始化组件;

    public class MvpInitializer implements Initializer<Void> { 
        @NonNull 
        @Override 
        public Void create(@NonNull Context context) { 
             MvpManager.init(context); 
             return null; 
        } 
        @NonNull 
        @Override 
        public List<Class<? extends Initializer<?>>> dependencies() { 
            return new ArrayList<>(); 
        } 
    } 
        ...... 
    }


      create(Context): 这里进行组件初始化工作;

      dependencies(): 返回需要初始化的列表,同时设置 App 启动时依赖库运行的顺序;

      在 AndroidManifest.xml 文件中注册 InitializationProvider;

      <application> 
              <provider 
                  android:authorities="${applicationId}.androidx-startup" 
                  android:name="androidx.startup.InitializationProvider" 
                  android:exported="false" 
                  tools:node="merge" > 
                <!-- 自动初始化 --> 
                  <meta-data android:name="com.test.Initializer" android:value="androidx.startup"/> 
          </provider> 
      </application>

       
      1. App 启动的时 App Startup 会读取 AndroidManifest.xml 文件里面的 InitializationProvider 下面的 声明要初始化的组件,完成自动初始化工作;

      2、手动初始化(也是延迟初始化)

      在 build.gradle 文件内添加依赖;

      创建一个类 LibaryD 实现 Initializer 接口,并重写两个方法,来初始化组件;

      在 AndroidManifest.xml 文件中注册 InitializationProvider

      <application> 
              <provider 
                  android:name="androidx.startup.InitializationProvider" 
                  android:authorities="${applicationId}.androidx-startup" 
                  android:exported="false" 
                  tools:node="merge"> 
                  <!-- 手动初始化(也是延迟初始化) --> 
                  <meta-data 
                      android:name="com.test.Initializer" 
                      android:value="androidx.startup" 
                      tools:node="remove" /> 
              </provider> 
          </application>

        • 只需要在 标签内添加 tools:node="remove" 清单合并工具会将它从清单文件中删除;

        • 在需要的地方进行初始化,调用以下代码进行初始化;

        • Initializer.getInstance(context).initializeComponent(Initializer::class.java);

        • 如果组件初始化之后,再次调用 AppInitializer.initializeComponent() 方法不会再次初始化;

        • 手动初始化(也是延迟初始化)是非常有用的,组件不需要在 App 启动时运行,只需要在需要它地方运行,可以减少 App 的启动时间,提高启动速度;

        二、源码分析

        1、InitializationProvider

        在AndroidManifest文件中配置的组件名必须为androidx.startup.InitializationProvider,现在我们来看这个类的源码;

        InitializationProvider.java 
        public final class InitializationProvider extends ContentProvider { 
            @Override 
            public boolean onCreate() { 
                Context context = getContext(); 
                if (context != null) { 
                    初始化 
                    AppInitializer.getInstance(context).discoverAndInitialize(); 
                } else { 
                    throw new StartupException("Context cannot be null"); 
                } 
                return true; 
            } 
            @Override 
            public Cursor query(...) { 
                throw new IllegalStateException("Not allowed."); 
            } 
            @Override 
            public String getType(...) { 
                throw new IllegalStateException("Not allowed."); 
            } 
            @Nullable 
            @Override 
            public Uri insert(...) { 
                throw new IllegalStateException("Not allowed."); 
            } 
            @Override 
            public int delete(...) { 
                throw new IllegalStateException("Not allowed."); 
            } 
            @Override 
            public int update(...) { 
                throw new IllegalStateException("Not allowed."); 
            } 
        }

          InitializationProvider其实也是利用了 ContentProvider 的启动机制,在ContentProvider#onCreate(...)中执行初始化;

          ContentProvider 的其他方法是没有意义的,所以都抛出了IllegalStateException;

          2、自动初始化分析

          App Startup 在 ContentProvider 中调用了AppInitializer#discoverAndInitialize()执行自动初始化;

          AppInitializer是 App StartUp 框架的核心类,整个 App Startup 框架的代码其实非常少,其中很大部分核心代码都在 AppInitializer 类中;

          2.1.AppInitializer.java discoverAndInitialize

          final Set<Class<? extends Initializer<?>>> mDiscovered; 
          void discoverAndInitialize() { 
              获取 androidx.startup.InitializationProvider 组件信息 
              ComponentName provider = new ComponentName(mContext.getPackageName(), InitializationProvider.class.getName()); 
              ProviderInfo providerInfo = mContext.getPackageManager().getProviderInfo(provider, GET_META_DATA); 
             androidx.startup 字符串 
              String startup = mContext.getString(R.string.androidx_startup); 
             获取组件信息中的 meta-data 数据 
              Bundle metadata = providerInfo.metaData; 
              遍历 meta-data 数据 
              if (metadata != null) { 
                  Set<Class<?>> initializing = new HashSet<>(); 
                  Set<String> keys = metadata.keySet(); 
                  for (String key : keys) { 
                      String value = metadata.getString(key, null); 
                    判断 meta-data 数据中,value 为 androidx.startup 的键值对 
                      if (startup.equals(value)) { 
                          Class<?> clazz = Class.forName(key); 
                           检查指定的类是 Initializer 接口的实现类 
                          if (Initializer.class.isAssignableFrom(clazz)) { 
                              Class<? extends Initializer<?>> component = (Class<? extends Initializer<?>>) clazz; 
                              将 Class 添加到 mDiscovered Set 中 
                              mDiscovered.add(component); 
                              初始化此组件 
                              doInitialize(component, initializing); 
                          } 
                      } 
                  } 
              } 
          } 
          mDiscovered 用于判断组件是否已经自动启动 
          public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) { 
              return mDiscovered.contains(component); 
          }

            • 获取androidx.startup.InitializationProvider组件信息(在各个 Module 中声明的组件信息,会在manifest merger tool的处理下合并);

            • androidx.startup字符串;

            • 获取组件信息中的 meta-data 数据;

            • 遍历 meta-data 数据;

            • 判断 meta-data 数据中,value 为 androidx.startup 的键值对;

            • 检查指定的类是 Initializer 接口的实现类;

            • 将 Class 添加到 mDiscovered Set 中,这将用于后续 判断组件是否已经自动启动;

            • 初始化此组件;

            2.2.AppInitializer.java AppInitializer.java

            private static final Object sLock = new Object(); 
            缓存每个组件的初始化结果; 
            final Map<Class<?>, Object> mInitialized; 
            初始化此组件 
            <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) { 
                对 sLock 加锁 
                Object result; 
              判断 initializing 中存在当前组件,说明存在循环依赖 
                if (initializing.contains(component)) { 
                    String message = String.format("Cannot initialize %s. Cycle detected.", component.getName()); 
                    throw new IllegalStateException(message); 
                } 
               检查当前组件是否已初始化 
                if (!mInitialized.containsKey(component)) { 
                    当前组件未初始化 
                    记录正在初始化 
                    initializing.add(component); 
                    通过反射实例化 Initializer 接口实现类 
                    Object instance = component.getDeclaredConstructor().newInstance(); 
                    Initializer<?> initializer = (Initializer<?>) instance; 
                   遍历所依赖的组件 
                    List<Class<? extends Initializer<?>>> dependencies = initializer.dependencies(); 
                    if (!dependencies.isEmpty()) { 
                        for (Class<? extends Initializer<?>> clazz : dependencies) { 
                            如果所依赖的组件未初始化,递归执行初始化 
                            if (!mInitialized.containsKey(clazz)) { 
                                doInitialize(clazz, initializing); 注意:这里将 initializing 作为参数传入 
                            } 
                        } 
                    } 
                   初始化当前组件      
              result = initializer.create(mContext); 
                   移除正在初始化记录 
                    initializing.remove(component); 
                    缓存初始化结果 
                    mInitialized.put(component, result); 
                } else { 
                    当前组件已经初始化,直接返回 
                    result = mInitialized.get(component); 
                } 
                 return (T) result; 
            }

              • 对 sLock 加锁;

              • 判断 initializing 中存在当前组件,说明存在循环依赖(这是因为递归初始化所依赖的组件时,会将 initializing 作为参数传入,如果 initializing 中存在当前组件,说明依赖关系形成回环,如果不抛出异常,将形成无限递归);

              • 检查当前组件是否已初始化;

              • 记录正在初始化;

              • 通过反射实例化 Initializer 接口实现类;

              • 遍历所依赖的组件,如果所依赖的组件未初始化,递归调用doInitialize(...)执行初始化;

              • 初始化当前组件;

              • 移除正在初始化记录;

              • 缓存初始化结果;

              3、手动初始化源码分析

              手动初始化(懒加载)的源码分析:

              AppInitializer.java 
              public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) { 
                  调用 doInitialize(...) 方法: 
                  return doInitialize(component, new HashSet<Class<?>>()); 
              }

                其实非常简单,就是调用上一节的doInitialize(...)执行初始化。需要注意的是,这个方法是允许在子线程调用的,换句话说,自动初始化与手动初始化是存在线程同步问题的,那么 App Startup 是如何解决的呢?

                前面有一个sLock没有说吗?其实它就是用来保证线程同步的锁:

                <T> T doInitialize(Class<? extends Initializer<?>> component, Set<Class<?>> initializing) { 
                   对 sLock 加锁 
                    synchronized (sLock) { 
                        ...  
                    } 
                }


                  总结

                  App Startup 是 Jetpack 的新成员,是为了解决因 App 启动时运行多个 ContentProvider 会增加 App 的启动时间的问题;

                  使用了一个 InitializationProvider 管理多个依赖项,消除了每个库单独使用 ContentProvider 成本,减少初始化时间;

                  App Startup 允许你自定义组件初始化顺序;

                  App Startup 提供了一种延迟初始化组件的方法,减少 App 初始化时间;


                  相关推荐

                  android下vulkan与opengles纹理互通

                  talkchan · 1179浏览 · 2020-11-23 10:37:39
                  Android 使用RecyclerView实现轮播图

                  奔跑的男人 · 2175浏览 · 2019-05-09 17:11:13
                  微软发布新命令行工具 Windows Terminal

                  吴振华 · 869浏览 · 2019-05-09 17:15:04
                  Facebook 停止屏蔽部分区块链广告

                  · 754浏览 · 2019-05-09 17:20:08
                  加载中

                  0评论

                  评论
                  分类专栏
                  小鸟云服务器
                  扫码进入手机网页