上一篇介绍了如何通过占位的方式启动插件中的Activity,遗漏了插件内部跳转Activity,这里先介绍一下。
首先插件内部跳转activity代码如下:
findViewById(R.id.btn).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(mActivity ,SecondActivity.class)); } });
从上一篇我们知道我们会在插件Activity的父类BaseActivity中重新startActivity。如下:
public void startActivity(Intent intent){ Intent newIntent=new Intent(); newIntent.putExtra("className" ,intent.getComponent().getClassName()); mActivity.startActivity(newIntent); }
因为mActivity是宿主注入进来的,相当于调用了我们的代理Activity中的startActivity。那么我们需要在ProxyActivity中重写startActivity。
ProxyActivity中的startActivity方法如下:
@Override public void startActivity(Intent intent) { String className = intent.getStringExtra("className"); Intent proxyIntent=new Intent(this,ProxyActivity.class); proxyIntent.putExtra("className",className); super.startActivity(proxyIntent); }
,然后将传递过来的插件跳转的目标Activity的全类名获取,然后跳转到我们的ProxyActivity,因为ProxyActivity是standard模式的,可以模拟Activity栈。然后我们在ProxyActivity中的onCreate中接收我们的全类名,进行反射,强转为我们的插件实现标准的实例,然后注入上下文,调用生命周期函数。核心代码如下:
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //加载真正插件里面的Activity String className=getIntent().getStringExtra("className"); try { Class mPluginActivityClass= getClassLoader() .loadClass(className); //实例化插件包里面的Activity Constructor constructor = mPluginActivityClass.getConstructor(new Class[]{}); Object mPluginActivity = constructor.newInstance(new Object[]{}); ActivityInterface activityInterface= (ActivityInterface) mPluginActivity; //注入上下文到插件中 activityInterface.insertAppContext(this); //执行插件里面的onCreate Bundle bundle=new Bundle(); bundle.putString("appName","我是宿主传递过来的信息"); activityInterface.onCreate(bundle); } catch (Exception e) { e.printStackTrace(); } }
效果如下:
接着我们的今天的主题----插件化之Service占位式
首先我们在插件内启动service,我们在PluginActivity中启动Activity
findViewById(R.id.btn_service) .setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(mActivity ,PluginService.class)); } });
和Activity插件化套路相同,我们在插件内创建一个BaseService,继承Service,实现我们的服务的标准ServiceInterface.
ServiceInterface如下:
public interface ServiceInterface { void insertAppContext(Service service); IBinder onBind(Intent intent); void onCreate(); int onStartCommand(Intent intent, int flags, int startId); void onDestroy();}
BaseService如下:
public class BaseService extends Service implements ServiceInterface { public Service appService; /** * 将宿主环境注入到插件内 * @param service */ @Override public void insertAppContext(Service service) { this.appService=service; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { } @SuppressLint("WrongConstant") @Override public int onStartCommand(Intent intent, int flags, int startId) { return 0; } @Override public void onDestroy() { }}
在插件中自定义服务,模拟每隔1s打印一次日志
** * 插件服务 */public class PluginService extends BaseService { public static final String TAG=PluginService.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //开启子线程,执行耗时任务 new Thread(new Runnable() { @Override public void run() { while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }finally { Log.d(TAG,"插件里面的服务正在执行中..."); } } } }).start(); return super.onStartCommand(intent, flags, startId); }}
当我们在我们的插件Activity启动插件服务的时候,如
startService(new Intent(mActivity,PluginService.class));
因为没有安装,没有上下文,因为我们知道startService最终是调用ContextImpl中的startService。所以我们需要在我们的插件中的BaseActivity中重新我们的startService,如下所示:
@Override public ComponentName startService(Intent service) { Intent newIntent=new Intent(); newIntent.putExtra("className" ,service.getComponent().getClassName()); return mActivity.startService(newIntent); }
将我们插件中的服务的全类名作为参数传递到我们mActivity也就是我们宿主的代理Activity中的startService中。那么我们去ProxyActivity中去重新startService方法,如下:
@Override public ComponentName startService(Intent service) { String className = service.getStringExtra("className"); Intent proxyIntent=new Intent(this,ProxyService.class); proxyIntent.putExtra("className",className); return super.startService(proxyIntent); }
那么这个ProxyService是啥呢,还是原来的套路,和ProxyActivity是一样一样的。
我们来看一下ProxyService的核心代码如下:
public class ProxyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { String className = intent.getStringExtra("className"); try { Class> clazz = PluginManager.getInstance(this).getClassLoader().loadClass(className); Object pluginService = clazz.newInstance(); ServiceInterface serviceInterface= (ServiceInterface) pluginService; serviceInterface.insertAppContext(this); serviceInterface.onStartCommand(intent,flags,startId); } catch (Exception e) { e.printStackTrace(); } return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { super.onCreate(); }}
上面代码的核心逻辑:接受传递过来的插件服务的全类名,然后通过反射实例化,然后强转成服务标准ServiceInterface的实例,然后注入环境,调用插件中对应的方法,如onStartCommand
测试效果如下:
总结,插件化占位式Service通信,核心逻辑如下图:
是不是很简单~
注意:插件内部的服务不用在AndroidManifest.xml中注册,但是代理服务是需要在宿主中注册的。
源码:https://github.com/FOREVER001/plugin-activity.git