Android功能庫初始化管理利器

大頭呆發表於2018-07-26

前言

隨著自己開發的應用的版本迭代,新功能不斷增多,隨之引入的第三方庫也不可避免地多了起來,你可能就會發現自己應用Application中各種框架的初始化程式碼也在逐漸臃腫起來:什麼推送啦,分享啦,統計啦,定位啦...另外還有你自己封裝的一些工具和框架。這些七七八八加起來,可能最終你的Application會變成這樣:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化推送
        PushAgent mPushAgent = PushAgent.getInstance(this);
        mPushAgent.register(new IUmengRegisterCallback() {
            @Override
            public void onSuccess(String deviceToken) {
                //註冊成功會返回device token
            }

            @Override
            public void onFailure(String s, String s1) {
            }
        });
        //初始化統計
        UMConfigure.init(this,"5a12384aa40fa3551f0001d1","umeng",UMConfigure.DEVICE_TYPE_PHONE,"");
        //初始化分享
        PlatformConfig.setWeixin("wxdc1e388c3822c80b", "3baf1193c85774b3fd9d18447d76cab0");
        PlatformConfig.setSinaWeibo("3921700954", "04b48b094faeb16683c32669824ebdad","http://sns.whalecloud.com");
        PlatformConfig.setYixin("yxc0614e80c9304c11b0391514d09f13bf");
        PlatformConfig.setQQZone("100424468", "c7394704798a158208a74ab60104f0ba");
        PlatformConfig.setTwitter("3aIN7fuF685MuZ7jtXkQxalyi", "MK6FEYG63eWcpDFgRYw4w9puJhzDl0tyuqWjZ3M7XJuuG7mMbO");
        //初始化定位
        LocationClient mLocationClient = new LocationClient(context);
        mLocationClient.setLocOption(getLocationOption());
        mLocationClient.registerLocationListener(new MyLocationListener());
        mLocationClient.start();
        mLocationClient.requestLocation();
        //初始化glide
        DisplayOption options = DisplayOption.builder().setDefaultResId(R.drawable.ic_default)
                .setErrorResId(-1).setLoadingResId(-1);
        imageDisplayLoader.setDefaultDisplayOption(options);
        //初始化自己的一些工具  
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                
            }

        });

    }
}
複製程式碼

上面我只是列舉了一些常用的功能框架,從個人開發經驗上說,這些應用程式級別的框架,作用的時間貫穿APP的整個生命週期,所以都會要求你在一開始的時候就進行初始化。

優化方案

對於單一模組的App來說,可能問題不大,只要先定義一個統一介面,然後分別實現,最後新增到一個集合,在Application中統一呼叫就好了:

public interface IAppInit {
    void init(@NonNull Application application);
}

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        List<IAppInit> initList = new ArrayList<>();
        initList.add(new ShareInit());
        initList.add(new PushInit());
        initList.add(new ImageInit());
        for (IAppInit iAppInit : initList) {
            iAppInit.init(this);
        }
    }
}

複製程式碼

但如今很多的進行了元件化的改造,其中的一個重要思想就是功能模組的元件化,也就是解耦,彼此互不依賴,但如果我們還是像上面這樣做的話就等於違背了這個思想,把這些功能模組的初始化程式碼全部集中在了一起。更好的方案當然是在模組內部做初始化,而且不需要在Application中統一呼叫這些初始化程式碼。

優雅地進行框架初始化

為了更好地解決這個問題,我寫了Initiator這個Gradle外掛。使用方法異常簡單:在程式的任意位置,只要實現IAppInit介面就可以了,無需手動呼叫,Initiator會在編譯時自動搜尋所有實現了該介面的類,並生成呼叫init()方法的的程式碼。Initiator支援kotlin,支援Application型別和library型別的module。

public class PushInit implements IAppInit {
    @Override
    public void init(Application application) {
        Log.d("init==", "PushInit");
    }
}
複製程式碼

為了滿足更多初始化需求,還可以為每個初始化增加多種配置,只要在這個類上加一個@AppInit註解就行了:

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface AppInit {
    boolean background() default false; //在工作執行緒中初始化,預設false

    boolean inChildProcess() default true;//允許在子程式中初始化,多程式應用Application的onCreate方法會呼叫多次,預設true

    boolean onlyInDebug() default false;//只在debug中做初始化,預設false

    int priority() default 0;//初始化優先順序,數字越大,優先順序越高,初始化時間越早

    long delay() default 0L;//初始化執行延時時間,在主執行緒和工作執行緒都可以延時
}
複製程式碼

採用編譯期註解,不使用反射,程式碼在編譯時生成,對最終程式執行效能影響很小。最終我們的程式碼可能如下:

@AppInit(priority = 22, delay = 1740, onlyInDebug = true)
public class PushInit implements IAppInit {

    @Override
    public void init(Application application) {
        Log.d("init==", "PushInit");
    }
}

複製程式碼

注意,如果你沒有做這些特別的配置,不需要加這個註解。另外你可能對Application做了多重繼承Initiator會找到多個Application的子類,請在你需要初始化的入口加上@InitContext註解:

@InitContext
public class App extends BaseApplication {

}
複製程式碼

目前暫時只支援Application型別,後期考慮增加Activity的支援,因為有些初始化可以延後放到啟動頁或首頁來做。目前可以用延時策略替代。

引入方式

首先,在專案根目錄的 build.gradle檔案中增加以下內容:

    dependencies {
         classpath 'com.renny.initiator:plugin:'${latest_version}"
    }
複製程式碼

然後,在 applicationlibrary 模組的build.gradle 檔案中應用外掛:

apply plugin: 'com.android.application'
// apply plugin: 'com.android.library'
apply plugin: 'initiator'
複製程式碼

Gradle Plugin或者實現方式感興趣的同學請看原始碼:Github連結。歡迎大家找找bug,提提新功能~

相關文章