项目中有一个书架的View提供给ReactNative使用,监听ReactNative相应的生命周期进行界面刷新,代码如下
//ViewManager
public class BookShelfManager extends SimpleViewManager<BookShelfView> {
private BookShelfView mBookShelfView;
@Override
protected BookShelfView createViewInstance(ThemedReactContext reactContext) {
mBookShelfView = new BookShelfView(reactContext.getCurrentActivity());
reactContext.addLifecycleEventListener(mBookShelfView);
mBookShelfView.setReactContext(reactContext);
return mBookShelfView;
}
//...
}
public class BookShelfView extends LinearLayout implements LifecycleEventListener {
public BookShelfView(Context context) {
super(context);
this.mContext = context;
initView();
}
public void setReactContext(ReactContext reactContext){
mReactContext = reactContext;
}
//form com.facebook.react.bridge.LifecycleEventListener
@Override
public void onHostResume() {
refresh();
}
//form com.facebook.react.bridge.LifecycleEventListener
@Override
public void onHostDestroy() {
mReactContext.removeLifecycleEventListener(this);
}
ViewManager将ReactContext传给BookShelfView,并且在ReactContext上注册了LifecycleEvent的监听。希望的行为是界面展示的时候触发onHostResume方法执行refresh刷新界面。
然而测试发现一个情况,打开多个ReactNative页面后返回到书架页面时,不能正常刷新。
调试后发现,其他ReactNative页面关闭时也会回调BookShelfView的onHostDestroy使得注销了监听,所以再也收不到onHostResume,所以界面也无法刷新了。
ReactContext源码中onHostResume方法的参数已经表明一个ReactContext可以对应多个Activity,而onHostDestroy是直接通知所有的listener跟Activity无关。
/**
* Should be called by the hosting Fragment in {@link Fragment#onResume}
*/
public void onHostResume(@Nullable Activity activity) {
mLifecycleState = LifecycleState.RESUMED;
mCurrentActivity = new WeakReference(activity);
ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_RESUME_START);
for (LifecycleEventListener listener : mLifecycleEventListeners) {
try {
listener.onHostResume();
} catch (RuntimeException e) {
handleException(e);
}
}
ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_RESUME_END);
}
/**
* Should be called by the hosting Fragment in {@link Fragment#onDestroy}
*/
public void onHostDestroy() {
UiThreadUtil.assertOnUiThread();
mLifecycleState = LifecycleState.BEFORE_CREATE;
for (LifecycleEventListener listener : mLifecycleEventListeners) {
try {
listener.onHostDestroy();
} catch (RuntimeException e) {
handleException(e);
}
}
mCurrentActivity = null;
}
所以在使用LifecyclerEventListener的时候我们需要自己做一层保护,代码如下:
@Override
public void onHostResume() {
//防止其他Activity resume触发刷新
Activity activity = mReactContext.getCurrentActivity();
if (activity != null && activity == mContext){
refresh();
}
}
@Override
public void onHostDestroy() {
//友情提示:rn的ReactContext传给了不同activity,如果不作处理,
//其他RN Activity onDestroy时候会使得监听注销,页面无法刷新.
Activity activity = mReactContext.getCurrentActivity();
if (activity != null && activity == mContext){
mReactContext.removeLifecycleEventListener(this);
}
}
不同的Activity是否共用ReactContext取决于ReactNative同学的代码,不过Android的代码还是应当做一层保护。