security center启动类型更改不了_Android APP冷启动优化

1、优化前问题

我的测试手机是小米1,对于目前的App来说,运行时都会有卡顿。刚接手新的项目,在我的手机上跑跑,发现App启动后时候,在进入Splash页面前有3~4秒的白屏,这个不能接受,趁着空闲,着手优化一下。

2、优化方案

我记忆中的优化方案是给Application设置一个theme,给这个theme添加一个<item name="android:windowBackground">@drawable/ic_splash</item>,保证splash_img和Splash页面一样,这样就能正常加载显示了。Run一下,发现无效果,而给SplashActivity添加,冷启动却能正常显示图片的效果,但问题是图片有拉伸。这个肯定不行吧,找了一下网上的策略,发现都是这么直接给theme添加图片的,准备自己查找一下解决方案。

因为直接放图片,在不同手机上有严重的拉伸,如果创建多张不同尺寸的splash图片放在不同的drawable/mipmap中,那又会增大包大小。(没有去验证这种方法是否可行)那就只能是用xml文件来布局显示了。

我尝试将@layout/activity_splash直接作为windowBackground的值,发现App启动即异常退出,于是想到可以使用layer-list这种布局。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="114dp">
        <bitmap android:src="@drawable/ic_splash" android:width="21dp" android:height="21dp"/>
    </item>
</layer-list>

运行后,图片还是有拉伸,google一下layer-list,发现文档中写的有防止图片缩放的方法。

默认情况下,所有可绘制项都会缩放以适应包含视图的大小。因此,将图像放在图层列表中的不同位置可能会增大视图的大小,并且有些图像会相应地缩放。为避免缩放列表中的项目,请在 <item> 元素内使用 <bitmap> 元素指定可绘制对象,并且对某些不缩放的项目(例如 "center")定义重力。例如,以下 <item> 定义缩放以适应其容器视图的项目:

<item android:drawable="@drawable/image" />

为避免缩放,以下示例使用重力居中的 <bitmap> 元素:

<item>
  <bitmap android:src="@drawable/image"
          android:gravity="center" />
</item>

好了,再次修改修改布局代码:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white"/>
    <item android:top="114dp">
        <bitmap android:src="@drawable/ic_splash" android:width="21dp" android:height="21dp"
            android:gravity="center|top"/>
    </item>
</layer-list>

运行后,非常完美。

3、再次优化

虽然在保证windowBackground的背景和SplashActivity的contentView一致情况下,效果已经完全可以了,但是了解activity的窗口的都清楚,其实windowBackground和contentView都是在同一个窗口中的,所以有了前者就不需要再设置后者了。于是,删除SplashActivity中的setContentView(R.layout.activity_splash);后,程序依旧完美运行。

4、原理剖析

其实这就是activity的窗口的机制了。Activity的attach方法。

Activity.java
final void attach(){
。。。
mWindow = new PhoneWindow(this, window, activityConfigCallback);//创建PhoneWindow
。。。
}

PhoneWindow.java

PhoneWindow(){
      mUseDecorContext = true;   //后面用到
      。。。
      mDecor = (DecorView) preservedWindow.getDecorView();   //获取DecorView,基本就是创建了,然后设置theme。
      。。。
}

public final void setBackgroundDrawable(Drawable drawable) {
     if (mDecor != null) {
         mDecor.setWindowBackground(drawable);   //设置PhoneWindow的背景,其实就是设置DecorView背景。
     }
}

那什么时候调用PhoneWindow的setBackgroundDrawable来设置背景呢?看Activity的基类AppCompatActivity

AppCompatActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppCompatDelegate delegate = this.getDelegate();
        delegate.installViewFactory();
        delegate.onCreate(savedInstanceState);
        。。。
}

public AppCompatDelegate getDelegate() {
        if (this.mDelegate == null) {
            this.mDelegate = AppCompatDelegate.create(this, this);
        }

        return this.mDelegate;
}

AppCompatDelegate.java
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
        return new AppCompatDelegateImpl(activity, activity.getWindow(), callback);
}

AppCompatDelegateImpl.java
AppCompatDelegateImpl(Context context, Window window, AppCompatCallback callback) {
      //sWindowBackgroundStyleable就是private static final int[] sWindowBackgroundStyleable = {android.R.attr.windowBackground};
      TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, (AttributeSet)null, sWindowBackgroundStyleable);
      Drawable winBg = a.getDrawableIfKnown(0);
      if (winBg != null) {
          this.mWindow.setBackgroundDrawable(winBg);      //设置window背景
      }
}

好了,基本上厘清了,Activity在attach时候new PhoneWindow-》new Decorview,在onCreate时候,设置PhoneWindow背景,及Decorview背景,所以窗口能正常显示我们设置的布局内容,因为系统已经替我们设置了默认的布局视图。

而setContentView的工作内容呢。

    public void setContentView(int resId) {
        this.ensureSubDecor();
        ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(16908290);
        contentParent.removeAllViews();
        LayoutInflater.from(this.mContext).inflate(resId, contentParent);      //只是将自定义的布局添加到16908290容器内,就是FrameLayout内容。
        this.mOriginalWindowCallback.onContentChanged();
    }

所以,setContentView在这个时候是画蛇添足的作用。

5、重要点。

(1)为SplashActivity的theme添加windowBackground。

(2)编写layer-list.xml布局文件。

(3)注掉SplashActivity的setContentView。

编辑、加图不太方便,先这么着。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值