【从入门到放弃】android布局优化深入解析

view = mFactory2.onCreateView(parent, name, context, attrs);

} else if (mFactory != null) {

view = mFactory.onCreateView(name, context, attrs);

} else {

view = null;

}

return view;

}

在真正进行反射实例化xml结点前,会调用mFactory2onCreateView方法

这样如果我们重写onCreateView方法,在其前后加上耗时统计,即可获取每个控件的加载耗时

private fun initItemInflateListener(){

LayoutInflaterCompat.setFactory2(layoutInflater, object : Factory2 {

override fun onCreateView(

parent: View?,

name: String,

context: Context,

attrs: AttributeSet

): View? {

val time = System.currentTimeMillis()

val view = delegate.createView(parent, name, context, attrs)

Log.i(“inflate Item”,name + " cost " + (System.currentTimeMillis() - time))

return view

}

override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {

return null

}

})

}

如上所示:真正的创建View的方法,仍然是调用delegate.createView,我们只是其之前与之后做了埋点

注意,initItemInflateListener需要在onCreate之前调用

这样就可以比较方便地实现监听每个控件的加载耗时

3.布局加载优化的一些方法介绍


布局加载慢的主要原因有两个,一个是IO,一个是反射

所以我们的优化思路一般有两个

1.侧面缓解(异步加载)

2.根本解决(不需要IO,反射过程,如X2C,Anko,Compose等)

AsyncLayoutInflater方案

AsyncLayoutInflater 是来帮助做异步加载 layout 的,inflate(int, ViewGroup, OnInflateFinishedListener) 方法运行结束之后 OnInflateFinishedListener 会在主线程回调返回 View;这样做旨在 UI 的懒加载或者对用户操作的高响应。

简单的说我们知道默认情况下 setContentView 函数是在 UI 线程执行的,其中有一系列的耗时动作:Xml的解析、View的反射创建等过程同样是在UI线程执行的,AsyncLayoutInflater 就是来帮我们把这些过程以异步的方式执行,保持UI线程的高响应。

使用如下:

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

new AsyncLayoutInflater(AsyncLayoutActivity.this)

.inflate(R.layout.async_layout, null, new AsyncLayoutInflater.OnInflateFinishedListener() {

@Override

public void onInflateFinished(View view, int resid, ViewGroup parent) {

setContentView(view);

}

});

// 别的操作

}

这样做的优点在于将UI加载过程迁移到了子线程,保证了UI线程的高响应

缺点在于牺牲了易用性,同时如果在初始化过程中调用了UI可能会导致崩溃

X2C方案

X2C是掌阅开源的一套布局加载框架

它的主要是思路是在编译期,将需要翻译的layout翻译生成对应的java文件,这样对于开发人员来说写布局还是写原来的xml,但对于程序来说,运行时加载的是对应的java文件。

这就将运行时的开销转移到了编译时

如下所示,原始xml文件:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:paddingLeft=“10dp”>

<include

android:id=“@+id/head”

layout=“@layout/head”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_centerHorizontal=“true” />

<ImageView

android:id=“@+id/ccc”

style=“@style/bb”

android:layout_below=“@id/head” />

X2C 生成的 Java 文件

public class X2C_2131296281_Activity_Main implements IViewCreator {

@Override

public View createView(Context ctx, int layoutId) {

Resources res = ctx.getResources();

RelativeLayout relativeLayout0 = new RelativeLayout(ctx);

relativeLayout0.setPadding((int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,res.getDisplayMetrics())),0,0,0);

View view1 =(View) new X2C_2131296283_Head().createView(ctx,0);

RelativeLayout.LayoutParams layoutParam1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);

view1.setLayoutParams(layoutParam1);

relativeLayout0.addView(view1);

view1.setId(R.id.head);

layoutParam1.addRule(RelativeLayout.CENTER_HORIZONTAL,RelativeLayout.TRUE);

ImageView imageView2 = new ImageView(ctx);

RelativeLayout.LayoutParams layoutParam2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,(int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,res.getDisplayMetrics())));

imageView2.setLayoutParams(layoutParam2);

relativeLayout0.addView(imageView2);

imageView2.setId(R.id.ccc);

layoutParam2.addRule(RelativeLayout.BELOW,R.id.head);

return relativeLayout0;

}

}

使用时如下所示,使用X2C.setContentView替代原始的setContentView即可

// this.setContentView(R.layout.activity_main);

X2C.setContentView(this, R.layout.activity_main);

X2C优点

