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”;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值