前言
随着自己开发的应用的版本迭代, 新功能不断增多, 随之引入的第三方库也不可避免地多了起来, 你可能就会发现自己应用 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 https://github.com/renjianan/initiator 这个 Gradle 插件. 使用方法异常简单: 在程序的任意位置, 只要实现 IAppInit 接口就可以了, 无需手动调用, Initiator https://github.com/renjianan/initiator 会在编译时自动搜索所有实现了该接口的类, 并生成调用 init() 方法的的代码. Initiator https://github.com/renjianan/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 https://github.com/renjianan/initiator 会找到多个 Application 的子类, 请在你需要初始化的入口加上 @InitContext 注解:
- @InitContext
- public class App extends BaseApplication {
- }
复制代码
目前暂时只支持 Application 类型, 后期考虑增加 Activity 的支持, 因为有些初始化可以延后放到启动页或首页来做. 目前可以用延时策略替代.
引入方式
首先, 在项目根目录的 build.gradle 文件中增加以下内容:
- buildscript {
- repositories {
- google()
- jcenter()
- maven { url 'https://dl.bintray.com/renjianan/maven'}
- }
- dependencies {
- classpath 'com.renny.initiator:plugin:'${latest_version}"
- }
- }
- allprojects {
- repositories {
- google()
- jcenter()
- maven { url 'https://dl.bintray.com/renjianan/maven'}
- }
- }
复制代码
然后, 在 application 或 library 模块的 build.gradle 文件中应用插件:
- apply plugin: 'com.android.application'
- // apply plugin: 'com.android.library'
- apply plugin: 'initiator'
复制代码
对 Gradle Plugin 或者实现方式感兴趣的同学请看源码: Github 链接 https://github.com/renjianan/initiator
来源: https://juejin.im/post/5b59a4e7e51d455f5f4cfa38