Android优雅的添加监听器

日常开发过程中大部分情况都会添加各种监听、回调,诸如:addListener(xx)addCallback(xx)之类,当然会成对的伴随着removeListener(xx)removeCallback(xx)出现,万一一不小心只调用了add忘记了remove,因为引用得不到释放,很有可能会出现内存泄露的问题。那有没有比较优雅的解决方法,能自动的调用remove呢?

最近项目开发中遇到一段优雅的代码,代码如下:

onBackPressedDispatcher.addCallback(this, object: OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        //
    }
})

这段代码的作用是监听返回事件,跟重写onBackPressed类似。我发现OnBackPressedDispatcher类只有addCallback没有removeCallback或者removeXXX之类的方法。其实就是传入的第一个参数this起到了自动移除监听的作用。

public final class OnBackPressedDispatcher {
    ...
    public void addCallback(@NonNull LifecycleOwner owner,
            @NonNull OnBackPressedCallback onBackPressedCallback) {
        Lifecycle lifecycle = owner.getLifecycle();
        if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {
            return;
        }

        onBackPressedCallback.addCancellable(
                new LifecycleOnBackPressedCancellable(lifecycle, onBackPressedCallback));
        if (BuildCompat.isAtLeastT()) {
            updateBackInvokedCallbackState();
            onBackPressedCallback.setIsEnabledConsumer(mEnabledConsumer);
        }
    }
    ...
}

最主要就是Lifecycle起到了关键作用,上面代码在展开叙述前先看看LifecycleOwnerLifecycle

public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    public val lifecycle: Lifecycle
}

public abstract class Lifecycle {
    ...
    public abstract fun addObserver(observer: LifecycleObserver)

    public abstract fun removeObserver(observer: LifecycleObserver)

    public enum class Event {
        /**
         * Constant for onCreate event of the [LifecycleOwner].
         */
        ON_CREATE,
        /**
         * Constant for onStart event of the [LifecycleOwner].
         */
        ON_START,
        ...
    }
    ...
}

public fun interface LifecycleEventObserver : LifecycleObserver {
    /**
     * Called when a state transition event happens.
     *
     * @param source The source of the event
     * @param event The event
     */
    public fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event)
}

Lifecycle的作用是感知和响应ActivityFragment的生命周期变化,方便做资源管理、自动取消任务等操作。

就比如下面是ComponentActivity中的一段代码:

getLifecycle().addObserver(new LifecycleEventObserver() {
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            ...
        }
    }
});

ActivityFragment生命周期变化走到onCreate()onStop()onDestroy()等时,会触发调用
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.XXX);进而触发onStateChanged(xx)回调

知道这个原理后再回头看OnBackPressedDispatcheraddCallback()内部代码。

首先判断当前的生命周期状态,如果是DESTROYED就不用往下走了。这里要注意owner.getLifecycle()返回的是LifecycleRegistry,其中getLifecycle()activity/ComponentActivity类中重写了。

@Override
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}

接下来将LifecycleOnBackPressedCancellable添加到匿名内部类中,这里所说的匿名内部类以及后面反复强调的匿名内部类都是同一个意思,也就是最开始我们使用onBackPressedDispatcher.addCallback(xx, xx)传入的第二个参数。

匿名内部类实际上是个抽象类,简化代码如下:

public abstract class OnBackPressedCallback {
    ...
    private CopyOnWriteArrayList<Cancellable> mCancellables = new CopyOnWriteArrayList<>();

    public final void remove() {
        for (Cancellable cancellable: mCancellables) {
            cancellable.cancel();
        }
    }

    void addCancellable(@NonNull Cancellable cancellable) {
        mCancellables.add(cancellable);
    }

    void removeCancellable(@NonNull Cancellable cancellable) {
        mCancellables.remove(cancellable);
    }
    ...
}

看到这里我们要再次明确本次分析源码的目的——为了搞懂为什么能够自动的"removeCallback()“而不需要手动调用。所以接下来分析的重点主要是看下如何将LifecycleOnBackPressedCancellable从匿名内部类中移除掉。

LifecycleOnBackPressedCancellable代码如下:

private class LifecycleOnBackPressedCancellable implements LifecycleEventObserver,
            Cancellable {
        private final Lifecycle mLifecycle;
        private final OnBackPressedCallback mOnBackPressedCallback;

        @Nullable
        private Cancellable mCurrentCancellable;

        LifecycleOnBackPressedCancellable(@NonNull Lifecycle lifecycle,
                @NonNull OnBackPressedCallback onBackPressedCallback) {
            mLifecycle = lifecycle;
            mOnBackPressedCallback = onBackPressedCallback;
            lifecycle.addObserver(this);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_START) {
                mCurrentCancellable = addCancellableCallback(mOnBackPressedCallback);
            } else if (event == Lifecycle.Event.ON_STOP) {
                // Should always be non-null
                if (mCurrentCancellable != null) {
                    mCurrentCancellable.cancel();
                }
            } else if (event == Lifecycle.Event.ON_DESTROY) {
                cancel();
            }
        }

        @Override
        public void cancel() {
            mLifecycle.removeObserver(this);
            mOnBackPressedCallback.removeCancellable(this);
            if (mCurrentCancellable != null) {
                mCurrentCancellable.cancel();
                mCurrentCancellable = null;
            }
        }
    }

