Flutter学习系列(6)— FlutterView初始化

前面一篇介绍了承载Flutter的Activity的初始化过程,通过分析FlutterActivityDelegate我们知道了FlutterView是真正运行Flutter App的地方,所以这一篇文章主要来看一看FlutterView的功能。

 

 

一 FlutterView 类结构

 

先看一下FlutterView的UML图。

  • 继承SurfaceView,它的内部有两个线程即主线程和渲染线程,使用渲染线程中向屏幕上绘图可以避免主线程阻塞,从而提高了程序的反应速度。使用了双缓冲机制。
  • 实现BinaryMesaenger接口, 这个接口定义了Android代码和Flutter代码直接通信的方式,此接口还有2个内部接口。 FlutterView实现了这个接口,拥有了和flutter通信的的能力
  • 实现TextureRegistry接口,这个接口主要是创建一个SurfaceTexture对象,使用SurfaceTextureEntry包装起来,拥有唯一的ID。
  • 实现AccessibilityStateChangeListener接口,主要用来监听系统accessibility 状态变化的。

成员变量

   private final DartExecutor dartExecutor;
    private final NavigationChannel navigationChannel;
    private final KeyEventChannel keyEventChannel;
    private final LifecycleChannel lifecycleChannel;
    private final SettingsChannel settingsChannel;
    private final SystemChannel systemChannel;
    private final InputMethodManager mImm;
    private final TextInputPlugin mTextInputPlugin;
    private final AndroidKeyProcessor androidKeyProcessor;
    private final SurfaceHolder.Callback mSurfaceCallback;
    private final ViewportMetrics mMetrics;
    private final AccessibilityManager mAccessibilityManager;
    private final MethodChannel mFlutterLocalizationChannel;
    private final List<ActivityLifecycleListener> mActivityLifecycleListeners;
    private final List<FirstFrameListener> mFirstFrameListeners;
    private final AtomicLong nextTextureId = new AtomicLong(0L);
    private FlutterNativeView mNativeView;
    private final AnimationScaleObserver mAnimationScaleObserver;
    private boolean mIsSoftwareRenderingEnabled = false; // using the software renderer or not
    private InputConnection mLastInputConnection;

上面列举出了FlutterView中的成员变量,大致分类:

  • Channel: 有一系列了的Channel,在Flutter中,Channel是用Android和Flutter进行通信的管道,他们都是基于BinaryMesaenger进行通信。后面会单独介绍Channel通信,这里只需要知道FlutterView中有一系列Channel可以让Android和Flutter进行交互。
  • 系统相关:InputMethodManager、AndroidKeyProcessor、SurfaceHolder.Callback、AccessibilityManager、AnimationScaleObserver、InputConnection 这些成员变量都是和系统相关,通知Flutter处理输入、按键等操作以及一些系统状态。
  • FlutterNativeView: 这个是我们在Activity初始化见过,后面单独分析。

 

简单的从类的结构来看Flutter主要提供了和Flutter交互的的能力,以及为Flutter提供了Android系统的一些信息。

 

 

 

二 FlutterView创建

 

  flutterView = viewFactory.createFlutterView(activity);
        if (flutterView == null) {
            FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
            flutterView = new FlutterView(activity, null, nativeView);
            flutterView.setLayoutParams(matchParent);
            activity.setContentView(flutterView);
            launchView = createLaunchView();
            if (launchView != null) {
                addLaunchView();
            }
        }

在FlutterActivity初始化的时候,会通过FlutterActivityDelegate来初始化Flutter Engine,然后就会创建FlutterView。主要看看FlutterView的构造函数

public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) 

这个构造函数内容比较多,我们分段来看:

 

 

1. 创建FlutterNativeView

 

如果外部没有传入FlutterNativeView,内部会自动创建一个。看似只有一行带代码,其实里面做了很多事情。

Activity activity = (Activity) getContext();
if (nativeView == null) {
    mNativeView = new FlutterNativeView(activity.getApplicationContext());
} else {
    mNativeView = nativeView;
}

 

FlutterView实现了BinaryMeeenger接口, 先看一下创建的过程:

public FlutterNativeView(Context context, boolean isBackgroundView) {
    mContext = context;
    mPluginRegistry = new FlutterPluginRegistry(this, context);
    mFlutterJNI = new FlutterJNI();
    mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
    mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
    mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
    attach(this, isBackgroundView);
    assertAttached();
    mMessageHandlers = new HashMap<>();
}