1.在保留xml的同时,又解决了它带来的性能问题

2.据X2C统计,加载耗时可以缩小到原来的1/3

X2C问题

1.部分属性不能通过代码设置,Java不兼容

2.将加载时间转移到了编译期,增加了编译期耗时

3.不支持kotlin-android-extensions插件,牺牲了部分易用性

Anko方案

AnkoJetBrains开发的一个强大的库,支持使用kotlin DSL的方式来写UI,如下所示

class MyActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {

super.onCreate(savedInstanceState, persistentState)

MyActivityUI().setContentView(this)

}

}

class MyActivityUI : AnkoComponent {

override fun createView(ui: AnkoContext) = with(ui) {

verticalLayout {

val name = editText()

button(“Say Hello”) {

onClick { ctx.toast(“Hello, ${name.text}!”) }

}

}

}

}

如上所示,Anko使用kotlin DSL实现布局,它比我们使用Java动态创建布局方便很多,主要是更简洁,它和拥有xml创建布局的层级关系,能让我们更容易阅读

同时,它去除了IO与反射过程,性能更好,以下是AnkoXML的性能对比

不过由于AnKo已经停止维护了,这里不建议大家使用,了解原理即可

AnKo建议大家使用Jetpack Compose来替代使用

Compose方案

ComposeJetpack 中的一个新成员,是 Android 团队在2019年I/O大会上公布的新的UI库,目前处于Beta阶段

Compose使用纯kotlin开发,使用简洁方便,但它并不是像Anko一样对ViewGroup的封装

Compose 并不是对 ViewViewGroup 这套系统做了个上层包装来让写法更简单,而是完全抛弃了这套系统,自己把整个的渲染机制从里到外做了个全新的。

可以确定的是,Compose是取代XML的官方方案

Compose的主要优点就在于它的简单好用,具体来说就是两点

1.它的声明式 UI

2.去掉了 xml,只使用 Kotlin 一种语言

由于本文并不是介绍Compose的,所以就不继续介绍Compose了,总得来说,Compose是未来android UI开发的方向,读者可以自行查阅相关资料

4.为什么放弃使用这些优化方法?


上面介绍了不少布局加载优化方法,而我最后在项目中最后都没有使用,这就是从真从入门到放弃

总得来说有以下几个原因

1.有些方式(如AsyncLayoutInflater,X2C)牺牲了易用性,虽然性能提升了,但是开发变得麻烦了

2.Anko使用上比较方便同时性能较高,但是比起XML方式改动很大,同时Anko已经放弃维护了,在团队中推动难度大

3.Compose是未来android UI开发的方向,但目前仍处于Beta阶段,相信在Release后,会成为我们替换XML的有效手段

4.还有最主要的一点是,针对我们的项目,布局加载耗时并不是主要耗时的地方,所以优化收益不大,可以将精力投入到其他地方

如下所示,我们将setConteView前后时间相减,得到布局加载时间

onWindowFocusChangedActivity真正可见时间,将其与onCreate时间相减,可得页面显示时间

在我们的项目中测试效果如下:

android 5.0

I/Log: inflateTime:33

I/Log: activityShowTime:252

I/Log: inflateTime:11

I/Log: activityShowTime:642

I/Log: inflateTime:83

I/Log: activityShowTime:637

android 10.0

I/Log: inflateTime:11

I/Log: activityShowTime:88

I/Log: inflateTime:5

I/Log: activityShowTime:217

I/Log: inflateTime:27

I/Log: activityShowTime:221

我在android5.0手机与10.0手机上分别做了测试,在我们的项目中布局加载耗时并不很长,同时它们在整个页面可见过程中,占得比例也并不高

所以得出结论:针对我们项目,布局加载耗时并不是主要耗时的地方,优化收益不大

这就是从入门到放弃的原因

一些常规优化手段

上面介绍了一些改动比较大的方案,其实我们在实际开发中也有些常规的方法可以优化布局加载

比如优化布局层级,避免过度绘制等,这些简单的手段可能正是可以应用到项目中的

优化布局层级及复杂度

1.使用ConstraintLayout,可以实现完全扁平化的布局,减少层级

2.RelativeLayout本身尽量不要嵌套使用

3.嵌套的LinearLayout中,尽量不要使用weight,因为weight会重新测量两次

4.推荐使用merge标签,可以减少一个层级

5.使用ViewStub延迟加载

避免过度绘制

1.去掉多余背景色,减少复杂shape的使用

2.避免层级叠加

3.自定义View使用clipRect屏蔽被遮盖View绘制

