二.整合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上,不知道明天能找到什麼解決辦法...請大家見諒。