原文地址:

一般来说,一个Library都需要传入一个Context参数以完成初始化,该Context参数可以从Application对象的onCreate方法中获取。因此,大部分库都会提供一个init方法,让你在Application Object中完成调用,本文就介绍另一个方法。首先来看下你现在的代码,可能是这个样子:


public class YourApplication extends Application {

    @Override

    public void onCreate() {

        super.onCreate();

        SomeLibrary.init(this);

        SomeOtherLibrary.init(this);

    }

}

这种方法的坏处就是会逼着你一定要写一个Application对象,否则就用不了其他的依赖库,对于处女座来说有时候会觉得很不美好。让我们来换个思路进行这件事,这也是从Firebase的客户端得到的灵感,我们首先创建一个空的ContentProvider,然后再manifest文件中完成注册,不过别把它开放给其他应用。而在应用初始化的时候,它会调用onCreate方法注册全部的ContentProvider,这也就意味着虽然Activity还没有启动,但是可以访问ApplicationContext了,在这里我们也就能初始化那些依赖库了。


public final class YourLibraryInitProvider extends ContentProvider {



    public YourLibraryInitProvider() {

    }



    @Override

    public boolean onCreate() {

        // get the context (Application context)

        Context context = getContext();

        // initialize whatever you need

    }



    @Nullable

    @Override

    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        return null;

    }



    @Nullable

    @Override

    public String getType(Uri uri) {

        return null;

    }



    @Nullable

    @Override

    public Uri insert(Uri uri, ContentValues values) {

        return null;

    }



    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

        return 0;

    }



    @Override

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

        return 0;

    }

}

<manifest package="some.library.packagename"

          xmlns:android="http://schemas.android.com/apk/res/android">

    <application>

        <provider

            android:authorities="${applicationId}.yourlibraryinitprovider"

            android:exported="false"

            android:enabled="true"

            android:name=".YourLibraryInitProvider" />

    </application>



</manifest>

这边有个需要注意的点,就是如果是有固定的字符串,可能在有些设备上就无法运行,因此要保证authorities的属性的唯一性,这也就是传入applicationID的原因:


public final class YourLibraryInitProvider extends ContentProvider {



    ...



    @Override

    public void attachInfo(Context context, ProviderInfo providerInfo) {

        if (providerInfo == null) {

            throw new NullPointerException("YourLibraryInitProvider ProviderInfo cannot be null.");

        }

        // So if the authorities equal the library internal ones, the developer forgot to set his applicationId

        if ("<your-library-applicationid>.yourlibraryinitprovider".equals(providerInfo.authority)) {

            throw new IllegalStateException("Incorrect provider authority in manifest. Most likely due to a "

                    + "missing applicationId variable in application\'s build.gradle.");

        }

        super.attachInfo(context, providerInfo);

    }



    ...

}

不过这种方法的坏处就是因为所有的ContentProvider都是运行在主线程中,也就意味着所有的初始化都会在主线程完成。如果你希望要异步的初始化一些库,那么可以选择还是手动地在某个地方进行初始化。


王下邀月熊_Chevalier
22.5k 声望8.5k 粉丝

爱代码 爱生活 希望成为全栈整合师