总结


本文主要介绍了以下内容

1.andrid绘制原理与布局加载原理

2.如何定量的获取android布局加载耗时

3.介绍了一些布局加载优化的方法与手段(AsyncLayoutInflater,X2C,Anko,Compose等)

4.介绍了因为在我们在项目中布局加载耗时优化收益不大,所以没有引入上述优化手段

最后分享给大家一份阿里P8大佬熬夜30天整理的《Android 360°全方面性能调优》,涵盖设计思想与代码质量优化、程序性能优化、开发效率优化、其中详细讲解了启动优化、布局优化、内存优化、屏幕适配、OOM问题等方面,并且他还将自己工作中的一些项目案例在PDF中做了实践分享,整合成了一套系统的性能优化知识笔记PDF,长达721页,几乎都可以出本书了。

第一章:设计思想与代码质量优化

1.六大原则.

2.设计模式

3.数据结构

4.算法

第二章:程序员性能优化

1.启动速度与执行效率优化

2.布局检测与优化

3.内存优化

4.耗电优化

5.网络传输与数据储存优化

6.APK大小优化

7.屏幕适配

8.OOM问题原理解析

9.ANR问题解析

10.Crash监控方案

第三章:开发效率优化

1.分布式版本控制系统Git

2.自动化构建系统Gradle

第四章:APP性能优化实践

1.启动速度

2.流畅度

3.抖音在APK包大小资源优化的实践

4.优酷响应式布局技术全解析

5.网络优化

6.手机淘宝双十一性能优化项目揭秘

7.高德APP全链路源码依赖分析
先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

最后

我一直以来都有整理练习大厂面试题的习惯,有随时跳出舒服圈的准备,也许求职者已经很满意现在的工作,薪酬,觉得习惯而且安逸。

不过如果公司突然倒闭,或者部门被裁减,还能找到这样或者更好的工作吗?

我建议各位,多刷刷面试题,知道最新的技术,每三个月可以去面试一两家公司,因为你已经有不错的工作了,所以可以带着轻松的心态去面试,同时也可以增加面试的经验。

我可以将最近整理的一线互联网公司面试真题+解析分享给大家,大概花了三个月的时间整理2246页,帮助大家学习进步。

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是部分内容截图:

部分目录截图

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频**

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

最后

我一直以来都有整理练习大厂面试题的习惯,有随时跳出舒服圈的准备,也许求职者已经很满意现在的工作,薪酬,觉得习惯而且安逸。

不过如果公司突然倒闭,或者部门被裁减,还能找到这样或者更好的工作吗?

我建议各位,多刷刷面试题,知道最新的技术,每三个月可以去面试一两家公司,因为你已经有不错的工作了,所以可以带着轻松的心态去面试,同时也可以增加面试的经验。

我可以将最近整理的一线互联网公司面试真题+解析分享给大家,大概花了三个月的时间整理2246页,帮助大家学习进步。

由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是部分内容截图:

[外链图片转存中…(img-x44D711V-1711252690317)]

[外链图片转存中…(img-oCE2AFPs-1711252690318)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android是一种基于Linux的开源操作系统,主要用于移动设备和平板电脑。要从入门到精通Android开发,可以按照以下步骤进行: 1. 学习Java编程语言:Android应用程序主要使用Java编写,因此首先需要掌握Java的基本语法和概念。 2. 下载并安装Android Studio:Android Studio是官方推荐的Android开发工具,提供了丰富的开发环境和工具。 3. 学习Android基础知识:了解Android应用程序的基本结构、组件(如Activity、Fragment、Service等)和布局(如LinearLayout、RelativeLayout等)等基础概念。 4. 开发简单的Android应用:从简单的Hello World应用开始,逐步学习如何创建界面、处理用户输入、与后端服务交互等。 5. 深入学习Android开发:学习更高级的主题,如数据存储、网络通信、多线程编程、传感器使用等。 6. 掌握Android界面设计:学习使用XML和布局文件创建界面,了解常用的UI组件和样式。 7. 学习Android性能优化:掌握一些优化技巧,如减少内存使用、优化网络请求、提高电池寿命等。 8. 发布和测试应用:学习如何将应用打包、签名并发布到Google Play商店,以及如何进行测试和调试。 以上步骤只是一个简单的指南,Android开发是一个广阔的领域,需要不断实践和学习才能掌握。建议参考官方文档、教程和开发者社区资源,以及进行实际项目开发来提升技能。祝你在Android开发的道路上取得成功!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值