各位Android开发大佬们,如果大中型应用开发的经历的话,就会发现每次一运行应用就要在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来说,可能问题不大,只要先定义一个统一接口,然后分别实现就好了:
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会在编译时自动搜索所有实现了该接口的类,并生成调用的代码。Initiator支持kotlin,支持Application类型Moudle,支持
public class PushInit implements IAppInit { @Override public void init(Application application) { Log.d("init==", "PushInit"); } } 复制代码
为了满足更多需求,还可以为每个初始化增加多种配置,只要在这个类上加一个注解就行了:
@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 { } 复制代码
首先,在项目根目录的 build.gradle 文件中增加以下内容:
buildscript { repositories { google() jcenter() maven { url 'https://dl.bintray.com/renjianan/maven'} } dependencies { // your other dependencies // dependency for initiator classpath 'com.renny.initiator:plugin:'${latest_version}"//目前最新版:1.0.8 } } allprojects { repositories { google() jcenter() maven { url 'https://dl.bintray.com/renjianan/maven'} } } 复制代码
复制代码然后,在 application 、 library 、java library模块的 build.gradle 文件中应用插件:
apply plugin: 'com.android.application' // apply plugin: 'com.android.library' //apply plugin: 'java-library' apply plugin: 'initiator' 复制代码