美文网首页
MultiRouter-多进程组件化路由

MultiRouter-多进程组件化路由

作者: f1abf4d2779c | 来源:发表于2017-08-31 20:53 被阅读179次

    APP诞生之初,用的是常见的分层结构设计, 这种架构简单、清晰并一直沿袭至今,随着业务的快速发展,业务模块越来越多,各个模块间相互引用,耦合越来越严重,因此做了第一版架构重构,对各模块进行拆分,多个模块并行开发,为了解决模块间相互依赖,模块间通信采用最简单的单进程路由架构。

    单进程路由架构 使用简单,适合小型项目或者初期项目的开发。在持续了一段开发时间后,渐渐的它的单进程模型的弊端也越来越明显,由于代码、内存、apk大小都在增长,对系统资源的占用越来越多,导致进程容易被系统回收或导致内存溢出崩溃,如果不进行内存优化,将很快无法支撑整个业务的发展,此时将整体的应用架构转型为多进程迫在眉睫,独立的通信进程可以保持各个进程模块的稳定性,也可以阻隔一些内存泄露导致的问题。

    实现方案

    一. 目标&需求

    1. 接口调用简单
    2. 实现apt自动注册Provider、Action
    3. 进程间可以传递复杂数据
    4. 初始化建立进程间通信通道,避免对每次请求结果都要判断是否异步
    5. 添加缓存策略,避免重复请求

    二. 技术选型

    2.1 如何让接口调用简单?

    使用建造者模式构建请求体,链式调用同时避免参数混乱

    2.2 如何自定义注解注册来生成Provider,Action注册代码?

    注解解析器: 使用官方推荐的AnnotationProcessor
    代码自动生成: 使用JavaPoet库或JDK自带的JavaFileObject类

    2.3 进程间如何通讯?
    1. 使用AIDL来做进程间的数据交换
    2. Boardcast发布进程间通知
    2.5 进程间如何传递复杂数据?

    有两种可选方案:

    1. 使用Binder支持的Parceable
    2. 使用Json格式String

    使用String来传递数据有两个明显不足:

    1. 使用麻烦,需要在请求和返回时对数据进行解析
    2. 效率不如Parceable

    所以选择Binder支持的Parceable来传递数据为最优方案。

    三. 最终实现 MultiProcessRouter

    Github项目地址:MultiProcessRouter

    MultiProcessRouter是一个基于AnnotationProcessor实现的多进程路由框架,它支持注解注册接口、多进程间数据交互,可快速应用于项目多进程模块化。

    使用说明

    Gradle配置
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
    
    allprojects {
        repositories {
            jcenter()
            maven {
                url 'https://dl.bintray.com/shamschu/maven'
            }
        }
    }
    
    apply plugin: 'com.neenbedankt.android-apt'
    
    compile 'com.sc.framework:router:1.0.0'
    compile 'com.sc.framework:annotation:1.0.0'
    apt "com.sc.framework:compiler:1.0.0"
    
    创建每个进程对应的LocalRouterService

    LocalRouterService为本地Service(运行在每个单独进程中),用来进行进程间的AIDL通信,一般来说,你只要继承LocalRouterService,并且在你的AndroidMenifest中注册该Service并使用android:process指定它所在的进程名称即可。

    public class ProcessService2 extends LocalRouterService {
    
    }
    
    <service
        android:name=".ProcessService2"
        android:process=":second"/>
    
    初始化路由

    在应用启动时调用:

    Router.register(Context context, IRouterServiceRegister serviceRegister);
    

    并实现IRouterServiceRegister的getServices()方法来返回每个进程对应的LocalRouterService映射列表。
    例如您的应用有两个进程,一个主进程,一个名称为second的其他进程,那么调用如下所示:

    Router.register(this, new IRouterServiceRegister() {
        @Override
        public Map<String, Class<? extends LocalRouterService>> getServices() {
            Map<String, Class<? extends LocalRouterService>> services = new HashMap<>();
            services.put(ProcessUtils.getMainProcess(TestApplication.this), ProcessService1.class);
            services.put(ProcessUtils.getMainProcess(TestApplication.this) + ProcessUtils.COLON + "second", ProcessService2.class);
            return services;
        }
    });
    
    接收路由服务初始化完成广播

    Router初始化时,动态注册InitializeCompleteReceiver,并实现onRouterServiceInitCompleted方法,它会在Router服务初始化完成后被触发,你可以在你应用的闪屏页Activity的onCreate中注册,并等待通知,通知成功后再进行app的下一步操作,一旦初始化完成,你可以任意的调用其他进程的接口。

    public class SplashActivity extends AppCompatActivity {
    
        private InitializeCompleteReceiver receiver;
        private boolean mReceiverRegister = false;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
            // enter main activity if router service has been initialized
            if (Router.checkRouterServiceInitCompleted(this)) {
                startMainActivity();
                return;
            }
            // register InitializeCompleteReceiver to receive router initialized broadcast.
            if (!mReceiverRegister) {
                receiver = new InitializeCompleteReceiver() {
                    @Override
                    protected void onRouterServiceInitCompleted() {
                        startMainActivity();
                    }
                };
                IntentFilter filter = new IntentFilter();
                filter.addAction(InitializeCompleteReceiver.ACTION_ROUTER_SERVICE_COMPLETED);
                registerReceiver(receiver, filter);
                mReceiverRegister = true;
            }
        }
    
        /**
         * Start your main activity
         */
        private void startMainActivity() {
            Intent intent = new Intent(SplashActivity.this, MainActivity.class);
            startActivity(intent);
            finish();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mReceiverRegister) {
                unregisterReceiver(receiver);
                mReceiverRegister = false;
            }
        }
    }
    
    注册Provider
    使用注解

    @Provider(process = PROCESS_NAME)

    PROCESS_NAME为Provider的进程名称。

    @Provider(process = "com.shamschu.framework")
    public class TestProvider extends RouterProvider {
    
        @Override
        public String getName() {
            return "TestProvider";
        }
    }
    
    注册Action
    使用注解

    @Action(provider = YOUR_PROVIDER.class)

    YOUR_PROVIDER.class为Action所属的Provider的类。

    @Action(provider = TestProvider.class)
    public class TestAction extends RouterAction<String> {
    
        @Override
        public RouterResponse<String> invoke(Context context, RouterRequest request) {
            return new RouterResponse.Builder<String>()
                .result("this is a router test!")
                .build();
        }
    
    }
    
    创建请求
    RouterRequest request = new RouterRequest.Builder()
            .process("com.shamschu.framework") // 请求进程
            .provider("TestProvider") // 请求进程提供的接口
            .action("TestAction") // 请求接口提供的动作,
            .cacheStrategy(CacheStrategy.FIXED) // 请求缓存策略 NONE: 不缓存,每次都重新获取 FIXED: 一旦请求后则缓存,不在重新发起请求
            .build();
    
    请求并获取结果
    RouterResponse<String> response = Router.route(v.getContext(), request);
    if (response.isSuccess()) {
        Toast.makeText(SecondActivity.this, response.getResult(), Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(SecondActivity.this, response.getError(), Toast.LENGTH_LONG).show();
    }
    

    相关文章

      网友评论

          本文标题:MultiRouter-多进程组件化路由

          本文链接:https://www.haomeiwen.com/subject/yjmwrxtx.html