该类实现了LifecycleEventObserverCancellable接口,构造方法中调用了lifecycle.addObserver(this),这个也是实现自动removeCallback的关键所在。实现接口中的方法onStateChanged(xx, xx)cancel(),接下来判断了3个生命周期状态,分别是ON_STARTON_STOPON_DESTROY

(1)进入ON_START状态后,调用OnBackPressedDispatcher类的addCancellableCallback(mOnBackPressedCallback),其中参数还是匿名内部类。

OnBackPressedDispatcher简化代码如下:

public final class OnBackPressedDispatcher {

    final ArrayDeque<OnBackPressedCallback> mOnBackPressedCallbacks = new ArrayDeque<>();

    public void addCallback(@NonNull LifecycleOwner owner,
            @NonNull OnBackPressedCallback onBackPressedCallback) {
        Lifecycle lifecycle = owner.getLifecycle();
        if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {
            return;
        }

        onBackPressedCallback.addCancellable(
                new LifecycleOnBackPressedCancellable(lifecycle, onBackPressedCallback));
        ...
    }

    Cancellable addCancellableCallback(@NonNull OnBackPressedCallback onBackPressedCallback) {
        //将匿名内部类添加到队列mOnBackPressedCallbacks中,目的是为了在按下返回键时能够调用到这个回调
        mOnBackPressedCallbacks.add(onBackPressedCallback);
        //将onBackPressedCallback回调包装成一个Cancellable对象
        OnBackPressedCancellable cancellable = new OnBackPressedCancellable(onBackPressedCallback);
        //将包装的Cancellable对象添加到onBackPressedCallback中
        onBackPressedCallback.addCancellable(cancellable);
        ...
        //返回包装的Cancellable对象
        return cancellable;
    }
    ...
}

这里重点是把匿名内部类包装成一个OnBackPressedCancellable对象,并将这个包装的对象添加到匿名内部类中,然后将其返回出去。

OnBackPressedCancellable代码如下:

private class OnBackPressedCancellable implements Cancellable {
    private final OnBackPressedCallback mOnBackPressedCallback;
    OnBackPressedCancellable(OnBackPressedCallback onBackPressedCallback) {
        mOnBackPressedCallback = onBackPressedCallback;
    }

    
    @Override
    public void cancel() {
        mOnBackPressedCallbacks.remove(mOnBackPressedCallback);
        mOnBackPressedCallback.removeCancellable(this);
        ...
    }
}

看到这里确实有点抓狂,我中有你,你中有我。别急,下面慢慢看。

返回的OnBackPressedCancellable对象赋值给LifecycleOnBackPressedCancellable类中的mCurrentCancellable属性。

看到这里相信有些人脑袋都有点晕了,几个类搞来搞去。别急,为了建立宏观的认识,看下下面的类图:

实际上搞来搞去也就3个类,2个接口。

此时匿名内部类OnBackPressedCallback中的mCancellables属性已经持有了两个对象,一个是LifecycleOnBackPressedCancellable对象,一个是OnBackPressedCancellable对象。

进入ON_STOP状态后,执行mCurrentCancellable.cancel(),进而触发调用OnBackPressedCancellable中的cancel()

private class OnBackPressedCancellable implements Cancellable {
    ...
    @Override
    public void cancel() {
        mOnBackPressedCallbacks.remove(mOnBackPressedCallback);
        mOnBackPressedCallback.removeCancellable(this);
        ...
    }
}

首先将匿名内部类从mOnBackPressedCallbacks中移除,这样就接收不到回调了。然后将当前OnBackPressedCancellable对象从匿名内部类中移除。

此时匿名内部类OnBackPressedCallback中的mCancellables属性就只有一个是LifecycleOnBackPressedCancellable对象了,并且生命周期监听也都还在。

进入ON_STOP状态后对于程序来说是不需要接收返回事件的,到目前为止也确实达到了这个目的。而当生命周期再次进入到ON_START状态后,又重新调用addCancellableCallback(mOnBackPressedCallback)

其实把匿名内部类包装了一层OnBackPressedCancellable的目的就是为了方便调用cancel()方法而已,也仅此而已。

进入ON_DESTROY状态后,执行LifecycleOnBackPressedCancellable中的cancel()方法:

private class LifecycleOnBackPressedCancellable {
    ...
    @Override
    public void cancel() {
        mLifecycle.removeObserver(this);
        mOnBackPressedCallback.removeCancellable(this);
        if (mCurrentCancellable != null) {
            mCurrentCancellable.cancel();
            mCurrentCancellable = null;
        }
    }
}

因为页面此时已经销毁了,所以生命周期监听不需要了,另外刚开始向匿名内部类中添加的LifecycleOnBackPressedCancellable对象也不需要了,最后调用OnBackPressedCancellable中的cancel()方法移除匿名内部类监听器mOnBackPressedCallback以及把匿名内部类中的OnBackPressedCancellable也移除掉。这样各队列中持有的对象都全部移除,这样也就达到了自动remove的目的了。

至此,整个分析过程就到此结束了,给我们的启发是我们完全可以仿照此种写法来设计自己项目中的监听器,无非就是引入Lifecycle的监听,以及针对ON_STARTON_STOPON_DESTROY这3种状态进行相应的监听器的添加和移除操作。

希望本文对大家有用,原创不易,转载请注明出处:https://www.longdw.com