JetPack之AppStartUp原理分析


对于冷启动的App,我们知道其启动过程中,ContentProvidor是先于Applycation初始化的,在Android 10的源码中可以验证:

	//ActivityThread.java
    private void handleBindApplication(AppBindData data) {
    		//初始化ContentProvidor
            if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers);
                }
            }
			//初始化Applycation
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {}
	}

如果一个App定义了多个ContentProvider,也会遍历ContentProvider列表,循环初始化:

private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }
    }

因此,如果一个App中定义了多个ContentProvider的话,就会影响冷启动的速度。AppStartUp正是为了解决多个ContentProvidor造成的冷启动时间长的问题,基本使用参考官方文档,其原理是使用系统的InitializationProvider来汇总所有的需要在其他ContentProvidor初始化的任务,其初始化方式有:

  1. 自动初始化;
  2. 主动初始化。

1. 自动初始化源码分析

AppStartUp所有功能的入口是InitializationProvider类的onCreate()函数:

//InitializationProvider.java
public boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            AppInitializer.getInstance(context).discoverAndInitialize();
        } else {
            throw new StartupException("Context cannot be null");
        }
        return true;
    }

所有的自动初始化功能是AppInitializer单例的discoverAndInitialize()方法完成的:

void discoverAndInitialize() {
        try {
            ComponentName provider = new ComponentName(mContext.getPackageName(),
                    InitializationProvider.class.getName());
            ProviderInfo providerInfo = mContext.getPackageManager()
                    .getProviderInfo(provider, GET_META_DATA);
            Bundle metadata = providerInfo.metaData;
            String startup = mContext.getString(R.string.androidx_startup);
            if (metadata != null) {
                Set<Class<?>> initializing = new HashSet<>();
                Set<String> keys = metadata.keySet();
               // 可以定义多个<meta-data>标签,每个标签中name不相同,value却是相同的
                for (String key : keys) {
                    String value = metadata.getString(key, null);
                    //value必须等于"androidx.startup"
                    if (startup.equals(value)) {
                        Class<?> clazz = Class.forName(key);
                        if (Initializer.class.isAssignableFrom(clazz)) {
                            Class<? extends Initializer<?>> component =
                                    (Class<? extends Initializer<?>>) clazz;
                            doInitialize(component, initializing);
                        }
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {}
    }

这段代码就是根据解析的Manifest.xml文件中的<providor>标签下的<meta-data>的信息,来初始化metaData中name指定的类的,具体初始化每个Initializer子类的函数是doInitialize(),该函数也是主动初始化时调用的函数,在看这个函数的逻辑之前先看一下<meta-data>的定义:

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

2. 主动初始化源码分析

假如我们想要在某个时机初始化某个类库的初始化类LibaryY,当然LibaryY是继承Initializer的,可以调用一下代码:

AppInitializer.getInstance(applicationContext)
                .initializeComponent(LibaryY::class.java)

先看一下LibaryY的定义:

class LibaryY : Initializer<LibaryY.Dependency> {
    override fun create(context: Context): Dependency {
        return Dependency()
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
        return mutableListOf()
    }

    companion object {
        private const val TAG = "LibaryY";
    }

    class Dependency {
        init {
            initializer = true
        }
        companion object {
            var initializer: Boolean = false
        }
    }
}

Dependency内部类是用来包装初始化的代码的,dependencies()函数是用来添加其他的依赖的Initializer,初始化本类前会先初始化dependencies()函数中添加的的Initializer。下面看一下initializeComponent()函数的逻辑:

	public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
	       return doInitialize(component, new HashSet<Class<?>>());
	   }

    <T> T doInitialize(
            @NonNull Class<? extends Initializer<?>> component,
            @NonNull Set<Class<?>> initializing) {
        synchronized (sLock) {
            boolean isTracingEnabled = Trace.isEnabled();
            try {
                if (isTracingEnabled) {
                    // Use the simpleName here because section names would get too big otherwise.
                    Trace.beginSection(component.getSimpleName());
                }
                if (initializing.contains(component)) {
                    String message = String.format(
                            "Cannot initialize %s. Cycle detected.", component.getName()
                    );
                    throw new IllegalStateException(message);
                }
                Object result;
                if (!mInitialized.containsKey(component)) {
                    initializing.add(component);
                    try {
                        Object instance = component.getDeclaredConstructor().newInstance();
                        Initializer<?> initializer = (Initializer<?>) instance;
                        List<Class<? extends Initializer<?>>> dependencies =
                                initializer.dependencies();
						//先初始化dependencies中的所有Initializer
                        if (!dependencies.isEmpty()) {
                            for (Class<? extends Initializer<?>> clazz : dependencies) {
                                if (!mInitialized.containsKey(clazz)) {
                                    doInitialize(clazz, initializing);
                                }
                            }
                        }
                        //再调用本Initializer的create()来执行本Initializer需要初始化的内容
                        result = initializer.create(mContext);
                        initializing.remove(component);
                        mInitialized.put(component, result);
                    } catch (Throwable throwable) {
                        throw new StartupException(throwable);
                    }
                } else {
                    result = mInitialized.get(component);
                }
                return (T) result;
            } finally {
                Trace.endSection();
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Jetpack Compose 的 mutableStateOf 和 REMEMBER 都是用于管理组件状态的工具。 mutableStateOf 是一个函数,它返回一个可变的状态对象。当状态对象发生变化时,Compose 会重新绘制相关的组件,以便更新 UI。这种方式类似于 React 中的 useState hook。mutableStateOf 的原理是,它会创建一个包含状态值的对象,并将其与 Compose 中的当前组件关联起来。当状态值发生变化时,Compose 会通知相关的组件进行重新绘制。 REMEMBER 是一个类似于 mutableStateOf 的函数,但它更加灵活,可以用于保存和管理任何类型的数据。REMEMBER 的原理是,它会创建一个包含初始值的变量,并将其与 Compose 中的当前组件关联起来。当变量的值发生变化时,Compose 会通知相关的组件进行重新绘制。 需要注意的是,mutableStateOf 和 REMEMBER 都是基于 Kotlin 的协程实现的。它们利用了协程的异步执行模型,以便对组件状态进行管理,从而实现了高效、灵活、响应式的 UI 编程体验。 ### 回答2: Jetpack Compose 是一种用于构建 UI 的现代化工具包,它引入了多种新的概念和设计模式。其中,`mutableStateOf` 和 `remember` 是两个核心概念,用于管理状态和数据的变化。 `mutableStateOf` 是一个函数,用于创建一个可变的状态对象。它接受一个初始值,并返回一个包含该初始值的可变状态对象。当状态对象的值发生变化时,Compose 会自动重绘相关的 UI。由于状态对象是可变的,因此可以通过修改状态对象来改变 UI 的呈现。 例如,我们可以使用 `mutableStateOf` 来创建一个计数器的状态对象: ```kotlin val count = mutableStateOf(0) ``` 在 UI 中,我们可以通过修改 `count` 的值来改变计数器的显示: ```kotlin count.value = count.value + 1 ``` 每当 `count` 的值发生变化时,Compose 会重新计算依赖于 `count` 的 UI,并更新 UI 的呈现。 另一方面,`remember` 是一个函数,用于创建一个可记忆的值。它接受一个 lambda 表达式,并返回该表达式的计算结果。不同于 `mutableStateOf`,`remember` 返回的值是不可变的,并且在每次重绘中都会保持一致。 ```kotlin val randomValue = remember { Random.nextInt() } ``` 在上述示例中,`randomValue` 的值是在第一次调用时计算的,并在后续的重绘中保持不变。这意味着 `randomValue` 的值不会因为其他 UI 的变化而改变。 通过结合使用 `mutableStateOf` 和 `remember`,我们可以有效地管理动态的状态和不变的数据,并让 Jetpack Compose 自动处理 UI 的变化和重绘。这种状态管理模式为我们提供了一种简单而强大的方式来构建响应式和高性能的 UI。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值