This is the 9th day of my participation in Gwen Challenge

Follow my public number Ananzhuo to learn more knowledge

Git address

App Startup

Introduce role

App Startup is a library that initializes data when an App is launched. Use App Startup to solve the problem of slow Startup caused by the abuse of ContentProvider.

Also, App Startup can be used for App development or SDK development

Advantages of App Startup

  1. Using contentProviders to automatically get the ApplicationContext is confusing, and the way multiple ContentProviders are initialized does not guarantee the order in which they are initialized

  2. Unified management can significantly improve the speed of app initialization. Note: This method is limited to those apps that use a lot of ContentProviders to initialize applications. Otherwise, it is not impossible to use, but it has no optimization effect

Rely on

Dependencies {implementation (" androidx. Startup: startup - runtime: 1.0.0 ")}Copy the code

Initialize a global singleton with AppStartup (main branch)

  1. The Car object
class Car(private val name: String) {
    companion object {
        var instance: Car? = null
        fun getInstance(name: String): Car {
            if (instance == null) {
                instance = Car(name)
            }
            return instance!!
        }
    }

    override fun toString(): String {
        return "$name  ${Random.nextInt(100)}"
    }
}
Copy the code
  1. You first need to implement an Initializer
class AndroidInitializer : Initializer<Car> { override fun create(context: Context): Car {return Car. GetInstance (" taxi ")} Override fun dependencies(): MutableList<Class<out Initializer<*>>> { return mutableListOf() } }Copy the code
  1. Register AndroidInitializer in the code
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup"  android:exported="false" > <meta-data android:name="com.ananananzhuo.appstartupdemo.AndroidInitializer" android:value="androidx.startup" /> </provider>Copy the code
  1. Analysis of the

In this case, the Car object maintains a global singleton method getInstance internally.

AppStartup is used to maintain a global singleton, so the singleton is initialized using the AndroidInitializer object create method we defined.

  1. We’ll call the Car toString method in MainActivity as follows
LogEE (Car.getInstance(" Car: ").toString()) logEE(Car.getInstance(" Car: ").tostring ()) logEE(Car.getInstance(" Car: ").tostring ()) ").toString())Copy the code

We called the toString method three times

The code output is as follows:

Our MainActivity code getInstance passes in “car” but prints “taxi” instead. Looking at the code in AndroidInitializer, we found that the object created in the create method in AndroidInitializer was “taxi”.

As a result, our global Car singleton was initialized in AndroidInitializer.

Manually initialize components

In the previous section we implemented auto initialization of Car objects by registering components in the Manifest.

However, it is actually possible to implement initialization without registering it in the Manifest. Manual initialization is as follows:

 AppInitializer.getInstance(this)
            .initializeComponent(AndroidInitializer::class.java)
Copy the code

The downside of this approach is that you can only initialize one component at a time

Implement initialization of interdependent multiple instances (branch: multiModule)

AppStartup = AppStartup = AppStartup = AppStartup = AppStartup = AppStartup

So now I’m going to use AppStartup to implement multi-instance initialization, let you know more about AppStartup application

The logic of this section is described first:

In this case we need to create two objects, Person and Noodle, both of which are global singletons.

Person holds a reference to the Noodle object,

There is an eat method in Person, and in this case our eat will output a log of “so-and-so” eating “noodles”

No more nonsense, on the code:

Don’t be too long code, are a look to understand the logic

  1. The Person and such
class Person(val name:String) { private var noodle: Noodle? = null companion object { private var instance: Person? = null fun getInstance(name:String): Person { if (instance == null) { instance = Person(name) } return instance!! }} fun addNoodle(paramsnoodle: Noodle) {Noodle = Paramsnoodle} fun eat() {logEE("${name} eat ${Noodle? .name}") } }Copy the code
Class Noodle {val name = "Noodle" companion object {private var instance: Noodle? = null fun getInstance(): Noodle { if (instance == null) { instance = Noodle() } return instance!! }}}Copy the code
  1. PersonInitializer, NoodleInitializer
class PersonInitializer : Initializer<Person> { override fun create(context: Context): Person {return person.getinstance (). Apply {addNoodle(Noodle. GetInstance ())}} Override fun dependencies(): MutableList<Class<out Initializer<*>>> { return mutableListOf(NoodleInitializer::class.java) } }Copy the code

class NoodleInitializer:Initializer<Noodle> {
    override fun create(context: Context): Noodle {
        return Noodle.getInstance()
    }

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

The Create method of PersonInitializer in both components creates an instance of Person and adds an instance of Noodle to it.

To highlight:

PersonInitializer dependencies method returns the mutableListOf (NoodleInitializer: : class. Java). Noodle instances in The NoodleInitializer are initialized before the Person in the PersonInitializer is initialized. Then when addNoodle is in PersonInitializer the Noodle global singleton has been created.

  1. Call the noodle-eating method
Person. GetInstance (" du fu ".) eat ()Copy the code
  1. Print Log Output

The log output is as expected

The way to register multi-instance components is as follows: PersonInitializer and NoodleInitializer were registered in meta-data.

In fact, components of NoodleInitializer can be unregistered because it is already declared in the Dependencies of PersonInitializer.

<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup"  android:exported="false"> <meta-data android:name="com.ananananzhuo.appstartupdemo.PersonInitializer" android:value="androidx.startup" /> <meta-data android:name="com.ananananzhuo.appstartupdemo.NoodleInitializer" android:value="androidx.startup" /> </provider>Copy the code

SDK development with AppStartup (branch: sdk_develop)

This example introduces the use of AppStartup in SDK development, which is actually the same as application development, but it still feels necessary to say.

In this example, we created a library module, wrote our AppStartup code logic in the library, and then packaged the library into ARR, integrated into the APP module, registered components in the APP Manifest. And invoke the associated methods of the component.

  1. Aar integration

  2. Code in the Library

class LibraryInitializer:Initializer<Student> {
    override fun create(context: Context): Student {
        return Student.getInstance()
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> {
       return mutableListOf()
    }
}
Copy the code
Class Student(val name: String) {companion object {private val Student = Student(" val ") fun getInstance(): Student {return Student}} fun study() {log.e ("tag", "${name} ")}}Copy the code
  1. Register components in the Manifest
 <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="com.ananananzhuo.appstartupdemo.androidx-startup"
            android:exported="false"
          >
            <meta-data
                android:name="com.ananananzhuo.library.LibraryInitializer"
                android:value="androidx.startup" />
        </provider>
Copy the code
  1. Log print

  1. conclusion

In this way, the third party SDK only needs to define its own AppStartup component. We can complete the initialization of the third party component by adding the information of the third party component to the manifest when registering the component.

This is a great way to avoid some self-righteous SDK that makes the initialization of contentProviders disgusting in the name of making it easier for us to integrate

In the future, if you cooperate with a third-party SDK provider and the initialization method of ContentProvider disgusted you, then take out my article to teach him a good life.

One last word: Cool cool cool cool cool