One, foreword
This is the third article in a series exploring the art of Android SDK development. The system introduces several initialization methods of SDK, as well as the multiple inheritance of Java and the posture of ContentProvider for SDK initialization that we have learned due to “going astray” in SDK development process. By recognizing several ways from initialization to initialization, the author tries to explore the essence and optimal solution of initialization.
Series of articles:
Android SDK Development Art Exploration (1) Introduction and Design
(2) Exception or ErrorCode
Android SDK development art exploration (iii) initialization
Android SDK development art exploration (4) personalized configuration
Android SDK development art exploration (5) security and verification
Android SDK development art exploration (6) compression and optimization
Android SDK development art exploration (vii) Dependency principles and packaging methods
The concept of initialization
In daily development, we can see that our common third-party SDKS require an initialization step before they can be used. So why initialize? What exactly does initialization do? The author believes that the essence of initialization is to inject the App Context into the SDK so that it can access the App resources and services through this Context. It also includes custom configuration of related options by calling SDK methods at initialization.
Three, several ways of initialization
3.1. Misguided Thinking — custom Application
In App development, we generally obtain the global context of the Application from the custom Application for obtaining related resources and services. The following is an example:
public class App extends Application {
@SuppressLint("StaticFieldLeak")
private static Context sContext;
@Override
public void onCreate(a) {
super.onCreate();
sContext = this;
}
public static Context getContext(a) {
returnsContext; }}Copy the code
SDK is a subset of App to some extent, encapsulated by abstracting part of the business and logic of App. Therefore, conventional wisdom makes it easy to implement this code directly within the SDK. Little do they know, this is the beginning of the road…
To customize an Application object, manually specify it in the Application node of Androidmanifest.xml using android:name=”.app “. Otherwise, the user-defined Application will not be loaded.
In conventional wisdom, IT’s easy for SDK developers to come up with a solution: just let the App specify how to load the SDK’s built-in custom Application objects. So the question is, does his App already have its own custom Application?
Inertia again: let the App inherit the SDK’s Application? Does his App inherit the custom Application from other SDKS?
Keep going, have inherited one? Let’s inherit one more, let’s inherit one more Application, okay? Java does not provide direct support for multiple class inheritance.
Through the interface implementation + reflection to create proxy Application object, curve implementation of Application multiple inheritance, due to more code, here will not paste source code. Solution: ApplicationProxyDemo
So far, under inertia 3 even, success goes astray. It’s not that it doesn’t solve the problem, it just solves it rudely and the friendliness plummets…
Looking back, the essence of SDK initialization is to inject an App context into the SDK, not a custom Application. The road certainly went awry, but we also learned some strange knowledge from the awry road, comfort yourself, also be a harvest. Change your mind and move on!
3.2. Generally used static initialization method
A refresher on the essence of SDK initialization: injecting App context for retrieving related resources and services. So why do we initialize it in Application?
It is perfectly possible to define a “pseudo-application class” and inject the Application Context (usually the Application Context) through static methods. The following is an example:
/** * * author: Bruce * time: 2020/07/09 * desc: SDK initialization entry * version: 1.0.0 *
*/
public class MySDK {
private static Context sContext;
private MySDK(a) {}public static void initSdk(Context context) {
// Get ApplicationContext to prevent memory leaks
sContext = context.getApplicationContext();
initSomething();
}
public static Context getContext(a) {
return sContext;
}
private static void initSomething(a) {
//init something}}Copy the code
In this way, we can initialize happily:
/** * * author: Bruce * time: 2020/07/09 * desc: Custom Application * version: 1.0.0 *
*/
public class App extends Application {
@Override
public void onCreate(a) {
super.onCreate();
// Initialize the SDK
MySDK.initSdk(this); }}Copy the code
This way, not to mention getting the context of the App, there is also a place to initialize the SDK logic, friendliness up up up.
3.3. “Non-intrusive” Initialization scheme of ContentProvider
Some SDKS seem to be introduced directly without any initialization. So how do they do it? The answer is to use the ContentProvider to get the context of the application. To see a sample
The above screenshots are from a well-known SDK class, AndroidUtilCode. There are many other SDKS that use similar initialization methods, such as Firebase, which uses this initialization method.
So why is it possible to initialize the ContentProvider and get the Application context? And look at a few pieces of source code
You can see that the provider is loaded during the App startup process, and an Application instance is passed in. Finally, the onCreate() method is called in the ContentProvider. Therefore, in a custom ContentProvider, you can get an instance of the Application by using the getContext() method.
The onCreate() method in ContentProvider precedes the onCreate() method in Application (note: the Application object has already been created). Is there another focus on the optimization of App startup time?
Finish the source code and then look at the SDK project how to configure it (in fact, the beginning of the screenshots already have) :
/** * * author: Bruce * time: 2020/07/09 * desc 1.0.0 * < / pre > * /
public class MySDKInitProvider extends FileProvider{
@Override
public boolean onCreate(a) {
/ / initialization
MySDK.initSdk(getContext());
return super.onCreate(); }}Copy the code
Registered in the MANIFEST under the SDK Module, it will be incorporated into the main project at compile time
<provider
android:name=".MySDKInitProvider"
android:authorities="${applicationId}.MySDKInitProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/my_sdk_provider_paths" />
</provider>
Copy the code
The authorities of your Provider should not be dead, otherwise two apps with the same SDK will not co-exist. This is probably one of the most obvious SDK mistakes to make.
3.4. Initialize the new pose -App Startup
Those of you who follow Jetpack may have noticed that Google recently added a new component called App Startup.
App Startup provides an efficient and direct way to initialize components at application Startup. Both SDK developers and APP developers can use APP Startup to simplify the Startup order and explicitly set the initialization order. App Startup also allows you to significantly reduce your App Startup time by defining the initialization of a shared ContentProvider uniform component.
With the release of this component, you can also see Google trying to initialize the pit fill for the messy ContentProvider and for something more controlled. Although the use of the Provider for initialization is convenient for the caller and appears “non-intrusive,” it is actually “strongly intrusive.” Just imagine, in the pursuit of App performance and startup speed, multiple SDKS simultaneously use their own defined contentProviders to achieve “self-start”, but also in a variety of sequential and dependent SDK initialization optimization, it may not feel good, right?
Since this component is still in the alpha stage, it is not recommended for production. If you are interested, please check out the official document address: app-startup
Four, conclusion
This article mainly introduces the concepts related to SDK initialization, and the essence of initialization, namely: the App Context is injected into the SDK, so that it can access the App resources and services through this Context. And several feasible initialization methods in SDK development: one is the abandoned custom Application scheme, the other is the feasible static initialization method, and the third is the “non-invasive” initialization scheme implemented by ContentProvider. As for why the word “non-intrusion” is put in double quotation marks, I believe you have some emotional understanding after reading it.
Finally, if this document is helpful or inspiring to your development, like/follow/share three lines is the best incentive for the author to continue to create, thanks for your support!
Refer to the article
- Understand the Application creation process
- How does Firebase initialize on Android?
Copyright Notice:
This article first appeared in my column AndDev Android development has been authorized to hongyang public account exclusive release.