当前位置: 首页 > 编程日记 > 正文

Android开发——布局性能优化的一些技巧(一)

0. 前言

上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布局的选择远不如减少布局层级、避免过分绘制、按需加载等效果明显。所以本篇将着重总结Android布局性能优化的各种技巧。本文原创,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52923827。

 

1.   <include/>

<include>标签可以在一个布局中引入另外一个布局,通常适合于界面布局复杂、不同界面有共用布局的APP中,比如顶部布局、侧边栏布局、底部Tab栏布局、ListViewitem布局等,将这些公共布局抽取出来再通过<include>标签引用,既可以使代码结构清晰,又可统一修改使用

比如先写一个公共的标题栏标题栏title_bar.xml(这里就不具体实现了),并在我们的主xml文件里调用<include>来使用这个公共布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><include layout="@layout/title_bar"/>
</RelativeLayout>

当然include也可以使用layout属性来设置布局文件的宽高和位置,但需要注意的是,必须要复写android:layout_widthandroid:layout_height属性才能使用其它属性(如:android:layout_grivityandroid:layout_align...android:id等),这样可以避免include引用中的子组件属性影响到include的布局效果。

比如下面这个例子给我们include进的组件设置高度和位置:

<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="10dp"><include layout="@layout/title_bar" /><includeandroid:layout_width="match_parent"android:layout_height="60dp"android:layout_alignParentBottom="true"layout="@layout/ title_bar"/></RelativeLayout>
</RelativeLayout>


2.   减少嵌套

这个问题我们在LinearLayout和RelativeLayout的性能对对比中已经解释过了,在不响应层级深度的情况下,使用Linearlayout而不是RelativeLayout。为开发者默认新建RelativeLayout是希望开发者能采用尽量少的View层级,因为很多效果是需要多层LinearLayout的嵌套,这必然不如一层的RelativeLayout性能更好。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客。


3.  <merge/>

<merge/>标签通过减少View树的层级来优化Android的布局。先来用个例子演示一下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="merge标签使用" />
</RelativeLayout>

运行后使用“DDMS -> DumpView Hierarchy for UI Automator”工具,截图如下:

 

最下面两层RelativeLayoutTextView就是布局中的内容,上面的FrameLayoutActivitysetContentView添加的顶层视图。下面我们将上述布局代码中的RelativeLayout修改为merge标签再查看层级结构如下:

 

1)从结果来看,FrameLayout下面直接就是TextView与之前的相比少了一层RelativeLayout但效果相同。这个例子中TextView不需要指定任何针对父视图的布局属性,只用于添加到父视图上并显示,这种情况就可以使用<merge/>标签优化。但是我们一般很少遇到这种情况。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客

2)更多的<merge/>标签使用情景是在LinearLayout里面嵌入一个布局(比如使用了include),而恰恰这个布局的根节点也是LinearLayout,这样就多了一层没有用的嵌套,增加了View深度,这个时候如果我们使用merge根标签就修饰被嵌入的布局的根标签就可以避免此问题。


4.   ViewStub

一个最最最可能使用到的场景就是请求网络加载列表,如果网络异常或者加载失败,我们可以显示一个用于提示用户的View,上面可以点击重新加载。当网络正常时,我们就没有理由显示这个提示View。但是如果我们通过代码逻辑这种方式实现动态更改这个View的可见性(GONE或者VISIBLE),在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化且耗费内存资源

为了解决这个性能问题,ViewStub应运而生,ViewStub是一个轻量级的View,看不见、不占布局位置、占用资源非常小。ViewStub被设置为可见或调用了ViewStub.inflate()的时候,ViewStub所指向的布局才会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局,ViewStub控件本身就不存在了(ViewStub对象会被置空),取而代之的是被inflateLayout,因此它也被称做惰性控件。为了确保文章的实时更新,实时修改可能出错的地方,请确保这篇是原文,而不是无脑转载来的“原创文”,原文链接为SEU_Calvin的博客

综上ViewStub的原理,就可以使用它来方便的在运行时,决定要不要显示某个布局。使用实例如下:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" >……<ViewStubandroid:layout_gravity="center"android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/hint_fail_view"android:inflatedId="@+id/hint_fail_view"android:layout="@layout/fail_view"/>
</merge>

android:layout="@layout/fail_view"指向页面加载失败的布局文件,里面包含一个idtvTextView

当出现网络异常时,我们在代码里这样使用ViewStub