主要创建了FlutterPluginRegistry和FlutterJNI 对象,这是FlutterNativeView最重要的两个成员变量:

  • FlutterPluginRegistry: 这个类实现了PluginRegistry的全部接口,是真正实现Plugin注册功能的类。 在FlutterActivity和FlutterActivityDelegate都实现了这个接口,但最终都是调用到了这里。
  • FlutterJNI: 这个类是调用Engine层c++方法的一个封装类。所有Flutter JNI的调用都集合在这个类中。 一个FlutterJNI对象是和一个Platform View相关联,所以包含一个nativePlatformViewId来标识

创建完这2个对象之后,调用了FlutterJNI下面的个方法,这3个方法创建了3个内部类实例,设置给了FlutterJNI的成员变量。 使用这3个成员变量的方法并没有被java代码调用,注释上写被native调用,应该是在C++层的Engine被调用。主要是一些Flutter Engine通知Android 程序一些事件,比如渲染第一帧、Flutter发送过来的消息、Engine的生命周期。

  public void setRenderSurface(@Nullable FlutterRenderer.RenderSurface renderSurface) {
    this.renderSurface = renderSurface;
  }

 public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
    this.platformMessageHandler = platformMessageHandler;
  }

 public void addEngineLifecycleListener(@NonNull EngineLifecycleListener engineLifecycleListener) {
    engineLifecycleListeners.add(engineLifecycleListener);
  }

然后调用了attach方法

private void attach(FlutterNativeView view, boolean isBackgroundView) {
    mFlutterJNI.attachToNative(isBackgroundView);
}

内部还是调用FlutterJNI的方法,最终调用了native的方法获得了一个nativePlatformViewId

@UiThread
public void attachToNative(boolean isBackgroundView) {
  ensureNotAttachedToNative();
  nativePlatformViewId = nativeAttach(this, isBackgroundView);
}

private native long nativeAttach(FlutterJNI flutterJNI, boolean isBackgroundView);

 

 

2. 创建成员变量

 

mIsSoftwareRenderingEnabled = mNativeView.getFlutterJNI().nativeGetIsSoftwareRenderingEnabled();
mAnimationScaleObserver = new AnimationScaleObserver(new Handler());
mMetrics = new ViewportMetrics();
mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
setFocusable(true);
setFocusableInTouchMode(true);

mNativeView.attachViewAndActivity(this, activity);

mSurfaceCallback = new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        assertAttached();
        mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        assertAttached();
        mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        assertAttached();
        mNativeView.getFlutterJNI().onSurfaceDestroyed();
    }
};
getHolder().addCallback(mSurfaceCallback);

mAccessibilityManager = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);

mActivityLifecycleListeners = new ArrayList<>();
mFirstFrameListeners = new ArrayList<>();

这里比较杂,主要做了几件事:

  1. 获取Flutter是否启用软件渲染
  2. 创建AnimationScaleObserver用于监听手机时候开启了动画
  3. 创建ViewportMetrics,主要用来保存一下显示相关的信息,比如屏幕高宽、像素密度等
  4. 关联FlutterNativeView和activity (里面具体步骤省略)
  5. 监听SurfaceView的回调,并且通过FlutterNativeView通知给Engine

 

 

3. 配置平台Plugin和Channel

 

dartExecutor = new DartExecutor(mNativeView.getFlutterJNI());

// Configure the platform plugins and flutter channels.
navigationChannel = new NavigationChannel(dartExecutor);
keyEventChannel = new KeyEventChannel(dartExecutor);
lifecycleChannel = new LifecycleChannel(dartExecutor);
systemChannel = new SystemChannel(dartExecutor);
settingsChannel = new SettingsChannel(dartExecutor);
mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE);

PlatformPlugin platformPlugin = new PlatformPlugin(activity);
MethodChannel flutterPlatformChannel = new MethodChannel(this, "flutter/platform", JSONMethodCodec.INSTANCE);
flutterPlatformChannel.setMethodCallHandler(platformPlugin);
addActivityLifecycleListener(platformPlugin);
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
mTextInputPlugin = new TextInputPlugin(this);
androidKeyProcessor = new AndroidKeyProcessor(keyEventChannel);

