【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )

2023-03-29 13:30:58 浏览数 (1)

Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )

【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )

【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )


文章目录

  • Android 插件化系列文章目录
  • 前言
  • 一、BaseActivity 注入上下文的使用
  • 二、BaseActivity 完整代码
  • 三、博客资源
  • 总结

前言

参考 【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 ) 中给出的实现思路 , 逐步实现 “ 插桩式 “ 插件化框架 ;

在 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 ) 博客中 , 开发了 DexClassLoader 类加载器加载插件包 , 并使用 AssetManager 加载插件包资源的模块 ;

在 【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 ) 博客中开发开发本地的 Activity 桩 , 即空壳 Activity , 用于持有插件界面组件 , 并在生命周期中回调插件界面 Activity 组件的对应生命周期方法 ;

本博客中开发插件包中的 Activity , 并进行插件化调用 ; 所有的插件包中的 Activity 都要继承 BaseActivity , 插件 Activity 中的相关功能都要使用 BaseActivity 中被注入的上下文进行代理操作 ;


一、BaseActivity 注入上下文的使用

在上一篇博客 【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 ) 中实现了 BaseActivity , 这是所有 " 插件 " 模块中 Activity 类的基类 , 其中的 private Activity proxyActivity 成员的作用是充当 插件 Activity 中的上下文 ;

代码语言:javascript复制
public class BaseActivity extends AppCompatActivity implements PluginActivityInterface {
    /**
     * 注入的 Activity , 代理该 Activity 类作为上下文
     */
    private Activity proxyActivity;
}

插件包中的 Activity 没有上下文对象 , 如果在插件包中的 PluginActivity 中调用与上下文相关的方法 , 如 findViewById 查找组件 , 肯定是无法实现的 , 必须修改 BaseActivity 中与上下文相关的方法 ;

setContentView 中需要调用 supersetContentView 方法 , 这里的上下文是无效的 , 也无法成功加载布局文件 , 因此必须调用 private Activity proxyActivity 成员的 setContentView 方法加载布局文件 ;

代码语言:javascript复制
// 在 BaseActivity 中调用如下方法是不生效的 
@Override
public void setContentView(int layoutResID) {
    super.setContentView(layoutResID);
}

需要进行如下修改 , 使用注入的上下文设置布局文件 , 这个注入的上下文就是代理 Activity , ProxyActivity ;

代码语言:javascript复制
@Override
public void setContentView(int layoutResID) {
    // 调用代理 Activity 中的 setContentView 方法
    if (proxyActivity == null) {
        proxyActivity.setContentView(layoutResID);
    }else{
        super.setContentView(layoutResID);
    }
}

这里说明一下

代码语言:javascript复制
if (proxyActivity == null) {
    proxyActivity.setContentView(layoutResID);
}else{
    super.setContentView(layoutResID);
}

分支的作用 , 在正式发布以后走的是 if (proxyActivity == null) 分支 , 但是在开发阶段 , 并没有注入 Activity , 开发者在组件化调试的时候使用的是 else 分支 , 这里特别注意 , 一定要实现 else 分支 , 否则开发时无法调试 ;

同理 public void setContentView(View view) 方法也需要如下修改 , 将

代码语言:javascript复制
@Override
public void setContentView(View view) {
    super.setContentView(view);
}

修改为 :

代码语言:javascript复制
@Override
public void setContentView(View view) {
    // 调用代理 Activity 中的 setContentView 方法
    if (proxyActivity == null) {
        proxyActivity.setContentView(view);
    }else{
        super.setContentView(view);
    }
}

public <T extends View> T findViewById(int id) 进行如下修改 , 将

代码语言:javascript复制
@Override
public <T extends View> T findViewById(int id) {
    return super.findViewById(id);
}

修改为 :

代码语言:javascript复制
@Override
public <T extends View> T findViewById(int id) {
    if (proxyActivity == null) {
        return proxyActivity.findViewById(id);
    }else{
        return super.findViewById(id);
    }
}

public void startActivity(Intent intent) 方法由

代码语言:javascript复制
@Override
public void startActivity(Intent intent) {
    super.startActivity(intent);
}

修改为 : 注意需要将类名放入 intent , 这个类名就是真正的调用界面跳转的类的类名 ;

代码语言:javascript复制
@Override
public void startActivity(Intent intent) {
    if (proxyActivity == null) {
        intent.putExtra("className", intent.getComponent().getClassName());
        proxyActivity.startActivity(intent);
    }else{
        super.startActivity(intent);
    }
}

二、BaseActivity 完整代码

BaseActivity 完整代码 :

代码语言:javascript复制
package com.example.plugin_core;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

/**
 * " 插件 " 模块中的 Activity 类都继承该类
 * 具体的 Activity 业务类的父类
 */
public class BaseActivity extends AppCompatActivity implements PluginActivityInterface {

    /**
     * 注入的 Activity , 代理该 Activity 类作为上下文
     */
    private Activity proxyActivity;

    /**
     * 注入代理 Activity
     * 在 ProxyActivity 中将代理 Activity 组件注入进来
     * @param proxyActivity
     */
    @Override
    public void attach(Activity proxyActivity) {
        this.proxyActivity = proxyActivity;
    }

    @Override
    public void setContentView(int layoutResID) {
        // 调用代理 Activity 中的 setContentView 方法
        if (proxyActivity == null) {
            proxyActivity.setContentView(layoutResID);
        }else{
            super.setContentView(layoutResID);
        }
    }

    @Override
    public void setContentView(View view) {
        // 调用代理 Activity 中的 setContentView 方法
        if (proxyActivity == null) {
            proxyActivity.setContentView(view);
        }else{
            super.setContentView(view);
        }
    }

    @Override
    public <T extends View> T findViewById(int id) {
        if (proxyActivity == null) {
            return proxyActivity.findViewById(id);
        }else{
            return super.findViewById(id);
        }
    }

    @Override
    public void startActivity(Intent intent) {
        if (proxyActivity == null) {
            intent.putExtra("className", intent.getComponent().getClassName());
            proxyActivity.startActivity(intent);
        }else{
            super.startActivity(intent);
        }
    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onCreate(Bundle savedInstanceState) {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onStart() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onResume() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onPause() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onStop() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onDestroy() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onSaveInstanceState(Bundle outState) {

    }
}

三、博客资源

博客资源 :

  • GitHub : https://github.com/han1202012/Plugin

总结

" 插件 " 模块中的所有 Activity 都要继承 BaseActivity , " 宿主 " 模块运行时 , 为 BaseActivity 中注入了上下文 , 所有涉及上下文的操作 , 如 setContentView , findViewById , startActivity 等方法 , 都需要借助注入的上下文来完成 , 使用插件 Activity 无法完成上述操作 ;

0 人点赞