Android高级进阶之12条代码优化以及性能优化方案

上面的selector会导致如下问题

selector中press的item属性永远不会被触发,为什么呢?因为在selector中从前往后匹配属性,第一个item和任何属性都会匹配,所以就算是执行了press的也是先匹配到上面的第一个item。 正确:

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

把没有任何条件选择的item放到最后,当前面的item都不匹配时就会选择最后的item。

4、context引起的内存泄漏

public static WifiManager getWIFIManager(Context ctx) {
WifiManager wm = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
}

上面的代码直接使用context来获取系统的WiFi服务,会导致下面问题

获取WiFi_SERVICE必需要用application 的context不能使用activity的context,如果上面方法中传入的是activity的context就会造成内存泄漏。 正确

public static WifiManager getWIFIManager(Context ctx) {
WifiManager wm = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}

这里为什么不用activity的context而要用application的context呢?因为activity的context生命周期和activity一致,当activity释放时context也应该被释放,这里由于context被wifiManager持有会导致activity不能被释放,而出现内存泄漏。application的context生命周期和application生命周期一致。所以当获取与当前activity生命周期无关而与整个应用生命周期有关的资源时,要使用application的context。

public Context getApplicationContext ()
/*Return the context of the single, global Application object of the current process. This generally should only be used if you need a Context whose lifecycle is separate from the current context, that is tied to the lifetime of the process rather than the current component.
*/

5、使用SparseArray代替HashMap

在Android中如果要存放的<key,value>中的key是基本数据类型:int,long,等基本数据类型时可以用SparseArray来代替HashMap,可以避免自动装箱和HashMap中的entry等带来的内存消耗。能被SparseArray代替的<key,value>类型有如下几种:

SparseArray <Integer, Object>
SparseBooleanArray <Integer, Boolean>
SparseIntArray <Integer, Integer>
SparseLongArray <Integer, Long>
LongSparseArray <Long, Object>
LongSparseLongArray <Long, Long> //this is not a public class

对比存放1000个元素的SparseIntArray和HashMap<Integer, Integer> 如下:

SparseIntArray

class SparseIntArray {
int[] keys;
int[] values;
int size;
}

Class = 12 + 3 * 4 = 24 bytes Array = 20 + 1000 * 4 = 4024 bytes Total = 8,072 bytes

HashMap

class HashMap<K, V> {
Entry<K, V>[] table;
Entry<K, V> forNull;
int size;
int modCount;
int threshold;
Set keys
Set<Entry<K, V>> entries;
Collection values;
}

Class = 12 + 8 * 4 = 48 bytes Entry = 32 + 16 + 16 = 64 bytes Array = 20 + 1000 * 64 = 64024 bytes Total = 64,136 bytes 可以看到存放相同的元素,HashMap占用的内存几乎是SparseIntArray的8倍。

SparseIntArray的缺点

SparseIntArray采用的二分查找法来查找个keys,因此查找某个元素的速度没有Hashmap的速度快。存储的元素越多时速度比hashmap的越慢,因此当当数据量不大时可以采用SparseIntArray,但是当数据量特别大时采用HashMap会有更高的查找速度。

6、自定义view中在layout、draw、onMeasue中new对象

问题代码

pubic class myview extends View
{

public myview(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int x=80;
int y=80;
int radius=40;
Paint paint=new Paint();
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor(“#CD5C5C”));
canvas.drawCircle(x,x, radius, paint);
}

}

自定义view的时候经常会重写onLayout ,onDraw ,onMeasue方法,但是要注意的是,如果在这些方法里面new 对象就会有如下问题

优化代码

public class myview extends View
{
int x;
int y;
int radius;
Paint paint;
public myview(Context context) {
super(context);
init();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor(“#CD5C5C”));
canvas.drawCircle(x,x, radius, paint);
}
private void init()
{
x=80;
y=80;
radius=40;
paint=new Paint();
}
}

看下Android官网上的解释为什么不能在onLayout ,onDraw ,onMeasue方法里面执行new 对象和执行初始化操作:

Creating objects ahead of time is an important optimization. Views are redrawn very frequently, and many drawing objects require expensive initialization. Creating drawing objects within your onDraw() method significantly reduces performance and can make your UI appear sluggish.

上面的意思总结一下就是在自定义view的时候最好提前初始化和new 对象,因为onDraw,onMeasure,onLayout的方法调用十分频繁,如果在这里初始化和new 对象会导致频繁的gc操作严重影响性能,也可能会导致掉帧现象。

ondraw的调用时机 1、view初始化的时候。 2、当view的invalidate() 方法被调用。什么时候会调用invalidate()方法呢?当view的状态需要改变的时候,比如botton被点击,editText相应输入等,就会reDraw调用onDraw方法。

7、静态变量引起的内存泄漏

问题代码

public class MyDlg extends Dialog {

private View mDialog;
private static MyDlg sInstance;
public MyDlg(Context context) {
super(context);
sInstance = this;
init();
}
private void init() {
mDialog = LayoutInflater.from(mCtx).inflate(R.layout.dialog_app_praise, null);
setContentView(mDialog);
}

上面的代码会导致如下问题:

上面代码中静态变量sInstance持有来context而这里的context是持有当前dialog的activity,由于静态变量一般只有在App销毁的时候才会进行销毁(此时类经历了,加载、连接、初始化、使用、和卸载)所以当activity执行完时由于被dialog中的静态变量持有无法被gc,所以造成内存泄漏。而这种dialog如果被多个地方调用就会造成严重的内存泄漏。

8、overdraw问题

问题代码

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





上面代码中linearlayout的background和ScrollView 里面的background一样只需要保留父布局LinearLayout里面的background就行了,不然会多进行一次绘制也就是引起overdraw问题。

9、inefficent layout weight

问题代码

<LinearLayout
android:layout_width=“match_parent”
android:layout_height=“48dp”
android:layout_gravity=“bottom”
android:background=“@color/white”
android:gravity=“center_vertical”
android:orientation=“horizontal”

<android.support.v7.widget.SwitchCompat
android:checked=“true”
android:id=“@+id/0checkbox”
android:layout_width=“wrap_content”
android:layout_height=“36dp”
android:layout_marginEnd=“15dp” />

上面布局中一个linearLayout里面包含一个textview和一个SwitchCompat,textview中的layout_weight=“1”,此时也明确给出了textview的layout_width=“165dp”,这个时候会带来下面的问题

当linearLayout的布局里面只有一个子view使用weight属性时如果LinearLayout是垂直布局这个子view应该设置layout_height=“0dp”,如果是水平布局这个子view应该layout_width=“0dp”,这样执行onMeasure的时候会首先不去measure 这个布局,可以提高性能。

10、字符串操作优化

String text=“bitch”;

最后:学习总结——Android框架体系架构知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。

下方即为我手绘的Android框架体系架构知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的Android框架体系架构知识脑图原件(包括上方的面试解析xmind文档)

除此之外,前文所提及的Alibaba珍藏版 Android框架体系架构 手写文档以及一本 《大话数据结构》 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!

——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
(包括上方的面试解析xmind文档)
[外链图片转存中…(img-0nYgid67-1714651694249)]

除此之外,前文所提及的Alibaba珍藏版 Android框架体系架构 手写文档以及一本 《大话数据结构》 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!

——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值