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 中的上下文 ;
public class BaseActivity extends AppCompatActivity implements PluginActivityInterface {
/**
* 注入的 Activity , 代理该 Activity 类作为上下文
*/
private Activity proxyActivity;
}
插件包中的 Activity 没有上下文对象 , 如果在插件包中的 PluginActivity 中调用与上下文相关的方法 , 如 findViewById
查找组件 , 肯定是无法实现的 , 必须修改 BaseActivity 中与上下文相关的方法 ;
setContentView
中需要调用 super
的 setContentView
方法 , 这里的上下文是无效的 , 也无法成功加载布局文件 , 因此必须调用 private Activity proxyActivity
成员的 setContentView
方法加载布局文件 ;
// 在 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)
方法也需要如下修改 , 将
@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)
进行如下修改 , 将
@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)
方法由
@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 无法完成上述操作 ;