Flutter Android Embedding V2:Activity/Fragment 生命周期与 Surface 的绑定

Flutter Android Embedding V2:Activity/Fragment 生命周期与 Surface 的绑定

大家好,今天我们深入探讨 Flutter Android Embedding V2 中 Activity/Fragment 生命周期与 Surface 的绑定机制。 理解这一机制对于构建稳定、高效、与原生 Android 平台良好集成的 Flutter 应用至关重要。

一、Flutter Android Embedding V2 的核心概念

在深入生命周期绑定之前,我们先回顾一下 Flutter Android Embedding V2 的几个关键概念:

  • FlutterEngine: Flutter 引擎是 Flutter 运行时的核心,负责 Dart 代码的执行、渲染和平台交互。每个 Flutter 应用至少需要一个 FlutterEngine 实例。

  • FlutterEngineGroup: 允许你共享一个 Flutter 引擎的资源(例如 isolate)在多个 FlutterActivity/FlutterFragment 实例之间。 这对于模块化 Flutter 应用和减少内存占用至关重要。

  • FlutterActivity/FlutterFragment: 这是将 Flutter 嵌入到原生 Android 应用中的主要组件。 FlutterActivity 是一个独立的 Activity,而 FlutterFragment 可以嵌入到现有的 Activity 中。

  • FlutterView: FlutterView 是 Android View 的一个子类,用于显示 Flutter 渲染的内容。 它充当 Flutter 引擎和 Android 视图层之间的桥梁。

  • Platform Channel: Flutter 和原生 Android 代码通过 Platform Channel 进行通信。 允许 Flutter 调用原生代码,反之亦然。

  • Surface: Android Surface 代表一块可以被写入的像素缓冲区。 Flutter 引擎将其渲染结果输出到 Surface,然后 Surface 的内容被显示在屏幕上。

二、Activity/Fragment 生命周期与 FlutterEngine 的关系

FlutterEngine 的生命周期与包含它的 Activity 或 Fragment 的生命周期密切相关。 正确地管理 FlutterEngine 的生命周期对于确保 Flutter 应用的稳定性和资源利用率至关重要。

以下表格总结了 Activity/Fragment 的主要生命周期方法以及它们对 FlutterEngine 的影响:

Activity/Fragment 生命周期方法 FlutterEngine 行为
onCreate() FlutterEngine 通常在这个方法中被初始化和启动(如果尚未启动)。 FlutterEngine 使用 FlutterEngineCache 来避免重复创建,并允许跨 ActivityFragment 共享 FlutterEngineFlutterEngine 的初始化涉及加载 Dart 代码、创建 Dart isolate 以及设置 Platform Channel。
onStart() 此时,Activity/Fragment 变为可见。Flutter 引擎通常不需要在这个阶段执行任何特定的操作。
onResume() Activity/Fragment 处于活动状态,可以与用户交互。 如果 Flutter 引擎暂停,则在此恢复。 FlutterRenderer 尝试重新连接到 Surface,确保 Flutter 内容可以正常渲染。
onPause() Activity/Fragment 即将失去焦点,但仍然可见。 通常在这个阶段暂停 Flutter 引擎。 暂停引擎可以减少 CPU 和 GPU 的使用,从而延长电池寿命。 FlutterRendererSurface 断开连接。
onStop() Activity/Fragment 不再可见。 Flutter 引擎通常不需要在这个阶段执行任何特定的操作。
onDestroy() Activity/Fragment 即将销毁。 非常重要: 必须在这个方法中销毁 FlutterEngine,释放其占用的资源。 如果使用 FlutterEngineGroup,并且 FlutterEngine 将被其他 ActivityFragment 复用,则不应该在此销毁 FlutterEngine。 正确地销毁 FlutterEngine 可以防止内存泄漏和崩溃。
onDetach() Fragment 从 Activity 中分离。 如果 Fragment 持有 FlutterEngine,则需要在此处进行清理工作,类似于 onDestroy()。 但是,具体操作取决于 Fragment 是否是最后一个持有 FlutterEngine 的组件。

代码示例 (FlutterActivity):

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;

public class MyFlutterActivity extends FlutterActivity {

    private FlutterEngine flutterEngine;
    private static final String ENGINE_ID = "my_engine_id";

    @Override
    public void configureFlutterEngine(FlutterEngine flutterEngine) {
        // 可选:配置 Flutter 引擎,例如添加 Platform Channel。
    }

