Android 轻量插件化:Service 怎么代理,为什么它比 Activity 简单

Activity 代理搞清楚以后,Service 就比较容易理解了。

假设插件里有:

1
2
3
4
5
6
public class UploadService implements PluginService {
@Override
public void onStartCommand(Intent intent) {
// 上传任务
}
}

但是系统不知道这个 Service 存在。

1. ProxyService

宿主注册一个固定 Service:

1
2
3
<service
android:name=".plugin.ProxyService"
android:exported="false" />

启动插件 Service 时,不直接启动插件类,而是:

1
2
3
Intent intent = new Intent(context, ProxyService.class);
intent.putExtra("plugin_service", "com.demo.plugin.UploadService");
context.startService(intent);

2. ProxyService

ProxyService 启动以后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ProxyService extends Service {

private PluginService target;

@Override
public int onStartCommand(Intent intent,
int flags,
int startId) {

String className = intent.getStringExtra("plugin_service");

target = pluginManager.createService(className);
target.onStartCommand(intent);

return START_STICKY;
}
}

核心逻辑其实和 Activity 一模一样:

1
2
3
4
5
6
7
插件 Service
↓ 替换
ProxyService

系统真正启动 ProxyService

ProxyService 创建插件 Service

3. ServiceContext

插件 Service 如果要调用:

1
startActivity(...)

或者:

1
getResources()

仍然需要一个插件 Context。

所以前一篇的 PluginContext 可以继续复用。

4. bindService 怎么办

启动 Service 只是第一步。

如果插件使用:

1
bindService(intent, connection, BIND_AUTO_CREATE);

事情就复杂了一点,因为系统返回的是 ProxyService 的 Binder。

一个比较轻量的做法,是让 ProxyService 持有插件 Service 对象,并由它统一返回插件定义的 Binder:

1
2
3
4
5
public interface PluginService {
IBinder onBind(Intent intent);
void onStartCommand(Intent intent);
void onDestroy();
}

ProxyService:

1
2
3
4
5
6
7
@Override
public IBinder onBind(Intent intent) {
if (target == null) {
createTarget(intent);
}
return target.onBind(intent);
}

5. 多个插件 Service

一个 ProxyService 可以管理多个插件 Service 实例,但需要注意生命周期。

简单做法可以用 Map:

1
Map<String, PluginService> services = new HashMap<>();

key 使用插件 Service 的完整类名。

这样:

1
2
3
4
ProxyService
├── plugin.AService
├── plugin.BService
└── plugin.CService

不过真正生产环境还需要处理 startId、stopSelf、bind/unbind、多客户端等问题。

6. Service 为什么适合第二个实现

因为它没有 Activity 的 Window 体系。

所以如果想自己动手写插件化框架,Service 是很适合拿来验证架构的一环。

下一篇继续看 BroadcastReceiver。

它反而会暴露出一个问题:静态注册和动态注册不是一回事。

坚持原创技术分享,您的支持将鼓励我继续创作!