这一部分创建了很多平台使用的channel,用于和Flutter之间通信,而且大多数的channel都传入了一个DartExecutor对象,它实现了BinaryMessenger接口,具有和Flutter通信的能力,所以这些Platform相关的Channel并没有使用FlutterNativeView 作为Messenger, 而是使用了DartExecutor, 他提供了执行指定Dart代码的能力(通过DartEntrypoint指定要执行的方法和代码的位置)。

public class DartExecutor implements BinaryMessenger

最后使用上面的channel把相关的一些信息传递给了Flutter(Dart)

setLocales(getResources().getConfiguration());
sendUserPlatformSettingsToDart();

 

 

 

三 执行Flutter程序

 

创建了FlutterView,通过FlutterViewNative、FlutterJNI 、Flutter Channel, 当前的FlutterView或者说当前的Activity已经具有了和Flutter Engine交互的能力。接下来就是运行Flutter程序。

args.bundlePaths = bundlePaths.toArray(new String[0]);
args.entrypoint = "main";
flutterView.runFromBundle(args);

FlutterActivityDelegate中通过调用FlutterView的runFromBundle方法来执行。

private void preRun() {
    resetAccessibilityTree();
}

private void postRun() {
}

public void runFromBundle(FlutterRunArguments args) {
  assertAttached();
  preRun();
  mNativeView.runFromBundle(args);
  postRun();
}

FlutterView里调用的是FlutterNativeView的方法

public void runFromBundle(FlutterRunArguments args) {
    boolean hasBundlePaths = args.bundlePaths != null && args.bundlePaths.length != 0;
    if (args.bundlePath == null && !hasBundlePaths) {
        throw new AssertionError("Either bundlePath or bundlePaths must be specified");
    } else if ((args.bundlePath != null || args.defaultPath != null) &&
            hasBundlePaths) {
        throw new AssertionError("Can't specify both bundlePath and bundlePaths");
    } else if (args.entrypoint == null) {
        throw new AssertionError("An entrypoint must be specified");
    }
    if (hasBundlePaths) {
        runFromBundleInternal(args.bundlePaths, args.entrypoint, args.libraryPath);
    } else {
        runFromBundleInternal(new String[] {args.bundlePath, args.defaultPath},
                args.entrypoint, args.libraryPath);
    }
}

这里主要检查了一下传入的参数,必须传递bundle文件路径和entrypoint 。使用runFromBundleInternal来处理

private void runFromBundleInternal(String[] bundlePaths, String entrypoint,
    String libraryPath) {
    assertAttached();
    if (applicationIsRunning)
        throw new AssertionError(
                "This Flutter engine instance is already running an application");
    mFlutterJNI.runBundleAndSnapshotFromLibrary(
        bundlePaths,
        entrypoint,
        libraryPath,
        mContext.getResources().getAssets()
    );

    applicationIsRunning = true;
}

最终调用FlutterJNI让Engine来运行Flutter bundle。Flutter就会开始执行Dart程序,在FlutterView的SurfaceView绘制UI。

 

 

 

四 其他功能

 

FlutterView作为运行Flutter程序的容器,还有许多重要的功能,下面只简单的列举,因为每一个部都是可以单独去研究的。

 

 

生命周期

FlutterActivityDelegate会把Activity的声明周期都通知给FlutterView,所以FlutterView也有类似的声明周期的回调方法。在回调方法中FlutterView通过LifecycleChannel把声明周期的信息同步给了Flutter。

   public void onPause() {
        lifecycleChannel.appIsInactive();
    }

    public void onPostResume() {
        updateAccessibilityFeatures();
        for (ActivityLifecycleListener listener : mActivityLifecycleListeners) {
            listener.onPostResume();
        }
        lifecycleChannel.appIsResumed();
    }

    public void onStop() {
        lifecycleChannel.appIsPaused();
    }

 

 

触屏事件处理