    @Override
    public FlutterEngine provideFlutterEngine(Context context) {
       // 检查 FlutterEngineCache 中是否存在引擎,如果存在则复用。
        flutterEngine = FlutterEngineCache.getInstance().get(ENGINE_ID);

        if (flutterEngine == null) {
            // 如果没有缓存的引擎,则创建一个新的 FlutterEngine。
            flutterEngine = new FlutterEngine(context);

            // 可选:配置引擎初始化参数。
            // 例如设置初始路由:
            // flutterEngine.getNavigationChannel().setInitialRoute("/my_route");

            // 启动 Dart 代码。
            flutterEngine.getDartExecutor().execute(DartExecutor.DartEntrypoint.createDefault());

            // 将引擎添加到缓存中。
            FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);
        }
        return flutterEngine;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 如果确定不需要复用 FlutterEngine,则销毁它。
        // 否则,不要销毁,让 FlutterEngineCache 管理。
        if (isFinishing()) {
            FlutterEngine cachedEngine = FlutterEngineCache.getInstance().get(ENGINE_ID);
             if (cachedEngine != null) {
                 cachedEngine.destroy();
                 FlutterEngineCache.getInstance().remove(ENGINE_ID);
             }
        }
    }
}

代码示例 (FlutterFragment):

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;

public class MyFlutterFragment extends Fragment {

    private FlutterEngine flutterEngine;
    private FlutterView flutterView;
    private static final String ENGINE_ID = "my_engine_id";

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
         // 检查 FlutterEngineCache 中是否存在引擎,如果存在则复用。
        flutterEngine = FlutterEngineCache.getInstance().get(ENGINE_ID);
        if (flutterEngine == null) {
            // 如果没有缓存的引擎,则创建一个新的 FlutterEngine。
            flutterEngine = new FlutterEngine(context);

            // 启动 Dart 代码。
            flutterEngine.getDartExecutor().execute(DartExecutor.DartEntrypoint.createDefault());

            // 将引擎添加到缓存中。
            FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 创建 FlutterView。
        flutterView = new FlutterView(getContext());
        flutterView.attachToFlutterEngine(flutterEngine);
        return flutterView;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        flutterView.detachFromFlutterEngine();
    }

    @Override
    public void onDetach() {
        super.onDetach();
       // 如果确定不需要复用 FlutterEngine,则销毁它。
        // 否则,不要销毁,让 FlutterEngineCache 管理。
        if (getActivity().isFinishing()) { // 检查 Activity 是否正在销毁
            FlutterEngine cachedEngine = FlutterEngineCache.getInstance().get(ENGINE_ID);
            if (cachedEngine != null) {
                cachedEngine.destroy();
                FlutterEngineCache.getInstance().remove(ENGINE_ID);
            }
        } else if (isRemoving()) { // 检查 Fragment 是否正在从 Activity 中移除
            flutterEngine.destroy();
            FlutterEngineCache.getInstance().remove(ENGINE_ID);
        }
    }
}

三、Surface 的创建、连接和销毁

Surface 是 Flutter 渲染的最终目标。 Flutter 引擎将渲染好的像素数据写入 Surface,然后 Android 系统负责将 Surface 的内容显示在屏幕上。

  1. Surface 创建: Surface 的创建通常由 FlutterViewFlutterTextureView 负责。 当 FlutterView 被添加到视图层级中时,它会创建一个 SurfaceHolder,然后 FlutterRenderer 使用该 SurfaceHolder 创建 Surface

  2. Surface 连接: FlutterRenderer 负责将 Flutter 引擎连接到 Surface。 当 Activity/Fragment 恢复时 (onResume()),FlutterRenderer 尝试重新连接到 Surface。 连接过程包括配置 Surface 的属性(例如像素格式和大小)以及通知 Flutter 引擎可以使用 Surface 进行渲染。

  3. Surface 销毁: 当 Activity/Fragment 暂停时 (onPause()),FlutterRenderer 与 Surface 断开连接。 当 Activity/Fragment 销毁时 (onDestroy()),Surface 也会被销毁。 断开连接和销毁 Surface 可以释放资源,防止内存泄漏。

四、处理 Surface 生命周期事件

FlutterRenderer 通过 SurfaceHolder.Callback 接口监听 Surface 的生命周期事件。 SurfaceHolder.Callback 接口定义了三个方法:

  • surfaceCreated(SurfaceHolder holder): 当 Surface 被创建时调用。
  • surfaceChanged(SurfaceHolder holder, int format, int width, int height): 当 Surface 的格式或大小发生变化时调用。
  • surfaceDestroyed(SurfaceHolder holder): 当 Surface 即将被销毁时调用。

FlutterRenderer 使用这些回调方法来同步 Flutter 引擎的渲染状态与 Surface 的状态。 例如,当 surfaceCreated() 被调用时,FlutterRenderer 会通知 Flutter 引擎可以使用 Surface 进行渲染。 当 surfaceDestroyed() 被调用时,FlutterRenderer 会通知 Flutter 引擎停止渲染并将 Surface 从渲染目标中移除。

五、FlutterRenderer 的作用

