当前位置: 移动技术网 > IT编程>移动开发>Android > Flutter启动页(闪屏页)的具体实现及原理详析

Flutter启动页(闪屏页)的具体实现及原理详析

2019年07月23日  | 移动技术网IT编程  | 我要评论

苹果被删,限号,15crmog高压锅炉管

为什么要有启动页?

在以下文章中,启动页就是闪屏页。

现在大部分app都有启动页,那么为什么要有启动页?这是个值得思考的问题,如果没有启动页会怎样,大部分的app会白屏(也有可能是黑屏,主题设置有关系)非常短的时间,然后才能展示app的内容。

那么问题来了,一定要有启动页吗?答案:不是,而且是尽可能不要有启动页,因为启动页会让用户体验不够连贯,甚至ios在开发手册上就不推荐使用启动页。

我们深入思考一下,既然不推荐为什么这样流行,答案非常简单,启动页的成本非常低,如果你想把的app启动优化到一个非常短的时间,还是有一定成本的。

android启动流程

为什么要谈android的启动流程呢?因为flutter启动的时候,依赖的是android的运行环境,其本质是activity上添加了一个flutterview,flutterview继承surfaceview,那么就容易理解了,flutter的全部页面都是渲染到了flutterview上,如果不熟悉flutter的启动流程可以参考flutter启动流程 这篇文章,下面是对flutter启动的一个简单描述。

在flutter中,启动页的作用是在flutterview显示第一帧之前,不要出现白屏,在flutterview显示第一帧之前,我们分成两个阶段,android启动阶段和flutter启动阶段,android启过程添加启动页非常容易,在主题xml中添加android:windowbackground属性,flutter怎么添加启动页呢?其实框架已经帮助咱们实现好了,我下面就给大家说一下原理。

flutter启动页具体实现和原理

创建一个splashactivity,这activity继承flutteractivity,重写oncreate()方法,在oncreate()方法中调用generatedpluginregistrant.registerwith() ,下面是启动页的代码。

public class splashactivity extends flutteractivity {

 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 generatedpluginregistrant.registerwith(this);
 }
}

在manifest中添加splashactivity作为app的启动activity,设置splashactivity的主题是launchtheme。下面是manifest的配置文件。

 <activity
 android:name=".splashactivity"
 android:configchanges="orientation|keyboardhidden|keyboard|screensize|locale|layoutdirection|fontscale|screenlayout|density|uimode"
 android:hardwareaccelerated="true"
 android:launchmode="singletop"
 android:theme="@style/launchtheme"
 android:windowsoftinputmode="adjustresize">
 <meta-data
 android:name="io.flutter.app.android.splashscreenuntilfirstframe"
 android:value="true" />
 <intent-filter>
 <action android:name="android.intent.action.main" />
 <category android:name="android.intent.category.launcher" />
 </intent-filter>
 </activity>

meta-data的name = "io.flutter.app.android.splashscreenuntilfirstframe"的value一定要设置成true,一定要设置成true,一定要设置成true重要的事情说三遍,如果这个属性设置成false,效果是这样的。

从现象观察,启动页中间有一段时间黑屏,这个为什么呢?前面我们说过,flutter的启动流程分成两部分,一部分是android启动阶段,一个是flutter的启动阶段,这个黑屏就是flutter的启动阶段没有启动页所造成的。我们从源码入手,详细分析一下,下面是flutteractivitydelegate的部分源码。

public final class flutteractivitydelegate
 implements flutteractivityevents,
  flutterview.provider,
  pluginregistry {
 private static final string splash_screen_meta_data_key = "io.flutter.app.android.splashscreenuntilfirstframe";

 private view launchview;

 @override
 public void oncreate(bundle savedinstancestate) {
 string[] args = getargsfromintent(activity.getintent());
 fluttermain.ensureinitializationcomplete(activity.getapplicationcontext(), args);
 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();//1
 if (launchview != null) {
 addlaunchview();//2
 }
 }
 }

 private view createlaunchview() {
 if (!showsplashscreenuntilfirstframe()) {//3
 return null;
 }
 final drawable launchscreendrawable = getlaunchscreendrawablefromactivitytheme();
 final view view = new view(activity);
 view.setbackground(launchscreendrawable);
 return view;
 }

 private drawable getlaunchscreendrawablefromactivitytheme() {
 //省略了部分代码
 try {
 return activity.getresources().getdrawable(typedvalue.resourceid);
 } catch (notfoundexception e) {
 return null;
 }
 }

 private boolean showsplashscreenuntilfirstframe() {
 try {
 activityinfo activityinfo = activity.getpackagemanager().getactivityinfo(
 activity.getcomponentname(),
 packagemanager.get_meta_data|packagemanager.get_activities);
 bundle metadata = activityinfo.metadata;
 return metadata != null && metadata.getboolean(splash_screen_meta_data_key);
 } catch (namenotfoundexception e) {
 return false;
 }
 }

 private void addlaunchview() {
 activity.addcontentview(launchview, matchparent);//4
 flutterview.addfirstframelistener(new flutterview.firstframelistener() {//5
 @override
 public void onfirstframe() {
 flutteractivitydelegate.this.launchview.animate()
  .alpha(0f)
  .setlistener(new animatorlisteneradapter() {
  @override
  public void onanimationend(animator animation) {
  ((viewgroup) flutteractivitydelegate.this.launchview.getparent())
  .removeview(flutteractivitydelegate.this.launchview);//5
  }
  });
 }
 });
 activity.settheme(android.r.style.theme_black_notitlebar);
 }
}

注释1

这个段代码很容易理解,创建一个launchview,主要逻辑在createlaunchview()中,原理也很简单,根据主题中的r.attr.windowbackground属性,生成一个drawable,然后创建了一个view,并且把这个view的背景设置成drawable。

注释3

showsplashscreenuntilfirstframe()是得到manifet中io.flutter.app.android.splashscreenuntilfirstframe的属性的值,如果是false,那么久返回一个空的的launchview,也就不会执行注释2的代码。这就是我们上面说的如果设置成false就显示黑屏的原因。

注释2

调用addlaunchview(),这方法也很简单,首先看注释4,把launchview添加到当前的activity中,然后添加了一个监听,在注释5处,这个监听是当flutterview第一帧加载完成后回调,回调做了什么事情呢?很简单,把launchview删除了,显示flutterview的第一帧。

总结一下,就是把android的启动页生成一个drawable,创建了一个launchview,把drawable设置成launchview的背景,当前的activity添加这launchview,如果flutterview的第一帧显示了,把launchview删除。

设置主题,下面是launchtheme的代码。

<resources>
 <style name="launchtheme" parent="@android:style/theme.black.notitlebar">
 <!-- show a splash screen on the activity. automatically removed when
 flutter draws its first frame -->
 <item name="android:windowbackground">@drawable/launch_background</item>
 </style>
</resources>

下面是launch_background的代码。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
 android:opacity="opaque">
 <item>
 <bitmap android:src="@mipmap/ic_launch_bg" />
 </item>
 <item
 android:width="90dp"
 android:height="90dp"
 android:gravity="center">
 <bitmap android:src="@mipmap/ic_launch_logo" />
 </item>
</layer-list>

最终效果如下,没有黑屏,非常顺滑。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网