Android 自定义控件 这样子写Handler正确吗?

在写自定义控件时,IDE提示这样子写可能会发生泄漏

image.png

提示可能发生泄漏的代码

private class CustomHandler extends Handler {
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {
            invalidate();
            if (animState == ANIM_NULL) {
                return;
            }
            if (animState == ANIM_CHECK) {
                animCurrentPage++;
            } else if (animState == ANIM_UNCHECK) {
                animCurrentPage--;
            }
            this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
            Log.e("CustomHandler", "animCurrentPage:" + animCurrentPage);
        } else {
            if (isCheck) {
                animCurrentPage = animMaxPage - 1;
            } else {
                animCurrentPage = -1;
            }
            invalidate();
            animState = ANIM_NULL;
        }
    }
}

通过搜索引擎搜索到结果后,修改后的代码

private static class CustomHandler extends Handler {
    private final WeakReference<CheckView> mCheckView;

    CustomHandler(CheckView checkView) {
        mCheckView = new WeakReference<>(checkView);
    }

    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        CheckView checkView = mCheckView.get();
        if (checkView != null) {
            int animCurrentPage = checkView.animCurrentPage;
            int animMaxPage = checkView.animMaxPage;
            int animState = checkView.animState;
            if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {
                checkView.invalidate();
                if (animState == ANIM_NULL) {
                    return;
                }
                if (animState == ANIM_CHECK) {
                    checkView.animCurrentPage++;
                } else if (animState == ANIM_UNCHECK) {
                    checkView.animCurrentPage--;
                }
                this.sendEmptyMessageDelayed(0, checkView.animDuration / animMaxPage);
                Log.e("CustomHandler", "animCurrentPage:" + animCurrentPage);
            } else {
                if (checkView.isCheck) {
                    checkView.animCurrentPage = animMaxPage - 1;
                } else {
                    checkView.animCurrentPage = -1;
                }
                checkView.invalidate();
                checkView.animState = ANIM_NULL;
            }
        }
    }
}

请问一下,这样子修改后,是否就可以解决泄漏的问题呢?我通过LeakCanary检测后并没有发现什么,但是我不知道这样子写是否规范?

阅读 2.8k
1 个回答

可以这样写,但是建议在View被销毁的时候比如onDetachedFromWindow回调方法将发的delay的消息移除掉

你是想要写一个匿名内部类。因为非静态的内部类为在Java编译成字节码后也是一个独立的类,但是为了达到内部类访问外部类中的成员变量和方法的功能,字节码中会持有外部类的一个对象的引用,才可以在两个独立类里面互相访问。如果你发送延迟Message的时候,Message 的成员变量target会持有Handler的引用,而这个匿名内部类Handler的对象又持有View的对象的引用。所以造成了该View对象不能及时被回收掉

如果改成静态的匿名内部类,该类只能访问外部类的静态方法和静态变量,所以不会持有外部类的实例对象。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题