美文网首页
Fragment 监听返回按键

Fragment 监听返回按键

作者: wzmyyj | 来源:发表于2020-05-10 11:49 被阅读0次

    在日常开发中,我们用fragment承担页面UI主要的逻辑,简化activity逻辑。有个场景,fragment需要监听返回键。但fragment不像activity能感知物理按键。

    过去

    我们会写一个监听接口,让fragment实现。然后activity遍历(或根据tag)找到需要的fragment,在按返回键时,主动将事件下发给fragment。

    虽然实现了fragment监听返回键的效果,但是代码需要侵入到activity,并不利于维护。google官方也考虑到了这个问题。

    现在

    在新版的AndroidX中:ComponentActivity中增加了OnBackPressedDispatcher(用于注册返回键监听)。

    activity继承关系如下:

    WechatIMG9.jpeg

    新的fragment监听方案:

    关键类:OnBackPressedCallback,OnBackPressedDispatcher,ComponentActivity。

    // 定义返回键监听事件。
    val callback = object : OnBackPressedCallback(false) {
    
            override fun handleOnBackPressed() {
                //do some thing
            }
        }
    
    // 注册监听事件。activity为ComponentActivity的子类对象即可。并绑定生命周期。
    activity.onBackPressedDispatcher.addCallback(lifecycleOwner, callback)
    // 也可以不绑定生命周期。
    activity.onBackPressedDispatcher.addCallback(callback)
    

    OnBackPressedCallback可以设置enabled,可以灵活控制要不要消费返回键点击事件。

    优势

    所有代码都在fragment里。不需要要求activity写多余的逻辑。只要能拿到activity对象和所在的lifecycleOwner即可完成监听任务。甚至是在自定义view中。

    深入源码

    OnBackPressedCallback:用于处理OnBackPressedDispatcher.onBackPressed()回调而无需将该实现与的子类强耦合的类ComponentActivity。源码比较简单

    public abstract class OnBackPressedCallback {
        private boolean mEnabled;
        private CopyOnWriteArrayList<Cancellable> mCancellables = new CopyOnWriteArrayList<>();
        /**
         * Create a {@link OnBackPressedCallback}.
         *
         * @param enabled The default enabled state for this callback.
         * @see #setEnabled(boolean)
         */
        public OnBackPressedCallback(boolean enabled) {
            mEnabled = enabled;
        }
        /**
         * Set the enabled state of the callback. Only when this callback
         * is enabled will it receive callbacks to {@link #handleOnBackPressed()}.
         * <p>
         * Note that the enabled state is an additional layer on top of the
         * {@link androidx.lifecycle.LifecycleOwner} passed to
         * {@link OnBackPressedDispatcher#addCallback(LifecycleOwner, OnBackPressedCallback)}
         * which controls when the callback is added and removed to the dispatcher.
         *
         * @param enabled whether the callback should be considered enabled
         */
        @MainThread
        public final void setEnabled(boolean enabled) {
            mEnabled = enabled;
        }
        /**
         * Checks whether this callback should be considered enabled. Only when this callback
         * is enabled will it receive callbacks to {@link #handleOnBackPressed()}.
         *
         * @return Whether this callback should be considered enabled.
         */
        @MainThread
        public final boolean isEnabled() {
            return mEnabled;
        }
        /**
         * Removes this callback from any {@link OnBackPressedDispatcher} it is currently
         * added to.
         */
        @MainThread
        public final void remove() {
            for (Cancellable cancellable: mCancellables) {
                cancellable.cancel();
            }
        }
        /**
         * Callback for handling the {@link OnBackPressedDispatcher#onBackPressed()} event.
         */
        @MainThread
        public abstract void handleOnBackPressed();
        void addCancellable(@NonNull Cancellable cancellable) {
            mCancellables.add(cancellable);
        }
        void removeCancellable(@NonNull Cancellable cancellable) {
            mCancellables.remove(cancellable);
        }
    }
    

    OnBackPressedDispatcher:存放监听的容器,通过它统一执行。

    储存结构:

    // 利用一个队列存储回调。    
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    final ArrayDeque<OnBackPressedCallback> mOnBackPressedCallbacks = new ArrayDeque<>();
    

    是否有有效回调:

    @MainThread
        public boolean hasEnabledCallbacks() {
            Iterator<OnBackPressedCallback> iterator =
                    mOnBackPressedCallbacks.descendingIterator();
            while (iterator.hasNext()) {
                if (iterator.next().isEnabled()) {
                    return true;
                }
            }
            return false;
        }
    

    执行顺序:

    // 按先注册顺序遍历,只执行enabled为true的回调。
    @MainThread
        public void onBackPressed() {
            Iterator<OnBackPressedCallback> iterator =
                    mOnBackPressedCallbacks.descendingIterator();
            while (iterator.hasNext()) {
                OnBackPressedCallback callback = iterator.next();
                if (callback.isEnabled()) {
                    callback.handleOnBackPressed();
                    return;
                }
            }
            if (mFallbackOnBackPressed != null) {
                mFallbackOnBackPressed.run();
            }
        }
    

    绑定生命周期原理:

    @MainThread
        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));
        }
    

    LifecycleOnBackPressedCancellable 监听生命周期变化,决定是否cancel掉监听。

    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;
                }
            }
        }
    

    ComponentActivity:

    关键代码:

    // 父类的 onBackPressed 事件委托给 OnBackPressedDispatcher 。
    private final OnBackPressedDispatcher mOnBackPressedDispatcher =
                new OnBackPressedDispatcher(new Runnable() {
                    @Override
                    public void run() {
                        ComponentActivity.super.onBackPressed();
                    }
                });
    // 自己的 onBackPressed 全交给 OnBackPressedDispatcher 处理。
    @Override
        @MainThread
        public void onBackPressed() {
            mOnBackPressedDispatcher.onBackPressed();
        }
    

    总结

    利用注册监听的方式,可以很好的结偶代码,可以activity的功能分发到各个能够访问activity对象的组件上。

    配个图

    相关文章

      网友评论

          本文标题:Fragment 监听返回按键

          本文链接:https://www.haomeiwen.com/subject/frodnhtx.html