内存优化(三):Profile内存检测工具

private float westXStart = 250;

private float westYStart = 300;

private float westXEnd = 150;

private float westYEnd = 300;

String colorStr[] = new String[]{

“#ffff00”,

“#ff3300”,

“#ccff00”,

“#ff00cc”,

“#ccffff”,

“#cc99ff”,

“#99ff66”,

“#993300”

};

private ValueAnimator valueAnimator;

private int currentColor = 0;

public IOSStyleLoadingView(Context context, AttributeSet attrs) {

super(context, attrs);

this.mContext = context;

this.mStrokeWidth = UIUtils.dp2px(this.mContext, 5);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

Sample test1=new Sample(“测试1”);

Paint paint = new Paint();

paint.setAntiAlias(true);

paint.setStrokeWidth(this.mStrokeWidth);

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeCap(Paint.Cap.ROUND);

Path p0 = new Path();

paint.setColor(Color.parseColor(colorStr[0]));

p0.moveTo(northwestXStart, northwestYStart);

p0.lineTo(northwestXEnd, northwestYEnd);

canvas.drawPath(p0, paint);

Path p1 = new Path();

paint.setColor(Color.parseColor(colorStr[1]));

p1.moveTo(northXStart, northYStart);

p1.lineTo(northXEnd, northYEnd);

canvas.drawPath(p1, paint);

Path p2 = new Path();

paint.setColor(Color.parseColor(colorStr[2]));

p2.moveTo(notheastXStart, notheastYStart);

p2.lineTo(notheastXEnd, notheastYEnd);

canvas.drawPath(p2, paint);

Path p3 = new Path();

paint.setColor(Color.parseColor(colorStr[3]));

p3.moveTo(eastXStart, eastYStart);

p3.lineTo(eastXEnd, eastYEnd);

canvas.drawPath(p3, paint);

Path p4 = new Path();

paint.setColor(Color.parseColor(colorStr[4]));

p4.moveTo(southeastXStart, southeastYStart);

p4.lineTo(southeastXEnd, southeastYEnd);

canvas.drawPath(p4, paint);

Path p5 = new Path();

paint.setColor(Color.parseColor(colorStr[5]));

p5.moveTo(southXStart, southYStart);

p5.lineTo(southXEnd, southYEnd);

canvas.drawPath(p5, paint);

Path p6 = new Path();

paint.setColor(Color.parseColor(colorStr[6]));

p6.moveTo(southwestXStart, southwestYStart);

p6.lineTo(southwestXEnd, southwestYEnd);

canvas.drawPath(p6, paint);

Path p7 = new Path();

paint.setColor(Color.parseColor(colorStr[7]));

p7.moveTo(westXStart, westYStart);

p7.lineTo(westXEnd, westYEnd);

canvas.drawPath(p7, paint);

}

@Override

protected void onAttachedToWindow() {

super.onAttachedToWindow();

startAnimation();

}

public void startAnimation() {

valueAnimator = ValueAnimator.ofInt(7, 0);

valueAnimator.setDuration(400);

valueAnimator.setRepeatCount(ValueAnimator.INFINITE);

valueAnimator.setInterpolator(new LinearInterpolator());

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

if ((int) animation.getAnimatedValue() != currentColor){

String b[] = new String[colorStr.length];

for (int c = 0, size = colorStr.length - 1; c < size; c++) {

b[c + 1] = colorStr[c];

}

b[0] = colorStr[colorStr.length - 1];

colorStr = b;

invalidate();

currentColor = (int) animation.getAnimatedValue();

}

}

});

valueAnimator.start();

}

}

img

内存分配

这是一个看起来相对平滑的内存走势图,但是也能看出内存一直在增加,不知道为什么我的内存分配Allocations一直为0,希望看到的小伙伴留言解答一下。

上面的代码有三个问题:

1、不断创建String对象,如下代码

paint.setColor(Color.parseColor(color[0]));

点击进去看源码:

public static int parseColor(@Size(min=1) String colorString) {

if (colorString.charAt(0) == ‘#’) {

// Use a long to avoid rollovers on #ffXXXXXX

// 这里调用了String类的substring方法

long color = Long.parseLong(colorString.substring(1), 16);

if (colorString.length() == 7) {

// Set the alpha value

color |= 0x00000000ff000000;

} else if (colorString.length() != 9) {

throw new IllegalArgumentException(“Unknown color”);

}

return (int)color;

} else {

Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT));

if (color != null) {

return color;

}

}

throw new IllegalArgumentException(“Unknown color”);

}

原来这里调用了String类的substring方法,我们都知道String类是不可变类,每一个字符串对应一个String对象,每次调用substring方法截取字符串就要新建一个String对象来接收截取后的值,所以我们选中的String对象就来自这里。

代码修改如下:

int[] colorInt = new int[colorStr.length];

// 构造方法中初始化

for (int i = 0; i < colorStr.length; i++) {

colorInt[i] = Color.parseColor(colorStr[i]);

}

2、不能再onDraw中创建对象

Path mPath = new Path();

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 把Paint、Path的创建移出去

mPath.reset();

paint.setColor(colorInt[(currentColor++)%8]);

mPath.moveTo(northwestXStart, northwestYStart);

mPath.lineTo(northwestXEnd, northwestYEnd);

canvas.drawPath(mPath, paint);

}

3、属性动画的addUpdateListener监听中不断创建数组

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

if ((int) animation.getAnimatedValue() != currentColor){

// 记录每次回调的int值,去改变颜色的角标

currentColor = (int) animation.getAnimatedValue();

invalidate();

}

}

});

通过修改,内存非常稳定,没有了大量对象的创建。那我们来看一下是否有内存泄漏的问题呢?

使用Profiler工具dump一下,查看内存分配的具体信息,在使用MAT工具查看明细。

img

查看Activity是否有强引用

可以看到我们刚刚的自定义菊花Activity退出后一直存在强引用,造成内存泄漏。Activity的Context一直被自定义控件持有,再往上看IOSStyleLoadingViewIOSStyleLoadingView$1内部类持有。

img

引用关系

注意:

动画一直要记得停止

protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

if (valueAnimator != null){

valueAnimator.removeAllUpdateListeners();

valueAnimator.cancel();

}

}

总结:

软引用与弱引用区别?

/**

  • 软引用

*/

Object softObject = new Object();

SoftReference objectSoftReference = new SoftReference<>(softObject);

softObject = null;

System.gc();

System.out.println(“sort:”+objectSoftReference.get());

/**

  • 弱引用(结果为null,只要被GC扫到就会被回收)

*/

Object weakObject = new Object();

WeakReference objectWeakReference = new WeakReference<>(weakObject);

weakObject = null;

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

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

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

重要知识点

下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。

高级进阶篇——高级UI,自定义View(部分展示)

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

  • 面试题部分合集

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
外链图片转存中…(img-xuOflIaD-1712894039956)]

重要知识点

下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。

[外链图片转存中…(img-E65g6XQu-1712894039956)]

高级进阶篇——高级UI,自定义View(部分展示)

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

[外链图片转存中…(img-sK9jAU95-1712894039957)]

  • 面试题部分合集
    [外链图片转存中…(img-GFQNMj84-1712894039957)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-XVeITLXj-1712894039957)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值