FlutterEngineCache

BaseOnFlutter2.0

FlutterEngineCache

public class FlutterEngineCache {
  private static FlutterEngineCache instance;

  private final Map<String, FlutterEngine> cachedEngines = new HashMap<>();
}

FlutterEngineInit

graph LR
FlutterApplication-->|after onCreate|flutterLoader.startInit-->similarToFlutter1.12

FlutterEngine-->initAssetManager
FlutterEngine-->initDartExecutor
FlutterEngine-->initMultipleChannels
FlutterEngine-->flutterLoader.startInitAndBlockUtilComplete
FlutterEngine-->flutterJNI.attachToNativeShell/Engine-->similarToFlutter1.12WhenConstuctFlutterView
FlutterEngine-->initFlutterRendererAndPlatformViewsController

FlutterEngine-->automaticallyRegisterPlugins

FlutterEngine

Constructor

public FlutterEngine(@NonNull Context context, @Nullable String[] dartVmArgs) {
  this(context, /* flutterLoader */ null, new FlutterJNI(), dartVmArgs, true);
}
/** Fully configurable {@code FlutterEngine} constructor. */
public FlutterEngine(
    @NonNull Context context,
    @Nullable FlutterLoader flutterLoader,
    @NonNull FlutterJNI flutterJNI,
    @NonNull PlatformViewsController platformViewsController,
    @Nullable String[] dartVmArgs,
    boolean automaticallyRegisterPlugins,
    boolean waitForRestorationData) {
  AssetManager assetManager;
  try {
    assetManager = context.createPackageContext(context.getPackageName(), 0).getAssets();
  } catch (NameNotFoundException e) {
    assetManager = context.getAssets();
  }
  this.dartExecutor = new DartExecutor(flutterJNI, assetManager);
  this.dartExecutor.onAttachedToJNI();

  DeferredComponentManager deferredComponentManager =
      FlutterInjector.instance().deferredComponentManager();

  accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
  deferredComponentChannel = new DeferredComponentChannel(dartExecutor);
  keyEventChannel = new KeyEventChannel(dartExecutor);
  lifecycleChannel = new LifecycleChannel(dartExecutor);
  localizationChannel = new LocalizationChannel(dartExecutor);
  mouseCursorChannel = new MouseCursorChannel(dartExecutor);
  navigationChannel = new NavigationChannel(dartExecutor);
  platformChannel = new PlatformChannel(dartExecutor);
  restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData);
  settingsChannel = new SettingsChannel(dartExecutor);
  systemChannel = new SystemChannel(dartExecutor);
  textInputChannel = new TextInputChannel(dartExecutor);

  if (deferredComponentManager != null) {
    deferredComponentManager.setDeferredComponentChannel(deferredComponentChannel);
  }

  this.localizationPlugin = new LocalizationPlugin(context, localizationChannel);

  this.flutterJNI = flutterJNI;
  if (flutterLoader == null) {
    flutterLoader = FlutterInjector.instance().flutterLoader();
  }

  if (!flutterJNI.isAttached()) {
    flutterLoader.startInitialization(context.getApplicationContext());
    flutterLoader.ensureInitializationComplete(context, dartVmArgs);
  }

  flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
  flutterJNI.setPlatformViewsController(platformViewsController);
  flutterJNI.setLocalizationPlugin(localizationPlugin);
  flutterJNI.setDeferredComponentManager(FlutterInjector.instance().deferredComponentManager());

  // It should typically be a fresh, unattached JNI. But on a spawned engine, the JNI instance
  // is already attached to a native shell. In that case, the Java FlutterEngine is created around
  // an existing shell.
  if (!flutterJNI.isAttached()) {
    attachToJni();
  }

  // TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if
  // possible.
  this.renderer = new FlutterRenderer(flutterJNI);

  this.platformViewsController = platformViewsController;
  this.platformViewsController.onAttachedToJNI();

  this.pluginRegistry =
      new FlutterEngineConnectionRegistry(context.getApplicationContext(), this, flutterLoader);

  if (automaticallyRegisterPlugins) {
    registerPlugins();
  }
}

getNavigationChannel

/** System channel that sends Flutter navigation commands from Android to Flutter. */
@NonNull
public NavigationChannel getNavigationChannel() {
  return navigationChannel;
}
public class NavigationChannel {
  private static final String TAG = "NavigationChannel";

  @NonNull public final MethodChannel channel;

  public NavigationChannel(@NonNull DartExecutor dartExecutor) {
    this.channel = new MethodChannel(dartExecutor, "flutter/navigation", JSONMethodCodec.INSTANCE);
  }

  public void setInitialRoute(@NonNull String initialRoute) {
    Log.v(TAG, "Sending message to set initial route to '" + initialRoute + "'");
    channel.invokeMethod("setInitialRoute", initialRoute);
  }

  public void pushRoute(@NonNull String route) {
    Log.v(TAG, "Sending message to push route '" + route + "'");
    channel.invokeMethod("pushRoute", route);
  }

  public void popRoute() {
    Log.v(TAG, "Sending message to pop route.");
    channel.invokeMethod("popRoute", null);
  }

  public void setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler) {
    channel.setMethodCallHandler(handler);
  }
}

FlutterActivity.cachedEngineId

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  delegate = new FlutterActivityAndFragmentDelegate(this);
  delegate.onAttach(this);//main
  delegate.onRestoreInstanceState(savedInstanceState);
}
//FlutterActivityAndFragmentDelegate
void onAttach(@NonNull Context context) {
  ensureAlive();

  // When "retain instance" is true, the FlutterEngine will survive configuration
  // changes. Therefore, we create a new one only if one does not already exist.
  if (flutterEngine == null) {
    setupFlutterEngine();
  }
  ......
}
//FlutterActivityAndFragmentDelegate
/* package */ void setupFlutterEngine() {
  // First, check if the host wants to use a cached FlutterEngine.
  String cachedEngineId = host.getCachedEngineId();
  if (cachedEngineId != null) {
    flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
    isFlutterEngineFromHost = true;
    if (flutterEngine == null) {
      throw new IllegalStateException(
          "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
              + cachedEngineId
              + "'");
    }
    return;
  }
/**
 * Returns the ID of a statically cached {@link FlutterEngine} to use within this {@code
 * FlutterActivity}, or {@code null} if this {@code FlutterActivity} does not want to use a cached
 * {@link FlutterEngine}.
 */
@Override
@Nullable
public String getCachedEngineId() {
  return getIntent().getStringExtra(EXTRA_CACHED_ENGINE_ID);
}