以下分析基于flutter_boost分支feature/flutter_1.9_androidx_upgrade
在Android當(dāng)activityA打開activityB之后砾莱,如果想要在activityA中拿到activityB的結(jié)果丹壕,一般是通過onActivityResutl()方法獲得。
這在Flutter當(dāng)中相當(dāng)于Future职辅。原生flutter中取得這個(gè)future很簡(jiǎn)單厌均。因?yàn)閺膄lutterA跳轉(zhuǎn)到flutterB唬滑,其實(shí)還是在一個(gè)activity中實(shí)現(xiàn)的,只需要
var future = Navigator.of(context).pushNamed("destRouteName");
就可以拿到這個(gè)future棺弊。
但是如果用到了混合棧晶密,比如flutterA-->activityB這樣的話,在flutterA中想要取得activityB的返回結(jié)果模她,就相對(duì)麻煩了稻艰。這里提供的是解決flutter_boost中出現(xiàn)此類問題的方案。
一 分析
1:Flutter側(cè)
在flutter_boost中缝驳,如果在flutterA中想要打開flutterB頁面连锯。在flutterA中可以調(diào)用
var future =await FlutterBoost.singleton.open("flutterB");
future.then((result){
print($result);
});
此時(shí)如果是默認(rèn)情況下归苍,那么當(dāng)flutterB頁面關(guān)閉時(shí)用狱,將會(huì)在flutterA中打印
{_resultCode__: -1, _requestCode__: -1}
當(dāng)我們?cè)趂lutterA中調(diào)用了FlutterBoost.singleton.open("flutterB")實(shí)際上是進(jìn)入了
Future<Map<dynamic,dynamic>> open(String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts}){
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
properties["url"] = url;
properties["urlParams"] = urlParams;
properties["exts"] = exts;
return channel.invokeMethod<Map<dynamic,dynamic>>(
'openPage', properties);
}
由于我們沒有傳入其他參數(shù),因此urlParams和exts都是null拼弃。方法體中夏伊,通過新創(chuàng)建一個(gè)Map<dynamic,dynamic> properties將所有參數(shù)組裝進(jìn)來。然后進(jìn)入
channel.invokeMethod<Map<dynamic,dynamic>>('openPage', properties);
這個(gè)channel是flutter_boost庫中的BoostChannel吻氧。而BoostChannel其實(shí)內(nèi)部維護(hù)了一個(gè)MethodChannel
class BoostChannel{
final MethodChannel _methodChannel = MethodChannel("flutter_boost");
………
Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) async {
assert(method != "__event__");
return _methodChannel.invokeMethod<T>(method,arguments);
}
}
2:Android側(cè)
上面在flutterA中打開一個(gè)flutterB頁面溺忧,通過調(diào)用flutter_boost內(nèi)部的open方法實(shí)現(xiàn)咏连。該open方法實(shí)際上是通過methodChannel來調(diào)用Android測(cè)的方法來最終打開flutterB頁面的。其實(shí)在flutter_boost中鲁森,任何一個(gè)flutter頁面都有一個(gè)NewBoostFlutterActivity與之對(duì)應(yīng)祟滴。當(dāng)調(diào)用找到了"openPage"方法時(shí)
class BoostMethodHandler implements MethodChannel.MethodCallHandler {
@Override
public void onMethodCall(MethodCall methodCall, final MethodChannel.Result result) {
FlutterViewContainerManager mManager = (FlutterViewContainerManager) NewFlutterBoost.instance().containerManager();
switch (methodCall.method) {
……
case "openPage": {
try {
Map<String, Object> params = methodCall.argument("urlParams");
Map<String, Object> exts = methodCall.argument("exts");
String url = methodCall.argument("url");
mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
@Override
public void onResult(Map<String, Object> rlt) {
if (result != null) {
result.success(rlt);
}
}
});
} catch (Throwable t) {
result.error("open page error", t.getMessage(), t);
}
}
break;
……
default: {
result.notImplemented();
}
}
}
}
在openPage中取出參數(shù)。然后調(diào)用
mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
@Override
public void onResult(Map<String, Object> rlt) {
if (result != null) {
result.success(rlt);
}
}
});
而剛才我們?cè)陉P(guān)閉flutterB頁面時(shí)歌溉,flutterA頁面中打印了
{_resultCode__: -1, _requestCode__: -1}
這個(gè)打印結(jié)果就是通過
result.success(rlt);
返回的垄懂。而這個(gè)onResult()方法是在FlutterViewContainerManager中調(diào)用的
void setContainerResult(IContainerRecord record,int requestCode, int resultCode, Map<String,Object> result) {
IFlutterViewContainer target = findContainerById(record.uniqueId());
if(target == null) {
Debuger.exception("setContainerResult error, url="+record.getContainer().getContainerUrl());
}
if (result == null) {
result = new HashMap<>();
}
result.put("_requestCode__",requestCode);
result.put("_resultCode__",resultCode);
final OnResult onResult = mOnResults.remove(record.uniqueId());
if(onResult != null) {
onResult.onResult(result);
}
}
而setContainerResult()在兩個(gè)地方進(jìn)行了調(diào)用。
(1) 在onDestory()
NewBoostFlutterAcitivity.onDestory();
delegate.onDestroyView();
mSyncer.onDestroy(); //IOperateSyncer的具體實(shí)現(xiàn)是ContainerRecord
在這個(gè)具體顯示中返回了-1
@Override
public void onDestroy() {
Utils.assertCallOnMainThread();
if (mState != STATE_DISAPPEAR) {
Debuger.exception("state error");
}
mState = STATE_DESTROYED;
mProxy.destroy();
mManager.removeRecord(this);
mManager.setContainerResult(this,-1,-1,null);
}
(2)在onActivityResult()
NewBoostFlutterAcitivity.onActivityResult()
delegate.onActivityResult(requestCode, resultCode, data);
在delegate中
void onActivityResult(int requestCode, int resultCode, Intent data) {
mSyncer.onActivityResult(requestCode,resultCode,data);
……
mSyncer.onContainerResult(requestCode,resultCode,result);
……
}
二:結(jié)論
在回顧一下問題痛垛,如果我們要在flutterA頁面中打開B頁面草慧,并且想要獲得B頁面的返回結(jié)果。需要區(qū)別B頁面是Flutter頁面還是Android原生頁面匙头。
1:B頁面是Flutter頁面
那就要根據(jù)實(shí)際情況重新在onDestory中返回不同的參數(shù)漫谷,而不是一刀切的返回-1,-1蹂析,null
setContainerResult(IContainerRecord record,int requestCode, int resultCode, Map<String,Object> result)
2:B頁面是原生頁面
由于methodChannel中的MethodChannel.Result對(duì)象只有在FlutterBoostPlugin中的OnResult中的onResult()中可以調(diào)用舔示。
FlutterViewContainerManager mManager = (FlutterViewContainerManager) NewFlutterBoost.instance().containerManager();
mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
@Override
public void onResult(Map<String, Object> rlt) {
if (result != null) {
result.success(rlt);
}
}
});
因此代碼如下
FlutterViewContainerManager mManager = (FlutterViewContainerManager) NewFlutterBoost.instance().containerManager();
mManager.setContainerResult(參數(shù)設(shè)置);
參數(shù)需要自己設(shè)置。
上面的解決方案并不完善电抚,只能暫時(shí)解決業(yè)務(wù)問題斩郎。如果看官有更好的處理方案,歡迎指教喻频。