FlutterRenderer 是 Flutter Android Embedding V2 中一个关键组件,它负责以下任务:

  • 管理 Flutter 引擎的渲染上下文。
  • 创建和管理 Surface。
  • 将 Flutter 引擎连接到 Surface。
  • 监听 Surface 的生命周期事件。
  • 同步 Flutter 引擎的渲染状态与 Surface 的状态。
  • 处理渲染相关的配置更改,例如屏幕旋转和窗口大小调整。

六、解决常见问题

  • 黑屏问题: 黑屏问题通常是由于 Surface 未正确创建、连接或配置引起的。 确保在 Activity/Fragment 的 onResume() 方法中重新连接到 Surface,并在 onPause() 方法中与 Surface 断开连接。 检查 Flutter 引擎是否已正确初始化并启动。 确保 Flutter 代码没有抛出任何异常,这些异常可能会导致渲染失败。

  • 性能问题: 性能问题可能是由于 Flutter 引擎的渲染效率低下或 Surface 的配置不当引起的。 使用 Flutter 的性能分析工具来识别性能瓶颈。 尝试使用不同的 Surface 配置,例如不同的像素格式或缓冲策略。 确保 Flutter 代码没有执行任何耗时的操作,这些操作可能会导致渲染卡顿。

  • 内存泄漏: 内存泄漏通常是由于 Flutter 引擎或 Surface 未正确销毁引起的。 确保在 Activity/Fragment 的 onDestroy() 方法中销毁 FlutterEngine。 确保在 onDetach() 方法中从 FlutterEngine 中移除 FlutterView 或 FlutterTextureView。 检查是否存在对 Flutter 对象的循环引用,这些循环引用可能会阻止垃圾回收。

七、 FlutterEngineGroup 的使用场景

FlutterEngineGroup 允许你共享一个 Flutter 引擎的资源在多个 FlutterActivityFlutterFragment 实例之间。 这在以下场景中特别有用:

  • 模块化 Flutter 应用: 如果你的 Flutter 应用被拆分为多个模块,你可以使用 FlutterEngineGroup 来共享引擎,从而减少内存占用和启动时间。
  • 混合原生-Flutter 应用: 如果你的应用同时包含原生 Android 代码和 Flutter 代码,你可以使用 FlutterEngineGroup 来在原生和 Flutter 之间无缝切换。
  • 多 Flutter 实例应用: 如果你的应用需要在同一时间显示多个 Flutter 界面,可以使用 FlutterEngineGroup 来管理这些界面的引擎。

使用 FlutterEngineGroup 需要注意以下几点:

  • 资源共享: 所有使用同一个 FlutterEngineGroupFlutterActivityFlutterFragment 共享相同的 Dart isolate 和渲染上下文。 这意味着它们可以共享数据和状态。
  • 生命周期管理: FlutterEngineGroup 的生命周期需要谨慎管理。 通常,FlutterEngineGroup 在应用的 Application 类中创建,并在应用退出时销毁。
  • 线程安全: 由于多个 FlutterActivityFlutterFragment 可能同时访问同一个 FlutterEngineGroup,因此需要确保代码是线程安全的。

代码示例 (FlutterEngineGroup):

import android.app.Application;
import io.flutter.embedding.engine.FlutterEngineGroup;

public class MyApplication extends Application {

    private FlutterEngineGroup flutterEngineGroup;

    @Override
    public void onCreate() {
        super.onCreate();
        flutterEngineGroup = new FlutterEngineGroup(this);
    }

    public FlutterEngineGroup getFlutterEngineGroup() {
        return flutterEngineGroup;
    }
}

然后在你的 FlutterActivityFlutterFragment 中,你可以通过以下方式获取 FlutterEngine

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;

public class MyFlutterActivity extends FlutterActivity {

    @Override
    public FlutterEngine provideFlutterEngine(Context context) {
        MyApplication application = (MyApplication) getApplication();
        return application.getFlutterEngineGroup().createAndRunDefault();
    }
}

八、调试技巧

  • 使用 Flutter DevTools: Flutter DevTools 提供了强大的调试功能,包括性能分析、内存分析和日志查看。
  • 使用 Android Studio 的调试器: Android Studio 的调试器可以帮助你逐步执行原生 Android 代码,并检查变量的值。
  • 查看 Logcat 日志: Logcat 日志包含了大量的调试信息,包括 Flutter 引擎的输出、Platform Channel 的消息以及原生 Android 代码的日志。
  • 使用 Flutter 的 debugPrint() 函数: debugPrint() 函数可以将调试信息输出到控制台。

理解生命周期,构建稳定应用

理解 Flutter Android Embedding V2 中 Activity/Fragment 生命周期与 Surface 的绑定机制对于构建稳定、高效、与原生 Android 平台良好集成的 Flutter 应用至关重要。 正确地管理 FlutterEngine 的生命周期,处理 Surface 的生命周期事件,以及使用 FlutterEngineGroup 可以帮助你避免常见的错误,提高应用的性能和稳定性。 通过学习这些知识,可以更好地掌控 Flutter 在 Android 平台上的运行机制。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注