波形自定义控件(五):原理解析之性能优化

上一篇讲解了自定义控件的绘制及动画效果的实现原理,不过示例代码还有很多很多需要改进的地方,本篇来讲解几个优化的技巧。

优化1:减少在onDraw方法上的计算和对象创建

在上一篇文章我们知道,控件要多次调用onDraw方法才能实现动画效果。如果在onDraw方法上做过于耗时的事情,就会导致动画看起来很卡顿,严重的话甚至导致ANR。

其次,由于频繁调用onDraw方法,如果在上面创建对象,会产生大量临时的对象,进而导致GC频繁。

回顾一下上一篇写的onDraw方法。

@Override
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	int width = getWidth();
	int height = getHeight();  
	//1
	Paint paint = new Paint();
	paint.setColor(Color.RED);
    int left = (width - 50) / 2;
    int top = (height - 50) / 2;
    int right = left + 50;
    int bottom = top + 50;
	canvas.drawRect(left,top,right,bottom,paint);
}

代码1的Paint的实例对象实在太“短命”了,创建出来才画了一个正方形,就要等待被回收了。我们可以改进一下代码,减少“短命”实例对象的出现。

//1
private Paint mPaint = new Paint();

@Override
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	int width = getWidth();
	int height = getHeight();  
	//2
	mPaint.setColor(Color.RED);
    int left = (width - 50) / 2;
    int top = (height - 50) / 2;
    int right = left + 50;
    int bottom = top + 50;
    //3
	canvas.drawRect(left,top,right,bottom,mPaint);
}

把Paint变成一个私有成员变量,复用mPaint就可以了。

优化2:避免Handler导致内存泄漏

上篇文章讲了如何通过Handler来实现动画效果,效果是可以实现,但是那么写是有内存泄漏风险的,回顾一下上篇文章的代码。

private Hnadler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
        	mCount++;
        	if(mCount <= 4){
        		invalidate();
            	sendEmptyMessageDelayed(0,250);
            }
        }    
}

这是一个匿名内部类,匿名内部类会持有外部类的对象实例,简单地说就是外部的类的对象实例和内部类的实例绑定在一起。那么问题就来了。如果sendEmptyMessageDelayed方法的延时时间特别长(比如5分钟),Activity被销毁的时候,由于控件和handler是绑定在一起的,handler迟迟不能被回收,控件也就没法被回收了,这时就导致内存泄漏了。

那该怎么办呢?首先先想想Handler为什么迟迟不能被回收,因为还有一个5分钟后才能发送的消息,取消发送。(Handler里的MessageQueue和Message是强引用的关系,不了解Handler内部原理的朋友可以看看我写的这篇文章

其次将Handler写成静态内部类的形式,静态内部类持有对外部类对象实例。这里就以WaveLoadingView的Handler为例吧。

private AnimHandler mAnimHandler = new AnimHandler(this);

private static final class AnimHandler extends Handler{
        private SoftReference<WaveLoadingView> mView;

        public AnimHandler(WaveLoadingView view){
            mView = new SoftReference<>(view);
        }

        @Override
        public void handleMessage(Message msg) {
            WaveLoadingView view = mView.get();
            if(view != null){
                view.refreshFrame();
            }
        }

		//1
        public void recycle(){
            mView.clear();
        }
 }

WaveLoadingView把处理动画的Handler写成了静态内部类的形式,还提供了一个回收的方法。来看看recycle方法。

 protected void recycle(){
 		//1
        mAnimHandler.removeCallbacksAndMessages(null);
        mAnimHandler.recycle();
        //2
        mAnimHandler = null;
}

handler调用removeCallbacksAndMessages方法就可以移除所有Message了。然后重写控件的onDetachedFromWindow方法。

@Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        recycle();
}

onDetachedFromWindow方法会在Activity销毁时调用,在这个方法上我们可以做一些控件的回收释放操作。这么一来Handler内存泄漏的问题也就得到了解决。

最后

下一篇将讲解如何为控件添加自定义监听器。

参考文章

https://www.jianshu.com/p/e7b6fa788ae6

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值