io.flutter.embedding.android.FlutterActivity(如无特殊说明,下文中的FlutterActivity单指此包下的类。)重写了android.app.Activity中的onCreate方法:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//...
setContentView(createFlutterView());
//...
}
再来看一下方法createFlutterView()的源码:
@NonNull
private View createFlutterView() {
return delegate.onCreateView(null,null,null,FLUTTER_VIEW_ID,getRenderMode() == RenderMode.surface);
}
可以看到,这里调用了一个delegate的onCreateView(…)方法。这个变量delegate是什么东西?在哪里被设值了?可以变更吗?它是FlutterActivity中的一个变量:
protected FlutterActivityAndFragmentDelegate delegate;
它在onCreate方法中被初始化了:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//...
delegate = new FlutterActivityAndFragmentDelegate(this);
//...
setContentView(createFlutterView());
//...
}
接着看一下这个delegate的onCreateView(…)方法的源码:
@NonNull
View onCreateView(
LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState,
int flutterViewId,
boolean shouldDelayFirstAndroidViewDraw) {
//...
flutterView.attachToFlutterEngine(flutterEngine);
//...
}
大致意思就是把flutterView attach到FlutterEngine(Flutter引擎)上去,并且提供了一个引擎对象flutterEngine。FlutterEngine是什么?简单地说,它使得在Android Application中执行Dart成为可能。再简单点说,它就是一个黑盒子,里面在执行Dart代码。至于它到底还干了什么别的,具体怎么干的?我也不知道。
接下来找找看这个引擎对象是如何被初始化的。
class FlutterActivityAndFragmentDelegate implements ... {
@Nullable private FlutterEngine flutterEngine;
void setupFlutterEngine() {
//...
// First, check if the host wants to use a cached FlutterEngine.
//...
// Second, defer to subclasses for a custom FlutterEngine.
//...
// Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
// FlutterView.
//...
}
}
源码注释的大致意思应该是:第一步,缓存的引擎用不用?用就返回。第二步,子类有没有提供自己的引擎?有就返回。第三步,创建一个,并返回。这里暂且不管它的引擎缓存机制是如何实现的,也不管它的子类提供引擎的机制是什么,先看一下它是如何被创建出来的。
void setupFlutterEngine() {
//...
flutterEngine = new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
false,
host.shouldRestoreAndSaveState());
//...
}
只是调了一个构造而已嘛!没什么大不了的。当我们仔细地观察会发现,所有构造器最后都指向同一个构造器,即
public FlutterEngine(
@NonNull Context context,
@Nullable FlutterLoader flutterLoader,
@NonNull FlutterJNI flutterJNI,
@NonNull PlatformViewsController platformViewsController,
@Nullable String[] dartVmArgs,
boolean automaticallyRegisterPlugins,
boolean waitForRestorationData)
此处,我们暂且不关注该构造器的具体实现,只看该方法的最后几行代码,如下所示:
//...
if (automaticallyRegisterPlugins && flutterLoader.automaticallyRegisterPlugins()) {
GeneratedPluginRegister.registerGeneratedPlugins(this);
}
public static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine) {
try {
Class<?> generatedPluginRegistrant =
Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method registrationMethod =
generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, flutterEngine);
} catch (Exception e) {
Log.e(
TAG,
"Tried to automatically register plugins with FlutterEngine ("
+ flutterEngine
+ ") but could not find or invoke the GeneratedPluginRegistrant.");
Log.e(TAG, "Received exception while registering", e);
}
}
这是一段极为普通的反射代码,它执行了类io.flutter.plugins.GeneratedPluginRegistrant
的方法registerWith
,是不是非常眼熟了?在我们的Flutter APP中android文件夹下就有一个自动生成的类与之同名,即
public final class GeneratedPluginRegistrant {
private static final String TAG = "GeneratedPluginRegistrant";
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
//...
}
}
现在我们知道了,当引擎被构造时,就会去注册插件。那么除了这一时机之外,还会有其它时机注册插件吗?
FlutterActivity类有代码如下所示:
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
//...
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//...
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
//...
setContentView(createFlutterView());
//...
}
FlutterFragmentActivity类有代码如下所示:
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
//...
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
}
FlutterActivityAndFragmentDelegate类有代码如下所示:
void onAttach(@NonNull Context context) {
//...
if (flutterEngine == null) {
setupFlutterEngine();
}
//...
host.configureFlutterEngine(flutterEngine);
isAttached = true;
}
FlutterFragment类有代码如下所示:
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
FragmentActivity attachedActivity = getActivity();
if (attachedActivity instanceof FlutterEngineConfigurator) {
((FlutterEngineConfigurator) attachedActivity).configureFlutterEngine(flutterEngine);
}
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(context);
//...
}
综上,上面的问题也就迎刃而解了。
接下来先看一下引擎这个类的大致格局:
public class FlutterEngine {
//...
@NonNull private final FlutterJNI flutterJNI;
@NonNull private final FlutterRenderer renderer;
@NonNull private final DartExecutor dartExecutor;
@NonNull private final FlutterEngineConnectionRegistry pluginRegistry;
@NonNull private final LocalizationPlugin localizationPlugin;
// System channels.
@NonNull private final AccessibilityChannel accessibilityChannel;
@NonNull private final DeferredComponentChannel deferredComponentChannel;
@NonNull private final KeyEventChannel keyEventChannel;
@NonNull private final LifecycleChannel lifecycleChannel;
@NonNull private final LocalizationChannel localizationChannel;
@NonNull private final MouseCursorChannel mouseCursorChannel;
@NonNull private final NavigationChannel navigationChannel;
@NonNull private final RestorationChannel restorationChannel;
@NonNull private final PlatformChannel platformChannel;
@NonNull private final SettingsChannel settingsChannel;
@NonNull private final SystemChannel systemChannel;
@NonNull private final TextInputChannel textInputChannel;
// Platform Views.
@NonNull private final PlatformViewsController platformViewsController;
// Engine Lifecycle.
@NonNull private final Set<EngineLifecycleListener> engineLifecycleListeners = new HashSet<>();
@NonNull
private final EngineLifecycleListener engineLifecycleListener =...;
//...
}
所有域都是非空final的,这给源码阅读带来好处,因为设值的地方肯定只有一处。此类除了这些域之外,还有各种构造、各种通道、插件注册和引擎生命周期相关的方法。
先看引擎生命周期。
public void addEngineLifecycleListener(@NonNull EngineLifecycleListener listener){//...}
public void removeEngineLifecycleListener(@NonNull EngineLifecycleListener listener){//...}
public interface EngineLifecycleListener {
void onPreEngineRestart();
void onEngineWillDestroy();
}
可以看到引擎提供了一个引擎生命周期监听器接口、两个方法,分别是添加、删除引擎生命周期监听器。源码看到此处,免不得要实践一下,试试这个接口中的两个方法是否会回调。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FlutterEngine fe = getFlutterEngine();
if (fe != null) {
fe.addEngineLifecycleListener(new FlutterEngine.EngineLifecycleListener() {
@Override
public void onPreEngineRestart() {
Log.d("Harry", "onPreEngineRestart");
}
@Override
public void onEngineWillDestroy() {
Log.d("Harry", "onEngineWillDestroy");
}
});
}
}
在FlutterActivity的子类MainActivity中重写onCreate方法,然后添加一个监听器即可。然后在命令行中使用flutter run
启动Flutter应用程序,待应用程序启动完毕后,在终端输入大写的R
,即Hot restart
,然后按返回键退出应用程序,在日志中便可以看到日志如下所示:
2022-04-23 18:35:12.578 ... D/Harry: onPreEngineRestart
2022-04-23 18:45:10.733 ... D/Harry: onEngineWillDestroy
在FlutterEngine类中,第一个非空final域就是变量flutterJNI
,那么就进去走马观花一下。进去一看,才发现这个类1000多行代码,这得看到猴年马月去!算了,不看了,不看了。
既来之,则安之。随便看看何妨?又不是进来寻找武林至尊秘籍的,看着不爽咱就撤。
闲言少叙,开始走马观花。
public void loadLibrary() {
//...
System.loadLibrary("flutter");
//...
}
这段代码应该很熟悉哦?就是加载libflutter.so
库。
private static native void nativeInit(
@NonNull Context context,
@NonNull String[] args,
@Nullable String bundlePath,
@NonNull String appStoragePath,
@NonNull String engineCachesPath,
long initTimeMillis);
public void init(
@NonNull Context context,
@NonNull String[] args,
@Nullable String bundlePath,
@NonNull String appStoragePath,
@NonNull String engineCachesPath,
long initTimeMillis) {
//...
FlutterJNI.nativeInit(context, args, bundlePath, appStoragePath, engineCachesPath, initTimeMillis);
//...
}
看样子,这里就是初始化FlutterJNI的地方了,只是它调用了一个native方法,换言之,真正初始化的代码在底层,是用C/C++完成的。咦!这好像一个小黑洞,洞外山丘高耸、丛林密布,站在洞外往里看,深不可测,甚是神秘。它太吸引人了,咱不妨动动手指往里探探?你能忍住不这么做?
在shell/platform/android
目录下,有个flutter_main.h
头文件。
//...
class FlutterMain {
public:
//...
private:
//...
static void Init(JNIEnv* env,
jclass clazz,
jobject context,
jobjectArray jargs,
jstring kernelPath,
jstring appStoragePath,
jstring engineCachesPath,
jlong initTimeMillis);
//..
};
看来是用C++写的。此处的static void Init(...)
函数和前面提到的private static native void nativeInit(...)
方法的参数是不是甚为相似?在Init(...)
函数形参中,前两个参数env
和clazz
分别代表jni执行环境(参看Java与C/C++交互相关内容)和FlutterJNI类对象(因为nativeInit(...)
方法是用static
修饰的)。这里是头文件,只是声明了该函数的签名,该函数的具体实现还得看源文件,接下来打开flutter_main.cc
源文件,这个文件篇幅还可以,200多行代码。
咱先找找看,是什么把上面提到的一个函数和一个方法进行关联起来的。
bool FlutterMain::Register(JNIEnv* env) {
static const JNINativeMethod methods[] = {
{
.name = "nativeInit",
.signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;J)V",
.fnPtr = reinterpret_cast<void*>(&Init),
},
//...
};
jclass clazz = env->FindClass("io/flutter/embedding/engine/FlutterJNI");
//...
}
这段代码可以证明上面所说的是正确的。况且这段代码不难理解:方法有名字、签名、函数指针,分别对应代码中的name、signature、fnPtr,其中函数指针就是上面头文件里声明的Init(...)
函数,至于reinterpret_cast
到底啥意思也不必深究,说白了就是强制转换,然后用jni找到FlutterJNI类对象。咱知道这些就够了,毕竟是走马观花嘛!哦对了,咱的马还栓在洞外呢!这个洞里是不是很爽?冬暖夏凉。哎呀!哪里来的水流淋在咱头上了?
好,回到正题上,再探探FlutterJNI底层初始化是怎么做的?
void FlutterMain::Init(JNIEnv* env,
jclass clazz,
jobject context,
jobjectArray jargs,
jstring kernelPath,
jstring appStoragePath,
jstring engineCachesPath,
jlong initTimeMillis) {
std::vector<std::string> args;
args.push_back("flutter");
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
args.push_back(std::move(arg));
}
auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
auto settings = SettingsFromCommandLine(command_line);
//...
g_flutter_main.reset(new FlutterMain(std::move(settings)));
//...
}
大致意思就是,定义一个向量,相当于数组,然后往里塞字符串"flutter",再往里塞其它必要的参数,之后生成命令行,根据命令行生成settings,最后构造一个FlutterMain的对象。知道了这些,好像没啥用哦。
你挑上担,他牵上马,我继续观花。
@Nullable private PlatformMessageHandler platformMessageHandler;
刚走不久,这个变量引起了我的注意,表面意思是平台消息Handler,干嘛用的呢?先猜猜看,这里所说的platform
可能是跨平台的平台
,相当于Android、iOS等。猜错了也没关系嘛。既然是平台消息,那多多少少跟Flutter与这些平台之间的消息交互挂点钩。
/** Handler that receives messages from Dart code. */
public interface PlatformMessageHandler {
void handleMessageFromDart(
@NonNull final String channel,
@Nullable ByteBuffer message,
final int replyId,
long messageData);
void handlePlatformMessageResponse(int replyId, @Nullable ByteBuffer reply);
}
没打开这个类之前,原以为这个类会相当庞大,没想到就这么几行而已。这个类的注释写着:这是一个Handler,用来接收从Dart那儿发过来的消息。Dart发给谁的消息要它接收呀?引擎本身,还是Android?既然Dart会有消息发过来,那么这边肯定可以发消息给Dart。既然如此,那又是怎么做到的呢?咱继续看。
private native void nativeDispatchEmptyPlatformMessage(
long nativeShellHolderId, @NonNull String channel, int responseId);
这是FlutterJNI对象可以调用的本地方法,用来发送一条空平台消息给Dart。不出意料,又是C/C++底层实现的。咱去找找看,到底是如何实现的。
在shell/platform/android
目录下,有个platform_view_android_jni_impl.cc
源文件。
{
.name = "nativeDispatchEmptyPlatformMessage",
.signature = "(JLjava/lang/String;I)V",
.fnPtr = reinterpret_cast<void*>(&DispatchEmptyPlatformMessage),
}
顺藤摸瓜。
void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env,
std::string name,
jint response_id) {
fml::RefPtr<flutter::PlatformMessageResponse> response;
if (response_id) {
response = fml::MakeRefCounted<PlatformMessageResponseAndroid>(
response_id, jni_facade_, task_runners_.GetPlatformTaskRunner());
}
PlatformView::DispatchPlatformMessage(
std::make_unique<flutter::PlatformMessage>(std::move(name),
std::move(response)));
}
这是分发空平台消息的底层实现,什么意思呢?如果response_id非0,就给response指针赋一个值,连带name,交付给PlatformView::DispatchPlatformMessage(...)
的。那么此函数又是如何实现的呢?
void PlatformView::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
delegate_.OnPlatformViewDispatchPlatformMessage(std::move(message));
}
不禁要问,这里的delegate_
是什么,这个函数又做了什么?这里将它理解为一个平台视图的委托即可。
void Shell::OnPlatformViewDispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
//...
task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable(
[engine = engine_->GetWeakPtr(), message = std::move(message)]() mutable {
if (engine) {
engine->DispatchPlatformMessage(std::move(message));
}
}));
}
原来是往任务队列里塞了一个任务,而这个任务就是发送消息。那么上面代码中的engine->DispatchPlatformMessage(std::move(message));
又做了件什么事情呢?
void Engine::DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) {
std::string channel = message->channel();
if (channel == kLifecycleChannel) {
if (HandleLifecyclePlatformMessage(message.get())) {
return;
}
} else if (channel == kLocalizationChannel) {
if (HandleLocalizationPlatformMessage(message.get())) {
return;
}
} else if (channel == kSettingsChannel) {
HandleSettingsPlatformMessage(message.get());
return;
} else if (!runtime_controller_->IsRootIsolateRunning() &&
channel == kNavigationChannel) {
// If there's no runtime_, we may still need to set the initial route.
HandleNavigationPlatformMessage(std::move(message));
return;
}
if (runtime_controller_->IsRootIsolateRunning() &&
runtime_controller_->DispatchPlatformMessage(std::move(message))) {
return;
}
FML_DLOG(WARNING) << "Dropping platform message on channel: " << channel;
}
然后就是根据不同的通道进行消息分发。这里咱不看其它通道消息是如何分发的,单看最后一个运行时控制器是如何分发消息的。
bool RuntimeController::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
//...
platform_configuration->DispatchPlatformMessage(std::move(message));
//...
}
怎么调用还没完!我都快没耐心了!
void PlatformConfiguration::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
//...
tonic::CheckAndHandleError(
tonic::DartInvoke(dispatch_platform_message_.Get(),
{tonic::ToDart(message->channel()), data_handle,
tonic::ToDart(response_id)}));
}
好像有门儿!。
Dart_Handle DartInvoke(Dart_Handle closure,
std::initializer_list<Dart_Handle> args) {
int argc = args.size();
Dart_Handle* argv = const_cast<Dart_Handle*>(args.begin());
Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv);
CheckAndHandleError(handle);
return handle;
}
函数参数是一个闭包和一个列表,实现是把列表大小给argc,argv指向列表头,然后传入参数执行闭包。这里的闭包实参应该就是上面的dispatch_platform_message_.Get()
,列表实参应该就是上面的
{tonic::ToDart(message->channel()), data_handle,tonic::ToDart(response_id)}
。
在FlutterEngine类中,第二个非空final域就是变量renderer
,那么就进去走马观花一下。顾名思义,它是一个渲染器,用来在Android视图层次结构中把Flutter页面绘制出来。那么绘制在哪里呢?这不废话嘛!前一句不是刚说完嘛!这里说的是更直接的地方,它是一个Surface,是由RenderSurface提供的。那RenderSurface又是什么呢?
public interface RenderSurface {
@Nullable
FlutterRenderer getAttachedRenderer();
void attachToRenderer(@NonNull FlutterRenderer renderer);
void detachFromRenderer();
void pause();
}
以上便是它的所有代码了,可是它是如何提供Surface的呢?它只是一个接口,那么要从它的实现者入手了。
public class FlutterImageView extends View implements RenderSurface
public class FlutterSurfaceView extends SurfaceView implements RenderSurface
public class FlutterTextureView extends TextureView implements RenderSurface
从源码可以清晰地发现,它的实现者有三个,分别是:FlutterImageView
、FlutterSurfaceView
、FlutterTextureView
。好了,到目前为止,已经知道了真正提供Surface的是谁了,至于它们仨又是如何实现的,此处不作赘述。
@NonNull private final FlutterJNI flutterJNI;
//...
private boolean isDisplayingFlutterUi = false;
private final FlutterUiDisplayListener flutterUiDisplayListener =
new FlutterUiDisplayListener() {
@Override
public void onFlutterUiDisplayed() {
isDisplayingFlutterUi = true;
}
@Override
public void onFlutterUiNoLongerDisplayed() {
isDisplayingFlutterUi = false;
}
};
public FlutterRenderer(@NonNull FlutterJNI flutterJNI) {
this.flutterJNI = flutterJNI;
this.flutterJNI.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
}
看,以上便是构造器的全貎了,设置了一个flutterJNI
,添加了一个监听器。这个构造器在哪里被调用了呢?
FlutterEngine
构造器中FlutterView
构造器中
另外,这个监听器的回调是在何时发生的呢?
public void onFirstFrame() {
//...
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
listener.onFlutterUiDisplayed();
}
}
void onRenderingStopped() {
//...
for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
listener.onFlutterUiNoLongerDisplayed();
}
}
以上两个实例方法是定义在FlutterJNI
中的。根据其方法名可以窥见监听回调的发生时机。再深入的是这两个实例方法的调用时机,此处不作介绍。
public void startRenderingToSurface(@NonNull Surface surface, boolean keepCurrentSurface) {
//...
if (this.surface != null && !keepCurrentSurface) {
stopRenderingToSurface();
}
this.surface = surface;
flutterJNI.onSurfaceCreated(surface);
}
再来看渲染器如何启动渲染工作的。设置surface,然后通知flutterJNI
有surface了。咱尝试着看一下flutterJNI
是如何处理这一通知的。
public void onSurfaceCreated(@NonNull Surface surface) {
//...
nativeSurfaceCreated(nativeShellHolderId, surface);
}
private native void nativeSurfaceCreated(long nativeShellHolderId, @NonNull Surface surface);
static void SurfaceCreated(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jobject jsurface) {
// ...
auto window = fml::MakeRefCounted<AndroidNativeWindow>(
ANativeWindow_fromSurface(env, jsurface));
ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}
void PlatformViewAndroid::NotifyCreated(
fml::RefPtr<AndroidNativeWindow> native_window) {
//...
PlatformView::NotifyCreated();
}
原来是通知了平台视图。那么之后又做了什么呢?咱先看一下这个函数的实现:
void PlatformView::NotifyCreated() {
std::unique_ptr<Surface> surface;
// Threading: We want to use the platform view on the non-platform thread.
// Using the weak pointer is illegal. But, we are going to introduce a latch
// so that the platform view is not collected till the surface is obtained.
auto* platform_view = this;
fml::ManualResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetRasterTaskRunner(), [platform_view, &surface, &latch]() {
surface = platform_view->CreateRenderingSurface();
if (surface && !surface->IsValid()) {
surface.reset();
}
latch.Signal();
});
latch.Wait();
if (!surface) {
FML_LOG(ERROR) << "Failed to create platform view rendering surface";
return;
}
delegate_.OnPlatformViewCreated(std::move(surface));
}
说真的,我也看不懂啥意思,但是没关系,我可以瞎猜嘛,猜错了也不用付费的。如果读者有自己的想法,甚至与我相悖,也没事。下面是我瞎猜的内容:有一个信号量latch,它一直在等待,直到surface被造出来,然后执行最后一句代码。那surface是如何被造出来的呢?
std::unique_ptr<Surface> PlatformViewAndroid::CreateRenderingSurface() {
if (!android_surface_) {
return nullptr;
}
return android_surface_->CreateGPUSurface(
android_context_->GetMainSkiaContext().get());
}
好了,到此处为止,可以知道它返回的是CreateGPUSurface
函数的返回值。Flutter的渲染是直接由GPU处理的,而Skia是Google的图形渲染引擎。再详细的内容,这里不关心。不过,可以看一下这里的android_surface_
是哪儿来的。
PlatformViewAndroid::PlatformViewAndroid(...) {
if (android_context_) {
//...
android_surface_ = surface_factory_->CreateSurface();
//...
}
}
std::unique_ptr<AndroidSurface> AndroidSurfaceFactoryImpl::CreateSurface() {
switch (android_context_->RenderingApi()) {
case AndroidRenderingAPI::kSoftware:
return std::make_unique<AndroidSurfaceSoftware>(android_context_,
jni_facade_);
case AndroidRenderingAPI::kOpenGLES:
return std::make_unique<AndroidSurfaceGL>(android_context_, jni_facade_);
default:
FML_DCHECK(false);
return nullptr;
}
}
enum class AndroidRenderingAPI {
kSoftware,
kOpenGLES,
};
好了,看清楚了,它是由工厂创建的,还分为两种方式进行创建,分别为kSoftware
、kOpenGLES
。
接下来还剩上文中的void PlatformView::NotifyCreated()
定义中的最后一句代码没说了。
void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
//...
auto ui_task = [engine = engine_->GetWeakPtr()] {
if (engine) {
engine->ScheduleFrame();
}
};
//...
sk_sp<GrDirectContext> resource_context =
platform_view->CreateResourceContext();
//...
}
调度帧、创建资源上下文。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)