二.集成Flutter
2.通过继承FlutterActivity等组件集成
需要说明的是,我最后在通过route添加不同flutter界面的地方失败了,目前没有找到好的解决办法,如果有人研究过这个,希望可以指出我的错误,帮我解决。
第一篇文章中详细介绍了如何将FlutterView添加到Android原生页面布局中。
(PS:有小伙伴在评论里说,可以设置监听来达到原生控件和FlutterView同时加载的效果,的确是一个可以优化的点,谢谢您的帮助!)
第二种方式是通过继承FlutterActivity、FlutterFragment及FlutterFragmentActivity。
public class FlutterExtendActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
但是目前有个问题没有解决,是这样的:
这样创建的Activity中的Flutter界面是default值,也就是空值返回的界面,但我们不可能永远通过默认的initialRoute来添加FlutterView。
如果在FlutterActivity的onCreate中更改route值呢?
@Override
protected void onCreate(Bundle savedInstanceState) {
FlutterMain.startInitialization(getApplicationContext());
super.onCreate(savedInstanceState);
getFlutterView().setInitialRoute("flutter_activity");
失败了。
getFlutterView().pushRoute("flutter_activity");
也失败了。
--------------------------------------------------------------------
↑这两张图其实是同一张...反正都不成功
主要原因是,super.onCreate之后,FlutterActivity已经创建好了布局,而且我们的这个Activity中又没有setContentView()的实现,设置route的操作不能挪到super.onCreate()前面。
我查看了FlutterActivity的源码,这个问题目前还没有解决,如果各位小伙伴有解决方法希望不吝赐教.
public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
private static final String TAG = "FlutterActivity";
private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
private final FlutterActivityEvents eventDelegate;
private final Provider viewProvider;
private final PluginRegistry pluginRegistry;
public FlutterActivity() {
this.eventDelegate = this.delegate;
this.viewProvider = this.delegate;
this.pluginRegistry = this.delegate;
}
public FlutterView getFlutterView() {
return this.viewProvider.getFlutterView();
}
public FlutterView createFlutterView(Context context) {
return null;
}
public FlutterNativeView createFlutterNativeView() {
return null;
}
public boolean retainFlutterNativeView() {
return false;
}
}
可以看出FlutterActivity实际是继承了Activity,实现了FlutterView.Provider、
PluginRegistry、ViewFactory三个接口。
但是FlutterActivity的三个在实例化时候的变量都指向了一个FlutterActivityDelegate对象,也就是说,它代理了FlutterActivity几乎所有的动作。
三个接口大致内容如下:
(1).FlutterView.Provider
public interface Provider {
FlutterView getFlutterView();
}
FlutterView.Provider是一个接口,提供了getFlutterView()抽象方法
那么FlutterActivity的具体实现呢?
public FlutterView getFlutterView() {
return this.viewProvider.getFlutterView();
}
但是viewProvider又指向了这个FlutterActivityDelegate;
(2).PluginRegistry
public interface PluginRegistry {
PluginRegistry.Registrar registrarFor(String var1);
boolean hasPlugin(String var1);
<T> T valuePublishedByPlugin(String var1);
public interface PluginRegistrantCallback {
void registerWith(PluginRegistry var1);
}
public interface ViewDestroyListener {
boolean onViewDestroy(FlutterNativeView var1);
}
public interface UserLeaveHintListener {
void onUserLeaveHint();
}
public interface NewIntentListener {
boolean onNewIntent(Intent var1);
}
public interface ActivityResultListener {
boolean onActivityResult(int var1, int var2, Intent var3);
}
public interface RequestPermissionsResultListener {
boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3);
}
}
(3).ViewFactory
public interface ViewFactory {
FlutterView createFlutterView(Context var1);
FlutterNativeView createFlutterNativeView();
boolean retainFlutterNativeView();
}
具体实现:
public FlutterView createFlutterView(Context context) {
return null;
}
public FlutterNativeView createFlutterNativeView() {
return null;
}
public boolean retainFlutterNativeView() {
return false;
}
也就是...这个接口的实现基本没有什么意义.
所以我们还是要看FlutterActivityDelegate这个类和它的实例究竟做了什么.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.eventDelegate.onCreate(savedInstanceState);
}
调用了eventDelegate.onCreate(),我们可以顺藤摸瓜看看它的onCreate()
public void onCreate(Bundle savedInstanceState) {
if (VERSION.SDK_INT >= 21) {
Window window = this.activity.getWindow();
window.addFlags(-2147483648);
window.setStatusBarColor(1073741824);
window.getDecorView().setSystemUiVisibility(1280);
}
String[] args = getArgsFromIntent(this.activity.getIntent());
FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
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();
}
}
if (!this.loadIntent(this.activity.getIntent())) {
String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
if (appBundlePath != null) {
this.runBundle(appBundlePath);
}
}
}
FlutterView是由FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) 这个构造方法new出来的。
实际上,
@NonNull
public static FlutterView createView(@NonNull final Activity activity, @NonNull final Lifecycle lifecycle, final String initialRoute) {
FlutterMain.startInitialization(activity.getApplicationContext());
FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null);
final FlutterNativeView nativeView = new FlutterNativeView(activity);
//↓这里还是调用了FlutterView的三个参数构造
final FlutterView flutterView = new FlutterView(activity, null, nativeView) {
private final BasicMessageChannel<String> lifecycleMessages = new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE);
@Override
public void onFirstFrame() {
super.onFirstFrame();
setAlpha(1.0f);
}
}
我们之前使用的Flutter.createView()显然也是调用了这个构造。但是createView()有一个String类型的initialRoute参数,FlutterActivity中调用的构造则没有。我猜想,会不会提供了更改Route的方式呢?
private boolean loadIntent(Intent intent) {
String action = intent.getAction();
if ("android.intent.action.RUN".equals(action)) {
String route = intent.getStringExtra("route");
//获取Intent中传递的route
String appBundlePath = intent.getDataString();
if (appBundlePath == null) {
appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
}
if (route != null) {
this.flutterView.setInitialRoute(route);
}
//如果route值不为空,则将它设置给flutterview
this.runBundle(appBundlePath);
return true;
} else {
return false;
}
}
FlutterActivityDelegate中有这个方法,从这个Activity跳转过来的Intent中可以获取route,key值为"route",如果route不为空的话,就给这个FlutterView设置一个initialRoute。出于这样的思路,我在跳转本Activity的时候,传递一个在Flutter中定义好页面的route值进去怎么样?
做了一下尝试,
findViewById(R.id.btn_flutter_acty).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, FlutterExtendActivity.class).putExtra("route","flutter1"));
}
});
结果是失败了,跳转后页面上出现的FlutterView仍然是传default时返回的页面.
额,由于今天没有什么时间了,所以就写这么多。确实人菜话多,而且今天也没有什么进展(MethodChannel实现通信成功了,不过明天再写吧)今天就卡在了这个FlutterActivity上,不知道明天能找到什么解决办法...请大家见谅。