HelloFlutter--FlutterActivity

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WBig_Red/article/details/85049191

自谷歌发布Flutter release版本几天后才开始学习Flutter,实在惭愧。在了解完一些基础知识之后开始尝试将编写的简单Flutter module打包进Android项目中。本文章将尝试过程中遇到的一些问题和笔记记录下来。
本篇文章只是闭门造车的结果,如有任何错误很抱歉!请帮忙指出,多谢了

Android项目依赖Flutter项目

对于已有的Android项目来说,将所有页面都换成flutter页面不太现实,只能从一些简单的页面入手逐个替换。

Flutter项目跟Android工程根文件夹是同级的,它不同于普通的Android module存在于Android工程根目录下。在AndroidStudio中创建Flutter module,也并不会将该项目放到Android项目目录中,而是默认选择Android项目根目录的同级目录下。
在依赖Flutter module的时候,首先需要在项目的setting.gradle加入如下依赖

include ':app'
//加入下面配置
setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        'flutter_module/.android/include_flutter.groovy'
))

以上配置的Flutter module的位置是出于Android根目录同级目录下,如果Flutter module的路径不同需要另外设置File函数的参数。编译项目,会在Android项目下生成名为flutter的module,正常来说该module不需要去修改代码,只需要在app的build.gradle中依赖该fluttermodule即可。

dependencies {
    ...
    // 加入下面配置
    implementation project(':flutter')
}

自此,完成Android项目对Flutter项目的依赖

FlutterActivity

在创建的Flutter项目的.andorid module中,只有一个类,那就是MainActivity类。
其继承自FlutterActivity,运行该Flutter工程时,Android项目的入口就是该MainActivity类。
MainActivity
该FlutterActivity类是Flutter项目的页面入口,Flutter为Android项目提供了FlutterView和FlutterFragment作为展示页面,附着在Activity上面。而FlutterActivity使用的便是FlutterView。
那么,从开发的角度,接下来引出几个问题?

  1. 继承FlutterActivity只能默认进入Flutter设定的首页?
  2. Flutter页面的生命周期如何管理?
  3. Flutter页面与Android原生页面之间如何通讯?
  4. Flutter页面是如何绘制的?

查看源码

查看FlutterActivity的类声明,该类实现了三个接口

public class FlutterActivity extends Activity implements 
Provider, PluginRegistry, ViewFactory {
  ...
}

这三个接口作用如下

  • Provider:只有一个简单的方法,那就是getFlutterView()返回当前Activity中的Flutter页面
  • PluginRegistry:插件注册相关的类,以后的文章再详细讲述
  • ViewFactory:该接口有三个方法,分别是
    public interface ViewFactory {
          FlutterView createFlutterView(Context var1);
    
          FlutterNativeView createFlutterNativeView();
    
          boolean retainFlutterNativeView();
      }   
    
    1. FlutterView createFlutterView(Context context):该方法比较直观,就是生成一个Flutter的页面,供Activity展示。但是并没有在源码中找到引用它的地方。FlutterActivity的实现返回值是null。
    2. FlutterNativeView createFlutterNativeView():从字面意思是生成一个Flutter的原生View,但是并没有在源码中找到引用它的地方。FlutterActivity的实现返回值也是null。
    3. boolean retainFlutterNativeView():字面意思,保留Flutter原生页面。是一个boolean类型的值,但是并没有在源码中找到引用它的地方。FlutterActivity的实现返回值是false。
      通过查看FlutterActivity所继承的三个接口,我们并没有找到FlutterActivity中直接生成FlutterView的线索,只能从实例变量中查找。

FlutterActivityDelegate