FlutterView重写了触屏相关的事件,中间手机了一些点击信息,最后都通过FlutterJNI().dispatchPointerDataPacket 发送给了Flutter, 这些后续研究触屏事件是在具体研究。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isAttached()) {
            return false;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            requestUnbufferedDispatch(event);
        }

        final int kPointerDataFlagBatched = 1;

        int pointerCount = event.getPointerCount();

        ByteBuffer packet = ByteBuffer.allocateDirect(pointerCount * kPointerDataFieldCount * kPointerBytesPerField);
        packet.order(ByteOrder.LITTLE_ENDIAN);

        int maskedAction = event.getActionMasked();
        int pointerChange = getPointerChangeForAction(event.getActionMasked());
        if (maskedAction == MotionEvent.ACTION_DOWN || maskedAction == MotionEvent.ACTION_POINTER_DOWN) {
            addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet);
        } else if (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP) {
            for (int p = 0; p < pointerCount; p++) {
                if (p != event.getActionIndex()) {
                    if (event.getToolType(p) == MotionEvent.TOOL_TYPE_FINGER) {
                        addPointerForIndex(event, p, kPointerChangeMove, kPointerDataFlagBatched, packet);
                    }
                }
            }
            addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet);
        } else {
            for (int p = 0; p < pointerCount; p++) {
                addPointerForIndex(event, p, pointerChange, 0, packet);
            }
        }

        if (packet.position() % (kPointerDataFieldCount * kPointerBytesPerField) != 0) {
          throw new AssertionError("Packet position is not on field boundary");
        }
        mNativeView.getFlutterJNI().dispatchPointerDataPacket(packet, packet.position());
        return true;
    }

    @Override
    public boolean onHoverEvent(MotionEvent event) {
        if (!isAttached()) {
            return false;
        }

        boolean handled = handleAccessibilityHoverEvent(event);
        if (!handled) {
            // TODO(ianh): Expose hover events to the platform,
            // implementing ADD, REMOVE, etc.
        }
        return handled;
    }

    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        if (!event.isFromSource(InputDevice.SOURCE_CLASS_POINTER) ||
            event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE ||
            !isAttached()) {
            return super.onGenericMotionEvent(event);
        }

        int pointerChange = getPointerChangeForAction(event.getActionMasked());
        ByteBuffer packet = ByteBuffer.allocateDirect(
            event.getPointerCount() * kPointerDataFieldCount * kPointerBytesPerField);
        packet.order(ByteOrder.LITTLE_ENDIAN);

        // ACTION_HOVER_MOVE always applies to a single pointer only.
        addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet);
        if (packet.position() % (kPointerDataFieldCount * kPointerBytesPerField) != 0) {
          throw new AssertionError("Packet position is not on field boundary");
        }
        mNativeView.getFlutterJNI().dispatchPointerDataPacket(packet, packet.position());
        return true;
    }

 

 

和Flutter通信

FlutterView实现了BinaryMessenger接口,但是内部实际是调用FlutterNativeView的方法。关于和Flutter通信,后面也会单独研究。

    @Override
    public void send(String channel, ByteBuffer message) {
        send(channel, message, null);
    }

    @Override
    public void send(String channel, ByteBuffer message, BinaryReply callback) {
        if (!isAttached()) {
            Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
            return;
        }
        mNativeView.send(channel, message, callback);
    }

    @Override
    public void setMessageHandler(String channel, BinaryMessageHandler handler) {
        mNativeView.setMessageHandler(channel, handler);
    }

对于FlutterNativeView来说,它是调用了FlutterJNI.dispatchPlatformMessage来发送消息

   public void send(String channel, ByteBuffer message, BinaryReply callback) {
        if (!isAttached()) {
            Log.d(TAG, "FlutterView.send called on a detached view, channel=" + channel);
            return;
        }

        int replyId = 0;
        if (callback != null) {
            replyId = mNextReplyId++;
            mPendingReplies.put(replyId, callback);
        }
        if (message == null) {
            mFlutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
        } else {
            mFlutterJNI.dispatchPlatformMessage(
                channel,
                message,
                message.position(),
                replyId
            );
        }
    }

 

 

 

五 总结

 

这一篇主要介绍了FlutterView初始化的流程和其他一些功能。FlutterView是比较重要的一个类:

  1. FlutterView提供了SurfaceView来绘制Flutter的UI
  2. 同时把Android的生命周期、点击事件等信息发送给Flutter。
  3. FlutterView并不负责直接和Flutter Engine通信,具体的通信功能在FlutterNativeView
  4. FlutterNativeView内部有一个FlutterJNI,它负责调用Flutter Engine的C++代码。
0

如果本文对您有帮助,可以扫描下方二维码打赏!您的支持是我的动力!
微信打赏 支付宝打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注