简述:
Atlas提供了3中通讯方式分别是:RemoteTransactor、RemoteView、RemoteFragment.
RemoteTransactor是RemoteView、RemoteFragment 通讯方式的简化版仅仅为了Bundle和Bundle之间的通讯而存在,这篇文章将提供简单的使用实例,和源码简析和指出其中存在的坑。
场景还原
准备:打开开发者选项——》不保留活动 模拟后台页面被回收的场景
测试 :
1.打开应用页面调用顺序 MainActivity ——> ActivityA
2. 点击返回键
正常情况下MainActivity的生命周期会走 onSaveInstanceState,点击返回键后走 onRestoreInstanceState 返回MainActivity页面
诡异现象:
我们发现我们的app并没有这样走,流程这样的 MainActivity的生命周期会走 onSaveInstanceState ——> onDestory——> finish 点击返回键后直接回到了桌面吗,这样的体验不能忍的。
调用实例
/**
* 初始化
*
* @param activity
*/
public static void initQbank(Activity activity) {
RemoteFactory.requestRemote(RemoteTransactor.class, activity, new Intent(BundleIntent.FLAG_QUESTION_BANK),
new RemoteFactory.OnRemoteStateListener() {
@Override
public void onRemotePrepared(RemoteTransactor iRemote) {
iRemote.call(String.valueOf(SKIP.INIT_ENV), new Bundle(), new IRemoteTransactor.IResponse() {
@Override
public void OnResponse(Bundle bundle) {
}
});
}
@Override
public void onFailed(String s) {
Log.e("UserRemoteActivity", s);
}
});
}
出了问题不能怂啊,让我们跟下源码看一下
//参数讲解:
// remoteClass 指定通讯方式
// activity 为了获取 remoteActivity 即 remoteTransactor.remoteActivity
// intent 存储目标bundle的标识
// listener 找到目标bundle后留给我们的回调去做后续的处理
public static <T extends IRemoteContext> void requestRemote(final Class<T> remoteClass,final Activity activity,final Intent intent, final OnRemoteStateListener listener){
//... 关键代码讲解,可以跟着源码去梳理
// 获取到目标标识,这个我们在清单文件通过 标签配置过
final String key = intent.getComponent()!=null ? intent.getComponent().getClassName() :intent.getAction();
String tempBundleName = null;
//判断通讯方式
if(remoteClass == RemoteView.class){
tempBundleName = AtlasBundleInfoManager.instance().getBundleForRemoteView(key);
}else if(remoteClass == RemoteTransactor.class){ //这次我们讲解的是这个
tempBundleName = AtlasBundleInfoManager.instance().getBundleForRemoteTransactor(key);
}else if(remoteClass == RemoteFragment.class){
tempBundleName = AtlasBundleInfoManager.instance().getBundleForRemoteFragment(key);
}
//获取到目标bundle的name
final String bundleName = tempBundleName;
...
//获取我们通信类
RemoteTransactor transactor = RemoteTransactor.crateRemoteTransactor(activity,key,bundleName);
//回调,在上面实例代码中可以看到
listener.onRemotePrepared(transactor);
//...
}
具体讲解 RemoteTransactor实例的生成
//代码引入
RemoteTransactor transactor = RemoteTransactor.crateRemoteTransactor(activity,key,bundleName);
public static RemoteTransactor crateRemoteTransactor(Activity activity,String key,String bundleName) throws Exception{
//创建远程RemoteTransactor 实例
RemoteTransactor remoteTransactor = new RemoteTransactor();
//目标bundle的名字
remoteTransactor.targetBundleName = bundleName;
//注意这个时候需要用到activity 这个我建议了Atlas团队去掉,这个Activity参数在这里除了引起误会意外并没有其他作用
if(activity!=null) {
remoteTransactor.remoteActivity = RemoteActivityManager.obtain(activity).getRemoteHost(remoteTransactor);
}
//获取目标bundle的信息
final BundleListing.BundleInfo bi = AtlasBundleInfoManager.instance().getBundleInfo(bundleName);
//根据清单文件中的key获取到目标bundle中的目标文件
String viewClassName = bi.remoteTransactors.get(key);
//通过反射拿到目标类
Class transactorClass = Atlas.getInstance().getBundleClassLoader(bundleName).loadClass(viewClassName);
//创建目标类的实例
IRemote remote = (IRemote)transactorClass.newInstance();
//将目标类实例存到remoteTransactor中
remoteTransactor.targetTransactor = remote;
//为targetTransactor 的remoteContext赋值
Util.findFieldFromInterface(remoteTransactor.targetTransactor,"remoteContext").set(remoteTransactor.targetTransactor,remoteTransactor);
//为targetTransactor 的realHost赋值 Util.findFieldFromInterface(remoteTransactor.targetTransactor,"realHost").set(remoteTransactor.targetTransactor,remoteTransactor.remoteActivity);
//这两句代码在这种通讯方式中完全没有用,估计是阿里的同学copy的结果,鄙视下不追求整洁
return remoteTransactor;
}
好了我们获取到了我们的RemoteTransactor 实例,在上面的实例中我们看到了listener.onRemotePrepared(transactor);回调 这个时候我们就梳理流畅了吧
RemoteTransactor 中的call 方法
@Override
public Bundle call(String commandName, Bundle args, IResponse callback) {
//就是这么回事
return targetTransactor.call(commandName,args,callback);
}
调用远端bundle的方法
@Override
public void onRemotePrepared(RemoteTransactor iRemote) {
iRemote.call(String.valueOf(SKIP.INIT_ENV), new Bundle(), new IRemoteTransactor.IResponse() {
@Override
public void OnResponse(Bundle bundle) {
}
});
}
目标类实现IRemote 接口
public class Entrance implements IRemote {
...
@Override
public Bundle call(String commandName, Bundle args, IResponse callback) {
int flag = Integer.parseInt(commandName);
if (flag == LiveSKIP.INIT_ENV) {
String env = args.getString(Args.ENV);
initPermission(env);
} else if (flag == LiveSKIP.RECORD) {
//回放
toRecord(ApplicationsHelper.context(), args);
// testToRecord(ApplicationsHelper.context(), args);
} else if(flag == LiveSKIP.LIVING) {
jumpToliving(ApplicationsHelper.context(), args);
}
callback.OnResponse(null);
return null;
}
}
这算是将RemoteTransactor 这种通讯方式梳理完了,里面还有很多细节,感兴趣的可以再扒源码看看
坑
Q25:RemoteTransactor 通讯方式引起的问题
A:如果使用RemoteTransactor 这种通讯方式的话,调用 RemoteFactory.requestRemote 时候最好
activity 传为null,避免不必要的问题,否则这个activity有可能被finish掉引起一些奇怪的现象
这个在Atlas外部交流群中我已经提出来了并写在了小喇叭里