在进行一番阅读之后,发现该委派类。在Android源码中有很多使用委派模式的地方,该处也算是一个。并且,在FlutterActivity中,FlutterActivityDelegate对象会跟随Activity的生命周期方法被调用同名方法。查看FlutterActivityDelegate的源码

  1. 构造方法
    public FlutterActivityDelegate(Activity activity, FlutterActivityDelegate.ViewFactory viewFactory) {
        this.activity = (Activity)Preconditions.checkNotNull(activity);
        this.viewFactory = (FlutterActivityDelegate.ViewFactory)Preconditions.checkNotNull(viewFactory);
    }
    
    其构造方法需要传入一个Activity对象,还有FlutterActivityDelegate.ViewFactory对象。但在上文已经发现FlutterActivityDelegate.ViewFactory的方法并无引用的地方,这里只需要着重关注Activity对象就好了。
  2. 同名生命周期方法:查看FlutterActivityDelegate类源码,该类定义了一些列对象Activity生命周期函数的同名函数。并分别运行在FlutterActivity类的对应生命周期中,由此可见Flutter页面的生命周期是由该委托类处理的。接下来逐个分析生命周期函数
    • onCreate:该方法中实现了flutterView的生成。查看代码,由于代码量大,这里只显示关键代码
        public void onCreate(Bundle savedInstanceState) {
            ...
            this.flutterView = this.viewFactory.createFlutterView(this.activity);
            if (this.flutterView == null) {
                FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
                this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
                this.flutterView.setLayoutParams(matchParent);
                this.activity.setContentView(this.flutterView);
                this.launchView = this.createLaunchView();
                if (this.launchView != null) {
                    this.addLaunchView();
                }
            }
            ...
        }
        
    
    从FlutterActivity实现的ViewFactory方法我们已经得知,传递给委托类FlutterActivityDelegate实例的ViewFactory并没有生成FlutterView可供FlutterActivityDelegate使用。所以只能继续查看this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView)之后的代码。
    public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry, AccessibilityStateChangeListener {
        public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
            super(context, attrs);
            ...
            Activity activity = (Activity)this.getContext();
            if (nativeView == null) {
                this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
            } else {
                this.mNativeView = nativeView;
            }
    
            this.mNativeView.attachViewAndActivity(this, activity);
            ...
        }
    }
    
    我们可以看到FlutterView继承自SurfaceView,在其构造方法中。如果传递的FlutterNativeView如果为空,那将会重新创建一个默认的FlutterNativeView。接着看
    public class FlutterNativeView implements BinaryMessenger {
        public FlutterNativeView(Context context) {
            this(context, false);
        }
    
        public FlutterNativeView(Context context, boolean isBackgroundView) {
            this.mNextReplyId = 1;
            this.mPendingReplies = new HashMap();
            this.mContext = context;
            this.mPluginRegistry = new FlutterPluginRegistry(this, context);
            this.attach(this, isBackgroundView);
            this.assertAttached();
            this.mMessageHandlers = new HashMap();
        }
    }
    
    在这里我们可以看到FlutterNativeView实现了BinaryMessenger接口,而BinaryMessenger是一个数据信息交流对象,其接口声明如下
    public interface BinaryMessenger {
        /**
        *Sends a binary message to the Flutter application.
        *Parameters:
        *channel - the name String of the logical channel used for the message.
        *message - the message payload, a direct-allocated ByteBuffer with the message bytes between position zero and current position, or null.
        */
        void send(String var1, ByteBuffer var2);
        
         /**
         * Sends a binary message to the Flutter application, optionally expecting a reply.
         * Any uncaught exception thrown by the reply callback will be caught and logged.
         * <p>
         * Parameters:
         * channel - the name String of the logical channel used for the message.
         * message - the message payload, a direct-allocated ByteBuffer with the message bytes between position zero and current position, or null.
         * callback - a BinaryMessenger.BinaryReply callback invoked when the Flutter application responds to the message, possibly null.
         */
        void send(String var1, ByteBuffer var2, BinaryMessenger.BinaryReply var3);
    
        /**
         * Registers a handler to be invoked when the Flutter application sends a message to its host platform.
         * Registration overwrites any previous registration for the same channel name. Use a null handler to deregister.
         * <p>
         * If no handler has been registered for a particular channel, any incoming message on that channel will be handled silently by sending a null reply.
         * <p>
         * Parameters:
         * channel - the name String of the channel.
         * handler - a BinaryMessenger.BinaryMessageHandler to be invoked on incoming messages, or null.
         */
        void setMessageHandler(String var1, BinaryMessenger.BinaryMessageHandler var2);
    
        /**
         * Binary message reply callback. Used to submit a reply to an incoming message from Flutter. 
         * Also used in the dual capacity to handle a reply received from Flutter after sending a message.
         */
        public interface BinaryReply {
            /**
             * Handles the specified reply.
             * Parameters:
             * reply - the reply payload, a direct-allocated ByteBuffer or null. 
             * Senders of outgoing replies must place the reply bytes between position zero and current position. 
             * Reply receivers can read from the buffer directly.
             */
            void reply(ByteBuffer var1);
        }
        
        /**
         * Handler for incoming binary messages from Flutter.
         */
        public interface BinaryMessageHandler {
            /**
             * Handles the specified message.
             * Handler implementations must reply to all incoming messages, 
             * by submitting a single reply message to the given BinaryMessenger.BinaryReply. 
             * Failure to do so will result in lingering Flutter reply handlers. The reply may be submitted asynchronously.
             * <p>
             * Any uncaught exception thrown by this method will be caught by the messenger implementation and logged, 
             * and a null reply message will be sent back to Flutter.
             * <p>
             * Parameters:
             * message - the message ByteBuffer payload, possibly null.
             * reply - A BinaryMessenger.BinaryReply used for submitting a reply back to Flutter.
             */
            void onMessage(ByteBuffer var1, BinaryMessenger.BinaryReply var2);
        }
    }
    
    要命的是Flutter框架在Android中还没有注释可以看,只能从官网查看文档
    这是一个用于在Flutter和Native之间交换数据的接口类,已知FlutterView已经实现了SurfaceView,flutterNativeView负责FlutterView和Flutter之间的通讯,再使用Skia绘制页面。

总结

在阅读完FlutterActivity的部分源码以后,得出了以上几个问题的答案。

  1. 继承FlutterActivity之后,重写ViewFactory中的方法可以进入不同的FlutterView页面。
  2. 在FlutterActivityDelegate委托类里,实现了对FlutterActivity和Flutter页面生命周期的管理
  3. HelloFlutter——MethodChannel(Native&Flutter数据交互)
  4. FlutterView继承了SurfaceView,使用FlutterNativeView在Android和Flutter之间作为通讯的桥梁,之后调用Skia框架绘制页面。这也是其与RN和其他依赖于WebView的混合开发的框架不同的根源。
    本篇文章只是闭门造车的结果,如有任何错误很抱歉!请帮忙指出,多谢了

猜你喜欢

转载自blog.csdn.net/WBig_Red/article/details/85049191