private View hintFailView;
if (网络异常) {if (hintFailView == null) {ViewStub viewStub = (ViewStub)this.findViewById(R.id.hint_fail_view);hintFailView = viewStub.inflate(); //注意这里TextView textView = (TextView) hintFailView.findViewById(R.id.tv);textView.setText("网络异常");}hintFailView.setVisibility(View.VISIBLE);
}else{//网络正常if (hintFailView!= null) {hintFailView.setVisibility(View.GONE);}//业务逻辑
}


5.  避免OverDraw

一个简单的过度绘制例子是父控件和其上的子控件都设置了Background,那么人们是看不到被子控件所覆盖的那部分父控件背景的,这就造成了OverDraw,我们可以通过设置-开发者选项-显示GPU过度绘制来查看应用是否存在严重的OverDraw问题。



如果你发现应用中有些色块为红色,那么你可要去优化它了,你需要去根据颜色提示去找到你过度绘制的地方,需要注意的是在我们有自己的背景色的情况下,顶层View的背景色我们可以置空来优化。

setContentView(R.layout.activity_overdraw_01);
getWindow().setBackgroundDrawable(null);

除了去除不必要的背景色,还有一个防止OverDraw的方法,那就是使用画布的clipRect()方法来去除自定义View中不必要的重叠绘制
在看clipRect方法之前先看看如果将res目录下的图片文件转换为bitmap对象,这里总结了两种方法,大家可以参考使用:

InputStream is = this.getContext().getResources().openRawResource(R.drawable.icon);  
Bitmap mBitmap = BitmapFactory.decodeStream(is);  
//或者使用BitmapDrawable
Bitmap mBitmap = new BitmapDrawable(is).getBitmap();

clipRect方法可以截取画布中的一个矩形区域,在此区域外的将不再绘制显示。实例如下:

/*
*author SEU_Calvin in 2016/10
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = mBmp.getWidth();
int height = mBmp.getHeight();canvas.save();
mPaint.setColor(Color.CYAN);
//先在屏幕的0,0处绘制一个与我们Bitmap宽高相等的蓝色矩形
canvas.drawRect(0, 0, width, height, mPaint);
canvas.restore();canvas.save();
//裁剪画布,左上角为0,0  右下角为指定宽高的2倍和1.5倍
canvas.clipRect(0, 0, width*2, height*3/2);
//以width,height为左上角绘制我们的Bitmap,由于图片的下半部分在裁剪画布之外所以不显示
canvas.drawBitmap(mBmp, width, height, mPaint);
canvas.restore();
}

结果如下所示,工作过程已经在代码的注释里写的很清楚了。



6.  其他小技巧

为了控制篇幅,将一些看了让人感到惊艳的布局优化小技巧总结分享到了布局性能优化的一些技巧(二),希望可以帮助到你~


最后希望各位看官老爷们多点赞支持~


转载于:https://www.cnblogs.com/qitian1/p/6461464.html

相关文章:

1-RAC基础

1 安装 pod ‘ReactiveObjC’ RAC 其实大大减少了代码量 2 基本使用 // 0 RAC 中最为常见的类 信号类/*RACSignal&#xff1a;信号类1.通过RACSignal 创建1个信号&#xff08;默认&#xff1a;冷信号&#xff09;2.通过订阅者&#xff0c;订阅信号信号&#xff08;变成:热信号…

static用法总结

C的static有两种用法&#xff1a;面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数&#xff0c;不涉及类&#xff1b;后者主要说明static在类中的作用。 一、面向过程设计中的static1、静态全局变量2、静态局部变量3、静态函数二、面向对象的…

小程序 缩放_缩放流星应用程序的初体验

小程序 缩放by Elie Steinbock埃莉斯坦博克(Elie Steinbock) 缩放流星应用程序的初体验 (First Experiences Scaling a Meteor App) I recently went through the challenge and ordeal of having to scale my Meteor app. It’s a project that had already been running in …

SQL Server Lock Escalation - 锁升级

Articles Locking in Microsoft SQL Server (Part 12 – Lock Escalation) http://dba.stackexchange.com/questions/12864/what-is-lock-escalation 2008 R2 Lock Escalation (Database Engine)---Forward from Locking in Microsoft SQL Server (Part 12 – Lock Escalation)…

Jzzhu and Chocolate

CF#257 div2 C:http://codeforces.com/contest/450/problem/C 题意&#xff1a;n*m的方格&#xff0c;每次可以横着或者纵向的切一刀&#xff0c;问切k之后&#xff0c;最小的最大是多少。 题解&#xff1a;比赛的时候没有想到怎么处理&#xff0c;看了别人的题解&#xff0c;才…

2-RACommand

RACommand RACCommand 就是命令 // RACCommand 就是命令// 0 创建一个CMD 穿进去一个用于构建RACSignal的Block参数来初始化RACommandRACCommand *cmd [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {// 此处是cmd 执行的输入源NSLog(…

玻璃上的编码喜悦(+ 10史诗般的Epigrams)

by Den McHenry丹麦克亨利(Den McHenry) 玻璃上的编码喜悦( 10史诗般的Epigrams) (Perlis on Coding Joy ( 10 Epic Epigrams)) Alan J. Perlis was the first recipient of the Turing Award. He’s possibly most remembered today for his Epigrams on Programming, which …

【Android】Activity生命周期(亲测)

测试手机&#xff1a;Nexus 5 系统&#xff1a;4.4 一、测试 测试代码&#xff1a; 1 package com.example.androidalarm;2 3 import android.app.Activity;4 import android.content.Context;5 import android.content.res.Configuration;6 import android.os.Bundle;7 impo…

angularjs 学习笔记 简单基础

angularjs是谷歌公司的一个项目&#xff0c;弥补了hml在构建方面的不足&#xff0c;通过指令&#xff08;directive&#xff09;来扩展html标签&#xff0c;可以使开发者使用html来声明动态内容。 angularjs主要用来开发单页应用&#xff08;SPA&#xff09;为主的项目。 angul…

3-RACSignal 常用方法

RACSingal的常用方法 一 基本使用 1map // 0 创建信号提供者// RACSubject&#xff0c;既能发送信号&#xff0c;又能订阅信号// 多用于代理&#xff0c;相当于OC里的delegate或者回调blockRACSubject *subject [RACSubject subject];// 1 绑定信号RACSignal *bindSignal …

javascript迭代_探索JavaScript迭代

javascript迭代by Festus K. Yangani由Festus K.Yangani 探索JavaScript迭代 (Exploring JavaScript Iteration) Loops allow programs to perform repetitive tasks, such as iterating through an array, while adhering to the DRY principle (Don’t Repeat Yourself). Th…

4 RACMulticastConnection 连接类

# RACMulticastConnection信号被多次订阅如果一个信号多次被订阅&#xff0c;那么代码块代码会多次被执行。objective-c// 创建信号RACSignal *sg1 [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {NSLog("网络请求…

ie6下常见的bug 调整页面兼容性

ie6下常见的bug 我们布局页面&#xff0c;首先符合标准&#xff0c;如何写一个页面的标准性&#xff1f; 但是ie6等浏览器本身就比较特殊&#xff0c;bug比较多&#xff0c;兵法云&#xff0c;知己知彼百战百胜。我们需要了解ie6的一些常见bug&#xff0c;这样&#xff0c;更好…

Cacti安装详细步骤

Cacti安装详细步骤 前提LNMP或LAMP架构已搭建完成 一、cacti概述 1. cacti是用php语言实现的一个软件&#xff0c;它的主要功能是用snmp服务获取数据&#xff0c;然后用rrdtool储存和更新数据&#xff0c;当用户需要查看数据的时候用rrdtool生成图表呈现给用户。因此&#xff0…

为什么使用单页应用_为什么我讨厌您的单页应用

为什么使用单页应用by Stefan Tilkov斯蒂芬蒂尔科夫(Stefan Tilkov) 为什么我讨厌您的单页应用 (Why I hate your Single Page App) Okay, now that I have your attention, let me say that I don’t really hate your single page app. I just find it highly annoying, unl…

marquee实现文字移动效果;js+div实现文字无缝移动效果

1.marquee实现文字移动&#xff1a; <marquee width"220px;" scrollamount"5" onmouseover"this.stop()" onmouseout"this.start()" ><p style"letter-spacing:2px;width: 1px;">欢迎您登录拜博医疗口腔集团内部…

URAL 1203 Scientific Conference(贪心 || DP)

Scientific Conference 之前一直在刷计算几何&#xff0c;邀请赛连计算几何的毛都买见着&#xff0c;暑假这一段时间就做多校&#xff0c;补多校的题目&#xff0c;刷一下一直薄弱的DP。多校如果有计算几何一定要干掉-。- 题意&#xff1a;给你N个报告会的开始时间跟结束时间&a…

5- RAC 集合 RACTuple RACSequence

RAC 集合 RACTuple RACSequence // 0 RACTuple 就是一个数组/*RACTuple 就是一个数组*/RACTuple *tp1 [RACTuple tupleWithObjects:"5",5,1, nil];RACTuple *tp2 [RACTuple tupleWithObjectsFromArray:["11","22","33"]];NSLog(&quo…

测试开发人员与开发人员_如何升级为开发人员

测试开发人员与开发人员by Will Hughes威尔休斯(Will Hughes) 如何升级为开发人员 (How to Level up as a Developer) Being a productive developer is something you can learn through experience, books, or trial and error. But, one of the best ways to become a prod…

ORA-00959: tablespace 'PSAPTEMP' does not exist

错误 : ORA-00959: tablespace PSAPTEMP does not exist 解决办法: CREATE TEMPORARY TABLESPACE PSAPTEMP TEMPFILE E:/Oracle/ORC/sapdata3/temp_1/temp.data1 SIZE 500M REUSE AUTOEXTEND ON NEXT 100M MAXSIZE unlimited EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M;ALTER …

RAC rac_liftSelector

RAC rac_liftSelector 主要是用于线程的同步 - (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.// rac_liftSelector// 类似于dispatch_group 中的组// 多线程中的组 等所有的请求都完毕之后 去更新UIRAC…

随笔记一些莆田话

莆田话是闽南话和福州话混合的产物&#xff0c;当然也是古汉语保留至今的珍宝。很多莆田话的词语是有源可溯的。这里记录一些平常想到的又可能不为人知的词语。 莆田话——普通话解释 物件——东西 万代——很多 先生——老师&#xff08;先生白读时是老师的意思&#xff09;&a…

JavaScript库和API

by Adam Recvlohe通过亚当雷夫洛厄(Adam Recvlohe) API就像一盒巧克力 (APIs are like a box of chocolates) If you have written JavaScript for the DOM before, then you probably know how unwieldy it can get. I mean getElementById is seven syllables and 14 charac…

Hadoop 全分布模式 平台搭建

现将博客搬家至CSDN&#xff0c;博主改去CSDN玩玩~ 传送门&#xff1a;http://blog.csdn.net/sinat_28177969/article/details/54138163 Ps&#xff1a;主要答疑区在本帖最下方&#xff0c;疑点会标注出来。个人在配置过程中遇到的困难都会此列举。 实验介绍&#xff1a; 本次实…

iOS 使用fastlane自动化打包步骤

加粗样式### iOS 使用fastlane 自动打包步骤 &#xff01;参考 1 查看ruby版本信息 本机是否安装ruby ruby -v 2 安装xcode命令行工具 点击同意即可 xcode-select --install 3 安装fastlane 键入如下命令 sudo gem install fastlane -NV4 使用 1 打开终端 cd 进入到要打包的…

今天开始搞CentOS 7

今天开始搞CentOS 7,安装过程很顺利&#xff0c;界面相当友好。转载于:https://www.cnblogs.com/lixd/p/3868649.html

java ruby_Java,Ruby和Go,我的天哪!

java rubyFree Code Camp has focused 100% on full stack JavaScript since we started 17 months ago. We’ve taught JavaScript on the front end, JavaScript on the back end (thanks to the powerful Node.js framework) — and even JavaScript as a database querying…

http和https的区别 与 SSL/TLS协议运行机制的概述

http和https的区别 与 SSL/TLS协议运行机制的概述 参考1 1 http 是不使用的SSL/TSL的通信通道 窃听风险&#xff1a;第三方获取通信内容篡改风险&#xff1a;修改通信内容冒充风险&#xff1a;冒充他人身份参与通信 2 SSL/TSL 协议应运而生 客户端先向服务器端索要公钥&am…

Babel 相关资料

Babel online editorBabel Plugin Handbookbabeljs usage options转载于:https://www.cnblogs.com/skating/p/6125227.html

php中this,self,parent三个关键字

phpfunctionclass语言cthis,self,parent三个关键字从字面上比较好理解,分别是指这、自己、父亲。this是指向当前对象的指针(姑且用C里面的指针来看吧) self是指向当前类的指针 parent是指向父类的指针(我 们这里频繁使用指针来描述&#xff0c;是因为没有更好的语言来表达)根据…