Skip to content

Commit

Permalink
使导航相关操作在 resumed 状态下执行
Browse files Browse the repository at this point in the history
  • Loading branch information
listenzz committed May 17, 2021
1 parent 750450e commit 94bee17
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
Expand All @@ -32,16 +33,20 @@
/**
* Created by Listen on 2017/11/20.
*/
public class NavigationModule extends ReactContextBaseJavaModule {
public class NavigationModule extends ReactContextBaseJavaModule implements LifecycleEventListener {

static final String TAG = "ReactNative";
static final Handler sHandler = new Handler(Looper.getMainLooper());

private final ReactBridgeManager bridgeManager;
private final ReactApplicationContext reactContext;
private final UiTaskExecutor uiTaskExecutor = new UiTaskExecutor();

NavigationModule(ReactApplicationContext reactContext, ReactBridgeManager bridgeManager) {
super(reactContext);
this.bridgeManager = bridgeManager;
this.reactContext = reactContext;
reactContext.addLifecycleEventListener(this);
}

@NonNull
Expand All @@ -53,14 +58,17 @@ public String getName() {
@Override
public void onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy();
reactContext.removeLifecycleEventListener(this);
FLog.i(TAG, "NavigationModule#onCatalystInstanceDestroy");
sHandler.removeCallbacksAndMessages(null);
sHandler.post(() -> {
uiTaskExecutor.clear();
List<ReactBridgeManager.ReactBridgeReloadListener> listeners = bridgeManager.getReactBridgeReloadListeners();
for (ReactBridgeManager.ReactBridgeReloadListener listener : listeners) {
listener.onReload();
}
listeners.clear();
bridgeManager.setPendingLayout(null, 0);
bridgeManager.setReactModuleRegisterCompleted(false);
bridgeManager.setViewHierarchyReady(false);
Activity activity = getCurrentActivity();
Expand All @@ -71,6 +79,23 @@ public void onCatalystInstanceDestroy() {
});
}

@Override
public void onHostResume() {
FLog.w(TAG, "NavigationModule#onHostResume");
uiTaskExecutor.notifyResume();
}

@Override
public void onHostPause() {
FLog.w(TAG, "NavigationModule#onHostPause");
uiTaskExecutor.notifyPause();
}

@Override
public void onHostDestroy() {
FLog.w(TAG, "NavigationModule#onHostDestroy");
}

@Nullable
@Override
public Map<String, Object> getConstants() {
Expand Down Expand Up @@ -109,43 +134,48 @@ public void signalFirstRenderComplete(final String sceneId) {
@ReactMethod
public void setRoot(final ReadableMap layout, final boolean sticky, final int tag) {
sHandler.post(() -> {
ReactContext reactContext = getReactApplicationContext();
if (!reactContext.hasActiveCatalystInstance()) {
FLog.w(TAG, "ReactContext has not active catalyst instance, skip action `setRoot`");
return;
}

if (bridgeManager.getPendingTag() != 0) {
throw new IllegalStateException("The previous `setRoot` has not been processed yet, you should `await Navigator.setRoot()` to complete.");
}
uiTaskExecutor.submit(() -> {
ReactContext reactContext = getReactApplicationContext();
if (!reactContext.hasActiveCatalystInstance()) {
FLog.w(TAG, "ReactContext has not active catalyst instance, skip action `setRoot`");
return;
}

bridgeManager.setViewHierarchyReady(false);
bridgeManager.setRootLayout(layout, sticky);
Activity activity = getCurrentActivity();
if (activity instanceof ReactAppCompatActivity && bridgeManager.isReactModuleRegisterCompleted()) {
ReactAppCompatActivity reactAppCompatActivity = (ReactAppCompatActivity) activity;
AwesomeFragment fragment = bridgeManager.createFragment(layout);
if (fragment != null) {
FLog.i(TAG, "Have active activity and react module was registered, set root directly");
reactAppCompatActivity.setActivityRootFragment(fragment, tag);
if (bridgeManager.getPendingTag() != 0) {
FLog.e(TAG, "The previous tag: " + bridgeManager.getPendingTag() + " layout: " + bridgeManager.getPendingLayout());
FLog.e(TAG, "Current tag: " + tag + " layout: " + layout);
throw new IllegalStateException("The previous `setRoot` has not been processed yet, you should `await Navigator.setRoot()` to complete.");
}
} else {
FLog.w(TAG, "Have no active activity or react module was not registered, schedule pending root");

bridgeManager.setViewHierarchyReady(false);
bridgeManager.setRootLayout(layout, sticky);
bridgeManager.setPendingLayout(layout, tag);
}

Activity activity = getCurrentActivity();
if (activity instanceof ReactAppCompatActivity && bridgeManager.isReactModuleRegisterCompleted()) {
ReactAppCompatActivity reactAppCompatActivity = (ReactAppCompatActivity) activity;
AwesomeFragment fragment = bridgeManager.createFragment(layout);
if (fragment != null) {
FLog.i(TAG, "Have active Activity and react module was registered, set root Fragment immediately");
reactAppCompatActivity.setActivityRootFragment(fragment, tag);
}
}
});
});
}

@ReactMethod
public void dispatch(final String sceneId, final String action, final ReadableMap extras, Promise promise) {
sHandler.post(() -> {
AwesomeFragment target = findFragmentBySceneId(sceneId);
if (target != null && target.isAdded()) {
bridgeManager.handleNavigation(target, action, extras, promise);
} else {
promise.resolve(false);
FLog.w(TAG, "Can't find target scene for action:" + action + ", maybe the scene is gone.\nextras: " + extras);
}
uiTaskExecutor.submit(() -> {
AwesomeFragment target = findFragmentBySceneId(sceneId);
if (target != null && target.isAdded()) {
bridgeManager.handleNavigation(target, action, extras, promise);
} else {
promise.resolve(false);
FLog.w(TAG, "Can't find target scene for action:" + action + ", maybe the scene is gone.\nextras: " + extras);
}
});
});
}

Expand Down Expand Up @@ -182,7 +212,6 @@ public void setResult(final String sceneId, final int resultCode, final Readable
fragment.setResult(resultCode, Arguments.toBundle(result));
}
});

}

@ReactMethod
Expand Down Expand Up @@ -328,4 +357,6 @@ private AwesomeFragment findFragmentBySceneId(String sceneId) {
}
return null;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ public void inflateStyle() {
Style style = getStyle();
GlobalStyle globalStyle = Garden.getGlobalStyle();
if (style != null && globalStyle != null && !isFinishing()) {
if (styleInflated) {
FLog.i(TAG, "Going to inflate style again.");
}
styleInflated = true;
FLog.i(TAG, "ReactAppCompatActivity#inflateStyle");
globalStyle.inflateStyle(this, style);
Expand All @@ -97,11 +94,11 @@ public void setActivityRootFragment(@NonNull AwesomeFragment rootFragment) {

public void setActivityRootFragment(@NonNull AwesomeFragment rootFragment, int tag) {
if (getSupportFragmentManager().isStateSaved()) {
FLog.i(TAG, "Schedule to set activity root fragment.");
FLog.i(TAG, "Schedule to set Activity root Fragment.");
scheduleTaskAtStarted(() -> setActivityRootFragmentSync(rootFragment, tag));
} else {
if (!isFinishing()) {
FLog.i(TAG, "Set activity root fragment immediately.");
FLog.i(TAG, "Set Activity root Fragment immediately.");
setActivityRootFragmentSync(rootFragment, tag);
}
}
Expand Down Expand Up @@ -139,22 +136,22 @@ protected void onCreateMainComponent() {
reactNavigationFragment.setRootFragment(awesomeFragment);
setActivityRootFragment(reactNavigationFragment);
} else if (bridgeManager.hasPendingLayout()) {
FLog.i(TAG, "set root from pending layout when create main component");
FLog.i(TAG, "Set root Fragment from pending layout when create main component");
setActivityRootFragment(bridgeManager);
} else if (bridgeManager.hasStickyLayout()) {
FLog.i(TAG, "set root from sticky layout when create main component");
FLog.i(TAG, "Set root Fragment from sticky layout when create main component");
AwesomeFragment fragment = bridgeManager.createFragment(bridgeManager.getStickyLayout());
if (fragment != null) {
setActivityRootFragment(fragment);
}
} else if (bridgeManager.hasRootLayout()) {
FLog.i(TAG, "set root from last root layout when create main component");
FLog.i(TAG, "Set root Fragment from last root layout when create main component");
AwesomeFragment fragment = bridgeManager.createFragment(bridgeManager.getRootLayout());
if (fragment != null) {
setActivityRootFragment(fragment);
}
} else {
FLog.w(TAG, "no layout to set when create main component");
FLog.w(TAG, "No layout to set when create main component");
}
}

Expand Down Expand Up @@ -183,9 +180,10 @@ private void setActivityRootFragment(ReactBridgeManager bridgeManager) {
int pendingTag = bridgeManager.getPendingTag();
ReadableMap pendingLayout = bridgeManager.getPendingLayout();
AwesomeFragment fragment = bridgeManager.createFragment(pendingLayout);
bridgeManager.setPendingLayout(null, 0);
if (fragment != null) {
setActivityRootFragment(fragment, pendingTag);
} else {
FLog.e(TAG, "Could not create fragment from pending layout.");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.reactnative.hybridnavigation;

import com.facebook.react.bridge.UiThreadUtil;

import java.util.LinkedList;
import java.util.Queue;

public class UiTaskExecutor {

private Queue<Runnable> tasks = new LinkedList<>();

public void submit(Runnable task) {
UiThreadUtil.assertOnUiThread();
tasks.add(task);
considerExecute();
}

public void clear() {
tasks.clear();
}

private boolean resumed;

public void notifyResume() {
resumed = true;
considerExecute();
}

public void notifyPause() {
resumed = false;
}

private boolean executing;

private void considerExecute() {
if (!executing && resumed) {
executing = true;
Runnable runnable = tasks.poll();
while (runnable != null && resumed) {
runnable.run();
runnable = tasks.poll();
}
executing = false;
}
}

}

0 comments on commit 94bee17

Please sign in to comment.