问题来源
1.我们的项目中用到了React-Navigation来处理路由,其中用的又是StackNavigation。
2.使用的是ActivityA横屏承载ReactNative的js页面,并且对Android的虚拟按键进行了统一处理
3.最近突然有一个需求,需要再搞一个ActivityB承载一个单页面的竖屏视图
问题暴露
上面的需求实现起来很简单
1.定义一个ActivityB
public class ActivityB extends ReactActivity {
@Override
protected String getMainComponentName() {
return "ActivityB";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
//处理手势,也可以不用实现这个
return new RNGestureHandlerEnabledRootView(ActivityB.this);
}
@Nullable
@Override
protected Bundle getLaunchOptions() {
Intent intent = getIntent();
String flag="";
Bundle bundle = new Bundle();
if (intent.hasExtra("flag")){
flag = intent.getStringExtra("flag");
bundle.putString("flag",flag);
}
return bundle;
}
};
}
}
2.在清单文件中声明
<activity android:name=".ActivityB"
android:screenOrientation="portrait"/>
3.实现桥接方法让ReactNative调用,并且添加到package中,最终注册在Application中
public IntentModule(@NonNull ReactApplicationContext reactContext) {
super(reactContext);
reactContext.addActivityEventListener(new ActivityEventListener() {
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (requestCode==110&&resultCode==111){
if (data!=null){
WritableMap map = Arguments.createMap();
if (data.hasExtra("data")) {
String datas = data.getStringExtra("data");
map.putString("data",datas);
}
if (data.hasExtra("uri")) {
String uri = data.getStringExtra("uri");
map.putString("uri",uri);
}
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("ActivityB", map);
}
}
}
@Override
public void onNewIntent(Intent intent) {
}
});
}
@NonNull
@Override
public String getName() {
return "IntentModule";
}
@ReactMethod
public void jumpCameraActivityForResult(ReadableMap map){
String flag = "";
if (map.hasKey("flag")){
flag = map.getString("flag");
}
Intent intent = new Intent(getCurrentActivity(), ActivityB.class);
if (!TextUtils.isEmpty(flag)){
intent.putExtra("flag",flag);
}
Objects.requireNonNull(getCurrentActivity()).startActivityForResult(intent,CAMERA_REQUEST_CODE);
}
@ReactMethod
public void finish(ReadableMap map){
String data="";
if (map.hasKey("data")){
data = map.getString("data");
}
String uri="";
if (map.hasKey("uri")){
uri=map.getString("uri");
}
Intent intent=new Intent();
if (!TextUtils.isEmpty(data)) {
intent.putExtra("data", data);
}
if (!TextUtils.isEmpty(uri)) {
intent.putExtra("uri", uri);
}
Objects.requireNonNull(getCurrentActivity()).setResult(ACTIVITY_RESULT_CODE,intent);
getCurrentActivity().finish();
}
4.直接在首页中点击进入的二级页面中加入跳转,并且点击返回
最终会发现除了ActivityB返回了,二级页面也不在了。。。。。。。
分析问题
1.首先在跳转ActivityB之前我打印了路由栈中的所有路由
2.在ActivityB退出之后我又打印了路由栈中的所有路由
经过对比确实发现二级页面不见了(不在栈中了)
3.我在路由的pop,rest等页面分别打了日志,发现并没有被调用
排除了方法误调导致的问题
4.去github的issuse里面去看看有没有别人遇到过这个问题
5.百度(无果)
查了一圈发现没有人提到这个问题(得嘞,还得自己排查)
6.我后来就琢磨是不是把ActivityB的虚拟返回去掉,并且ActivityB显示全屏是不是可以解决这个问题
尝试后发现果然可以。。。
7.那没毛病,肯定是ReactNative的返回处理和原生的返回处理都被执行了,导致不仅ActivityB退出了,ReactNative中的二级页面也退出了
8.去看看ReactActivity是如何处理返回的,果不其然发现优先处理ReactNative内部的返回
@Override
public void onBackPressed() {
if (!mDelegate.onBackPressed()) {
super.onBackPressed();
}
}
到这里就简单了我不让他走ReactNative内部的返回不就行了,返回false给他
到这里本次的问题就圆满解决了。
附上ActivityB的整体源码
public class ActivityB extends ReactActivity {
@Override
protected String getMainComponentName() {
return "ActivityB";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
public boolean onBackPressed() {
return false;
}
@Nullable
@Override
protected Bundle getLaunchOptions() {
Intent intent = getIntent();
String flag="";
Bundle bundle = new Bundle();
if (intent.hasExtra("flag")){
flag = intent.getStringExtra("flag");
bundle.putString("flag",flag);
}
return bundle;
}
};
}
}