以Android7.0为例,我们知道Android应用在启动时候,PhoneWindowManager会添加一个空白启动窗口,叫做addStartingWindow,在界面加载完毕后,会removeStartingWindow。

 
    /** {@inheritDoc} */@Overridepublic View addStartingWindow(IBinder appToken, String packageName, int theme,CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,int icon, int logo, int windowFlags) {if (!SHOW_STARTING_ANIMATIONS) {return null;}if (packageName == null) {return null;}WindowManager wm = null;View view = null;try {Context context = mContext;if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName+ ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="+ Integer.toHexString(theme));if (theme != context.getThemeResId() || labelRes != 0) {try {context = context.createPackageContext(packageName, 0);context.setTheme(theme);} catch (PackageManager.NameNotFoundException e) {// Ignore}}PhoneWindow win = new PhoneWindow(context);win.setIsStartingWindow(true);final TypedArray ta = win.getWindowStyle();if (ta.getBoolean(com.android.internal.R.styleable.Window_windowDisablePreview, false)|| ta.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {return null;}Resources r = context.getResources();win.setTitle(r.getText(labelRes, nonLocalizedLabel));win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);synchronized (mWindowManagerFuncs.getWindowManagerLock()) {// Assumes it's safe to show starting windows of launched apps while// the keyguard is being hidden. This is okay because starting windows never show// secret information.if (mKeyguardHidden) {windowFlags |= FLAG_SHOW_WHEN_LOCKED;}}// Force the window flags: this is a fake window, so it is not really// touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM// flag because we do know that the next window will take input// focus, so we want to get the IME window up on top of us right away.win.setFlags(windowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,windowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);win.setDefaultIcon(icon);win.setDefaultLogo(logo);win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT);final WindowManager.LayoutParams params = win.getAttributes();params.token = appToken;params.packageName = packageName;params.windowAnimations = win.getWindowStyle().getResourceId(com.android.internal.R.styleable.Window_windowAnimationStyle, 0);params.privateFlags |=WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;if (!compatInfo.supportsScreen()) {params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;}params.setTitle("Starting " + packageName);wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);view = win.getDecorView();if (win.isFloating()) {// Whoops, there is no way to display an animation/preview// of such a thing!  After all that work...  let's skip it.// (Note that we must do this here because it is in// getDecorView() where the theme is evaluated...  maybe// we should peek the floating attribute from the theme// earlier.)return null;}if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for " + packageName+ " / " + appToken + ": "+ (view.getParent() != null ? view : null));wm.addView(view, params);// Only return the view if it was successfully added to the// window manager... which we can tell by it having a parent.return view.getParent() != null ? view : null;} catch (WindowManager.BadTokenException e) {// ignoreLog.w(TAG, appToken + " already running, starting window not displayed. " +e.getMessage());} catch (RuntimeException e) {// don't crash if something else bad happens, for example a// failure loading resources because we are loading from an app// on external storage that has been unmounted.Log.w(TAG, appToken + " failed creating starting window", e);} finally {if (view != null && view.getParent() == null) {Log.w(TAG, "view not successfully added to wm, removing view");wm.removeViewImmediate(view);}}return null;}

空白启动窗口给用户的操作体验是很差的,尤其是低端手机,或者应用冷启动时间较长时。所以就想到能不能在应用冷启动的时候,对启动窗口进行截屏,然后将截图缓存起来。当下一次应用冷启动时候,用截图的窗口代替原来的空白启动窗口呢?答案是可以的。流程如下图所示。问题的关键是截屏时机在哪里?冷启动过程中,WindowState中的mAttrs(WindowManager.LayoutParams)的type,有一个切换过程,从WindowManager.LayoutParams.TYPE_APPLICATION_STARTING  --->WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW,

            if (mService.isFastStartingWindowSupport() && mWin.mAttrs.type == WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW  && mService.lastLayoutParamsType== android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING  && mWin.mAppToken != null) {mCanScreenshot = true;doCacheBitmap();}mService.lastLayoutParamsType = mWin.mAttrs.type;//application start , mWin.mAttrs.type from  3--->1

lastLayoutParamsType是在    WMS中新声明的

public int lastLayoutParamsType = -1;

当然这个变化还有你的应用androidmanifest中application的设置有关。

上面截屏的逻辑是定义在WindowStateAnimator中performShowLocked的,在此时截屏,其实整个界面还是没有绘制完成的,看下面的doCacheBitmap,需要子线程延时一定时间,同时,对截屏的图像进行判断。

    void doCacheBitmap() {AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {@Overrideprotected Void doInBackground(Void... para) {//android.os.Process.setThreadPriority//    (android.os.Process.THREAD_PRIORITY_FOREGROUND);try {if (mWmSleep != -1) {Thread.sleep(mWmSleep);} else {Thread.sleep(250);}if(mWin.mWinAnimator.mSurfaceController == null){// in some case , mSurfaceController is nullreturn null;}if(!mCanScreenshot){return null;}Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AsyncScreenshot");Bitmap bmShot = SurfaceControl.screenshot(new Rect(),(int) mWin.mWinAnimator.mSurfaceController.mSurfaceW,(int) mWin.mWinAnimator.mSurfaceController.mSurfaceH,mSurfaceController.mSurfaceLayer,mSurfaceController.mSurfaceLayer, false, 0);Slog.i(TAG, "doCacheBitmap, mToken =" + mWin.mToken);int leftTopColor = bmShot.getPixel(0, 0);int rightTopColor = bmShot.getPixel(mContext.getResources().getDisplayMetrics().widthPixels - 1, 0);int leftBottomColor = bmShot.getPixel(0, mContext.getResources().getDisplayMetrics().heightPixels - 1);int rightBottomColor = bmShot.getPixel(mContext.getResources().getDisplayMetrics().widthPixels - 1, mContext.getResources().getDisplayMetrics().heightPixels - 1);int averageColor = (getAverageRGB(leftTopColor) + getAverageRGB(rightTopColor) + getAverageRGB(leftBottomColor) + getAverageRGB(rightBottomColor)) / 4;if (averageColor < 5) {//in some case, the bitmap is a starting window(it is a picture with black boder,or the picture is whole black) , not a started window , so returnreturn null;}if (bmShot != null && mWin.mToken != null) {mService.setBitmapByToken(mWin.mToken.token, bmShot.copy(bmShot.getConfig(), true));bmShot.recycle();}Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);} catch (Exception e) {e.printStackTrace();}return null;}};task.execute();}

应用快速启动流程如下图所示:

(1) 用户在点击应用的时候,ActivityManagerService会执行startActivity方法,然后ActivityStack执行startActivityLocked方法,然后ActivityRecord执行showStartingWindow方法,最后调用WindowManagerService的setAppStartingWindow来设置一个启动窗口。

(2) WindowManagerService会判断当前系统是否支持FSW并且当前窗口是否有Bitmap缓存,如果是开机后第一次启动,则执行Android系统原有方法addStartingWindow,添加一个空白窗口。如果系统支持FSW并且当前窗口有Bitmap缓存,则执行addFastStartingWindow方法,添加一个非空白窗口。

(3) 应用冷启动时,WindowMangerService通过WindowStateAnimator进行窗口缓存。WindowMangerService收到configChange广播,则清除bitmap缓存。

加入该技术后,给用户的感觉是应用秒开,对比测试友商手机,冷启动速度都要比我们的差,加入该技术的应用,冷启动速度只有300ms。

该技术的局限性在于,仅适用于启动界面变化较小的APP,变化较大的应用不适合,第三方应用基本都不适合。

第一篇博客就写到这里把。

Android快速启动窗口技术相关推荐

  1. android 快速启动,《Android APP可以有的东西》之显示篇:快速启动App

    前言 又有好久木有更新啦,快成咸鱼了. 早上看到一篇关于app快速启动的公众号文章,觉得应该全面了解一下这个东西,所以这篇文章就小小地实践一下下记录下来,内容并不多,demo都没有必要上,大家直接看代 ...

  2. android 快速启动服务,Android应用快速启动设计

    Android启动过程 Anroid应用启动在应用层主要分为如下几个阶段:Application初始化,Activity初始化,Service初始化,视图Tranversal 从快速启动的角度来看,应 ...

  3. imx6 android快速启动,android启动不起来(已解决)

    我使用imx6dl,使用JB4.3.3-1.1.0版本,但在启动的时候最后停在了Freeing init memory: 232K,就没了动静,各位大侠帮忙分析一下吧: 以下是log: U-Boot ...

  4. imx6 android快速启动,freescale imx6 开机启动速度优化之Bootchart工具的使用问题

    之前有安装bootchart,先执行以下命令,卸载掉bootchart工具 sudo apt-get autoremove bootchart bootchart安装 1.安装 $sudo apt-g ...

  5. Android 快速修复功能,安卓系统修复工具(ReiBoot for Android)v2.1.0免费版

    通过ReiBootforAndroid用户可以解决自己手机的大部分问题并将其快速回复到最佳状态,ReiBootforAndroid一款非常好用的安卓手机系统修复软件.像是黑屏.卡在下载界面或者顺序解体 ...

  6. 嵌入式Linux初始化硬件RTC,嵌入式Linux系统中的快速启动技术研究

    嵌入式Linux系统主要特点在于使用Bootloader替代了桌面系统的BIOS,同时对系统进行了规模上的裁剪,但硬件上的劣势往往导致系统启动速度较慢,而嵌入式产品使用者又对系统的开机速度比较敏感,样 ...

  7. 英特尔快速启动技术如何安装

    英特尔快速启动技术,在大家购买计算机时应该都有见过,这个技术很实用.众所周知,当我们使用计算机睡眠按钮的时候,电脑会保存当前工作状态到内存中,但前提是计算机必须要一直供电,否则内存数据会丢失. 所以, ...

  8. 一文讲解电源技术中的安森美深力科CAT6219-330TDGT3 500 mA,带快速启动 LDO稳压器 详情讲解

    一文讲解电源技术中的安森美深力科CAT6219-330TDGT3 500 mA,带快速启动 LDO稳压器 详情讲解 CAT6219-330TDGT3是一款 500 mA CMOS 低漏稳压器,在负载电 ...

  9. 用华为HMS ML kit人体骨骼识别技术,Android快速实现人体姿势动作抓拍

    用华为HMS ML kit人体骨骼识别技术,Android快速实现人体姿势动作抓拍 你有没有过这种体验,拍照时对着镜头,脑子一片空白.表情僵硬.手和脚无处安放,最后拍出来的照片很是奇怪.拍照软件中的固 ...

  10. 快速启动android模拟器,逍遥安卓模拟器黑科技发布电脑玩手游永久快速启动

    原标题:逍遥安卓模拟器黑科技发布电脑玩手游永久快速启动 所有使用安卓模拟器的用户,在电脑上玩手游的过程中,等待安卓模拟器以及游戏的启动是最煎熬的过程,尤其是当安卓模拟器使用过一段时间之后,启动的速度会 ...

最新文章

  1. 测试进口原装磁屏蔽电感 10MH的漏感以及在再生高频放大检波电路中的应用
  2. 如何提高PyTorch“炼丹”速度?这位小哥总结了17种方法,可直接上手更改的那种...
  3. 1.7 截取(提取)子字符串(substring())
  4. android PowerManage
  5. iOS15仿微信详情二维码支持保存本地相册
  6. 前端学习(2250)拉取代码文件
  7. 夺命雷公狗---微信开发09----玩转单图文消息回复
  8. PHP生成随机数;订单号唯一
  9. 千万级测试String、StringBuffer和StringBuilder的速度
  10. android开发actionbar,Android 开发之为ActionBar 添加Actionbar Button
  11. 配置国内免费registry mirror -daocloud、网易、阿里云和七牛
  12. 唤客猫SCRM功能详解(二)
  13. 怎么设置计算机键盘数字键,电脑右边的数字键不能用怎么办_电脑右边数字键盘用不了的修复方法...
  14. 深入理解计算机系统第2版--读书笔记
  15. Nuscenes——环视相机下BEV时序融合:前后帧空间对齐操作
  16. 第三部分 数据结构 -第一章 栈-1357:车厢调度(train)
  17. 基于单幅图像的2D转3D算法研究
  18. NIST 网络安全框架导读
  19. 【大数进制转换】清华大学考研复试上机——进制转换(10—2)
  20. 景区如何设计打造文旅夜游项目

热门文章

  1. dell 服务器自动更新驱动程序,通过Repository Manager 1.3来管理戴尔驱动程序更新
  2. keyshot场景素材导入_KeyShot导入Rhino室内场景渲染的详细方法
  3. IJCAI2021 Person Re-identification相关论文集合推荐
  4. SpringMVC:视图解析器(ViewResolver)
  5. struct usb_driver
  6. 百度短网址 php,PHP实现百度、网易、新浪短网址服务的API接口调用
  7. Sails框架知识点
  8. python123高次方程求根_1.1方程求根之二分法
  9. 【OpenCV】图像多通道混合、缩放
  10. 「干货」从动态的角度分析DDR的时序结构