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();
}
}
内存分配
这是一个看起来相对平滑的内存走势图,但是也能看出内存一直在增加,不知道为什么我的内存分配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工具查看明细。
查看Activity是否有强引用
可以看到我们刚刚的自定义菊花Activity退出后一直存在强引用,造成内存泄漏。Activity的Context一直被自定义控件持有,再往上看IOSStyleLoadingView
又IOSStyleLoadingView$1
内部类持有。
引用关系
注意:
动画一直要记得停止
总结
这次面试问的还是还是有难度的,要求当场写代码并且运行,也是很考察面试者写代码
因为Android知识体系比较庞大和复杂的,涉及到计算机知识领域的方方面面。在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
止
总结
这次面试问的还是还是有难度的,要求当场写代码并且运行,也是很考察面试者写代码
因为Android知识体系比较庞大和复杂的,涉及到计算机知识领域的方方面面。在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-yQKwBek2-1643891054624)]
里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…