Startup Startup
Source code version:
- Startup: 1.1.0
Navigation:
- Jetpack-lifecycle source code parsing
- Jetpack-livedata source code parsing
- Jetpack-viewmodel source code
- Jetpack-startup
- See more articles here: home page
use
Implementation, Initializer
class WorkManagerInitializer : Initializer<WorkManager> {
override fun create(context: Context): WorkManager {
// Initialize the WorkManager
val configuration = Configuration.Builder().build()
WorkManager.initialize(context, configuration)
// Return the initialized instance of WorkManager, So that through AppInitializer. GetInstance (context). InitializeComponent (WorkManagerInitializer: : class. Java) initialization and obtain.
return WorkManager.getInstance(context)
}
override fun dependencies(a): List<Class<out Initializer<*>>> {
// No dependencies on other libraries
return emptyList()
}
}
Copy the code
Because WorkManager does not depend on any other libraries, the dependencies() method returns an empty list.
class ExampleLoggerInitializer : Initializer<ExampleLogger> {
override fun create(context: Context): ExampleLogger {
// Initialize ExampleLogger and return its object, So that through AppInitializer. GetInstance (context). InitializeComponent (ExampleLoggerInitializer: : class. Java) initialization and obtain.
return ExampleLogger(WorkManager.getInstance(context))
}
override fun dependencies(a): List<Class<out Initializer<*>>> {
/ / rely on WorkManagerInitializer
return listOf(WorkManagerInitializer::class.java)
}
}
Copy the code
Because ExampleLogger depends on WorkManager, the dependencies() method returns a list containing WorkManagerInitializer that is initialized before it.
Initialization, Initializer
Automatically initialize components
Add in the manifest file
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.example.ExampleLoggerInitializer"// to initializeInitializerClass name full pathandroid:value="androidx.startup" />
</provider>
Copy the code
Automatically initialize the component, which initializes the component when the application starts. There is no need to add a
entry for WorkManagerInitializer because it is a dependency on ExampleLoggerInitializer. This is not a problem.
Description:
- the
provider
theDeclaration format fixed, only need to modify<meta-data>
thename
Can.- the
<meta-data>
theThe orderAnd determine theThe order of initialization.- the
tools:node="merge"
Property to ensure list merge toolProperly resolve any conflicting entries.
Manually initialize components
Manually initializing a component means not automatically initializing the component, so you must disable automatic initialization, also known as lazy initialization.
Disable automatic initialization of a single component
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="com.example.ExampleLoggerInitializer"
tools:node="remove" />
</provider>
Copy the code
To disable automatic initialization for a single component, add tools:node=”remove” to the specified
.
Description:
- if
<meta-data>
Own (Can be modified), delete the specified<meta-data>
Can; if<meta-data>
Not your own (e.g., tripartite libraries,Do not modify the), is usedtools:node="remove"
Just declare it.- Disabling automatic initialization of a component also disables automatic initialization of that component’s dependencies.
tools:node="remove"
, fromThe combined listingIn theremoveThis element.
Disable automatic initialization for all components
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
Copy the code
To disable automatic initialization for all components, declare tools:node=”remove” on InitializationProvider’s provider. Leave everything else unchanged or delete all
.
Description:
- Not recommendedAll of the componentsIs automatically initialized because it willDisable alluse
startup
libraryInitialize thetheThree party libraries(e.g.,lifecycle
The libraryProcessLifecycleInitializer
) give rise to the needmanualInitialize theallusestartup
Tripartite library library, not convenient for follow-up maintenance.
Manually initialize components
val result = AppInitializer.getInstance(context)
.initializeComponent(ExampleLoggerInitializer::class.java)
Copy the code
Manual initialization component, called AppInitializer. InitializeComponent () method, the above code manual initialization ExampleLogger, because ExampleLogger depend on WorkManager again, So the WorkManager is also initialized.
Description:
- The return value
result
forExampleLoggerInitializer
thecreate()
Method returnExampleLogger
Instance.- if
AppInitializer.initializeComponent()
Method initialized byInitializer
It is already initialized. A call to it again will not be initialized again, but will returnInitialization for the first timetheThe resulting value(such as initializationExampleLoggerInitializer
, always returnsInitialization for the first timetheExampleLogger
Instance).
The source code
Implementation, Initializer
, Initializer class
public interface Initializer<T> {
// Initialize the component given the application context
@NonNull
T create(@NonNull Context context);
// The Initializer dependency list. This is used to determine the initialization order of initializers.
For example, if an initializer B defines another initializer A as its dependency, then A is initialized before B.
@NonNullList<Class<? extends Initializer<? >>> dependencies(); }Copy the code
The Initializer class, for the Initializer interface, defines two important methods:
create()
Method, which containsAll actions required to initialize the componentAnd returnT an instance of the.dependencies()
Method, which returnsInitializer
Depends on othersInitializer<T>
The object’sThe list of. You can use this methodcontrolapp
inAt the startruninitializers
theThe order.
Initialization, Initializer
Automatically initialize components
Let’s take a look at the startup library manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.startup" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="30" />
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge" />
</application>
</manifest>
Copy the code
It declares the minimum SDK version 14 and declares a ContentProvider, which is InitializationProvider. Let’s look at the InitializationProvider class.
InitializationProvider class
public class InitializationProvider extends ContentProvider {
@Override
public final boolean onCreate(a) {
Context context = getContext();
if(context ! =null) {
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
@Nullable
@Override
public final Cursor query(
@NonNull Uri uri,
@Nullable String[] projection,
@Nullable String selection,
@Nullable String[] selectionArgs,
@Nullable String sortOrder) {
throw new IllegalStateException("Not allowed.");
}
@Nullable
@Override
public final String getType(@NonNull Uri uri) {
throw new IllegalStateException("Not allowed.");
}
@Nullable
@Override
public final Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
throw new IllegalStateException("Not allowed.");
}
@Override
public final int delete(
@NonNull Uri uri,
@Nullable String selection,
@Nullable String[] selectionArgs) {
throw new IllegalStateException("Not allowed.");
}
@Override
public final int update(
@NonNull Uri uri,
@Nullable ContentValues values,
@Nullable String selection,
@Nullable String[] selectionArgs) {
throw new IllegalStateException("Not allowed."); }}Copy the code
InitializationProvider class, which is a ContentProvider, In the onCreate () method calls inside the AppInitializer. GetInstance (context). DiscoverAndInitialize (), . Let’s take a look at AppInitializer getInstance (context) method, and then take a look at its discoverAndInitialize () method.
Description:
Application
,ContentProvider
,Activity
theonCreate()
Order of execution:Application.attachBaseContext()
->ContentProvider.onCreate()
->Application.onCreate()
->Activity.onCreate()
.
AppInitializer –> getInstance method
public final class AppInitializer {
// A singleton AppInitializer instance
private static volatile AppInitializer sInstance;
// Obtain the singleton AppInitializer instance
@NonNull
@SuppressWarnings("UnusedReturnValue")
public static AppInitializer getInstance(@NonNull Context context) {
if (sInstance == null) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = newAppInitializer(context); }}}returnsInstance; }}Copy the code
AppInitializer. GetInstance (context) method, to get the singleton AppInitializer instance.
AppInitializer –> discoverAndInitialize method
public final class AppInitializer {
// Tracing
private static final String SECTION_NAME = "Startup";
// The Set Set of Initializer has been found, and value is the Initializer class.
@NonNull
finalSet<Class<? extends Initializer<? >>> mDiscovered;// Discover and initialize
@SuppressWarnings("unchecked")
void discoverAndInitialize(a) {
try {
Trace.beginSection(SECTION_NAME);
// Get the InitializationProvider ProviderInfo
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
// Get
information
Bundle metadata = providerInfo.metaData;
// Get the string "androidx.startup"
String startup = mContext.getString(R.string.androidx_startup);
// Check whether metadata is null, that is, whether
is configured.
if(metadata ! =null) {
// Initialize the Class collection of InitializerSet<Class<? >> initializing =new HashSet<>();
android:name
Set<String> keys = metadata.keySet();
// Traverses all keys in the metadata
for (String key : keys) {
// Get the value of metadata, that is, get android:value in
.
String value = metadata.getString(key, null);
android:value = "androidx.startup"
if (startup.equals(value)) {
android:name specifies the class
Class<? > clazz = Class.forName(key);// Check whether
android:name is a subclass of Initializer.
if (Initializer.class.isAssignableFrom(clazz)) {
// If Initializer is a subclass, the call will be strong.Class<? extends Initializer<? >> component = (Class<? extends Initializer<? >>) clazz;// Add to the mDiscovered collection
mDiscovered.add(component);
// Prints logs
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Discovered %s", key));
}
// Initialize component, that is, initialize the class specified by Android :name in
.
doInitialize(component, initializing);
}
}
}
}
} catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
throw new StartupException(exception);
} finally{ Trace.endSection(); }}}Copy the code
AppInitializer. DiscoverAndInitialize () method, to find and initialization, Initializer, find all, Initializer list file configuration, and then call doInitialize initialized () method.
Description:
<meta-data>
Within theandroid:value
That must beandroidx.startup
.<meta-data>
Within theandroid:name
That must beInitializer
A subclasstheClass name full path.- inThe manifest fileConfiguration of theall
Initializer
, will be added tomDiscovered
(Found)A collection of.
Let’s see AppInitializer. DoInitialize () method.
AppInitializer –> doInitialize method
public final class AppInitializer {
/ / thread lock
private static final Object sLock = new Object();
// The Map collection of Initializer has been initialized. Key is the class of Initializer and value is the return value of the initializer.oncreate () method.
@NonNull
finalMap<Class<? >, Object> mInitialized;// Do the initialization
@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
<T> T doInitialize(
@NonNullClass<? extends Initializer<? >> component,@NonNullSet<Class<? >> initializing) {
// Synchronize to ensure thread safety.
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 the class is being initialized and then initialized, an exception is thrown.
if (initializing.contains(component)) {
String message = String.format(
"Cannot initialize %s. Cycle detected.", component.getName()
);
throw new IllegalStateException(message);
}
/ / the result
Object result;
// Determine whether the class has been initialized to prevent repeated initialization.
if(! mInitialized.containsKey(component)) {// If it is not initialized, initialize it and record the result of its create.
// Add to the collection being initialized, tag being initialized.
initializing.add(component);
try {
// reflection creates objects
Object instance = component.getDeclaredConstructor().newInstance();
Component implements Initializer, so no problem.Initializer<? > initializer = (Initializer<? >) instance;// Get the list of initializers it depends onList<Class<? extends Initializer<? >>> dependencies = initializer.dependencies();If the Initializer list it depends on is not empty, it initializes the list first.
if(! dependencies.isEmpty()) {// Iterate over the list of initializers it depends on
for(Class<? extends Initializer<? >> clazz : dependencies) {// Check whether the Initializer it depends on has already been initialized.
if(! mInitialized.containsKey(clazz)) {// if it is not initialized, it is initialized recursively.
// - Note: The following code is executed after all dependencies are completed.doInitialize(clazz, initializing); }}}// Print log: component name in initialization.
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initializing %s", component.getName()));
}
// Call the create() method to initialize and record its return.
result = initializer.create(mContext);
// Print logs: indicates the name of the component whose initialization is completed.
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initialized %s", component.getName()));
}
// Remove from the initializing collection, the flag has been initialized.
initializing.remove(component);
// Store the initialized Initializer and the result returned by its create() method.
mInitialized.put(component, result);
} catch (Throwable throwable) {
throw newStartupException(throwable); }}else {
Get the result of create() if it is already initialized.
result = mInitialized.get(component);
}
// Returns the result of initializer.create()
return (T) result;
} finally{ Trace.endSection(); }}}}Copy the code
AppInitializer. DoInitialize () method, as a real initialization, Initializer method, it reflected, Initializer objects, and invoke the create () method to notify the internal initialization, and returns the create () method returns a value.
Description:
- If the
Initializer
Not initialized,Reflection to createthisInitializer
Object and call itcreate()
methodsNotifies internal initializationAnd should becreate()
methodsThe results ofAdded to themInitialized
For subsequent acquisition;Otherwise,, frommInitialized
To deriveInitialization for the first timetheThe resulting valueTo make itDon’t create it very oftenthisInitializer
Object.- If you want to create
Initializer
Depend on othersInitializer
, will proceedLoop recursive initializationotherInitializer
To make otherInitializer
All initialization is completeIs executedInitializer
thecreate()
Methods.doInitialize()
Method, because usedsynchronized
Code block, and locksLock
forstaticOf (only), so when there are threadsisperformdoInitialize()
Method is executed by another threaddoInitialize()
Both methodsWait for the last thread to complete.
Manually initialize components
AppInitializer –> initializeComponent method
// Initialize the Initializer class
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
return doInitialize(component, newHashSet<Class<? > > ()); }Copy the code
AppInitializer. InitializeComponent () method, direct call doInitialize () method to create, and returns its doInitialize () method of the resulting value (namely, Initializer. The create () method return values).
Description:
- only
initializeComponent()
Method to getInitializer
thecreate()
Method, regardless of whetherAutomatic initialization(ContentProvider
)deposit, orManual initialization(callinitializeComponent()
)deposit, can beOnce again,callinitializeComponent()
methodsAccess to theIn thecreate()
methodsThe return value.- Due to the
doInitialize()
Method, usedsynchronized
, resulting inIts implementationEverything else has to wait. Such as:A
,B
Time consumingsoRespectively in a child threadperforminitializeComponent()
Method,C
inThe main threadExecute to make it three separately inThree threadsExecute to achieveconcurrentBut the result is:A
The execution of,B
Waiting for theA
Execution completed,C
Waiting for theA
,B
Execution completed, not reachedconcurrentThe effect.
Other source
AppInitializer –> isEagerlyInitialized method
Public Boolean isEagerlyInitialized(@nonnull Class<? extends Initializer<? >> Component) {// If discoverAndInitialize() has never been called, there is no rush to initialize anything. return mDiscovered.contains(component); }Copy the code
AppInitializer. IsEagerlyInitialized () method, is eagerly for, Initializer is initialized, whether that is in the listing file configuration.
The advantages and disadvantages
advantages
- Provides a rule that can be used by all three librariesThe same
ContentProvider
In itsInside the libraryforInitialize the.Reduced initialization codeandTo optimize thetheCreate multipleContentProvider
Caused by thePerformance, time loss. - Supports initialization order and dependencies.
disadvantages
- Multithreaded concurrent initialization is not supported.
- Reflection to create
Initializer
Class that has a slight impact on performance.
conclusion
Jetpack-startup source code Jetpack’s other source code series will be published later, please stay tuned. If you have any questions, see you in the comments!
Finally, I would like to recommend my website, devbolg.cn, the developer’s technical blog, which currently contains android related technologies, and will be open to all developers later. Welcome to experience!