2020-12-20

Jetpack Navigation 系列

navigation 导航返回操作系列问题源代码解读


前言

Navigation这个组件第一次使用到实际项目中,在项目中遇到问题, 下面问题的记录。以及涉及到的系统源代码

提示:以下是本篇文章正文内容,下面案例可供参考

一: 系统back按钮处理流程处理

Activity中的流程。

  • Activity–>KeyDown–>
  • if (keyCode == KeyEvent.KEYCODE_BACK)–> onBackPressed();
  • 下面代码说明返回按钮的处理顺序。 mActionBar->Fragment-> Activity自身
  • Activity自身的默认行为是关闭掉自己 (finish())
	public void onBackPressed() {
        if (mActionBar != null && mActionBar.collapseActionView()) {
            return;
        }
        FragmentManager fragmentManager = mFragments.getFragmentManager();
        if (!fragmentManager.isStateSaved() && 
            fragmentManager.popBackStackImmediate()) {
            return;
        }
        
        if (!isTaskRoot()) {
            // If the activity is not the root of the task, 
            // allow finish to proceed normally.
            finishAfterTransition();
            return;
        }
        try {
            // Inform activity task manager that 
            // the activity received a back press
            // while at the root of the task. 
            // This call allows ActivityTaskManager
            // to intercept or defer finishing.
            ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken,
                    new IRequestFinishCallback.Stub() {
                        public void requestFinish() {
                            mHandler.post(() -> finishAfterTransition());
                        }
                    });
        } catch (RemoteException e) {
            finishAfterTransition();
        }
    }

在ComponentActivity中处理流程。

  • androidx.activity.ComponentActivity.onBackPressed
  • AndroidX中重写了对BackPressed事件的处理方式。
  • 这里是我们今天的重点OnBackPressedDispatcher
  • 代码重点结论。
    后显示的页面,先处理返回事件。
    OnBackPressedCallback ,可以开启和关闭当前注册的事件回调处理器
    如果没有如何OnBackPressedCallback了,那么做Activity的callback
 //-------------------
 //类名 androidx.activity.ComponentActivity.java
 public void onBackPressed() {
        mOnBackPressedDispatcher.onBackPressed();
 }
 
 private final OnBackPressedDispatcher mOnBackPressedDispatcher =
            new OnBackPressedDispatcher(new Runnable() {
                @Override
                public void run() {
                    ComponentActivity.super.onBackPressed();
                }
            });
            
public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
	return mOnBackPressedDispatcher;
}
  
//OnBackPressedDispatcher.java  
@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();
    }
}

```java
  @Nullable
  private final Runnable mFallbackOnBackPressed;
  @SuppressWarnings("WeakerAccess") /* synthetic access */
  final ArrayDeque<OnBackPressedCallback> mOnBackPressedCallbacks = new ArrayDeque<>();

NavHostFragment 系统返回按钮的处理流程。

> NavHostFragment->onCreate->NavHostController->setOnBackPressedDispatche
> NavHostFragment->onCreate->NavHostController->enableOnBackPressed
> 这里的enableOnBackPressed和R.styleable.NavHostFragment_defaultNavHost的是关联在一起的。 
> 如果defaultNavHost设置为false。那么默认是不会按下返回按键就关闭当前目标Fragment的。
 //androidx.navigation.fragmen.NavHostFragment
 public void onCreate(@Nullable Bundle savedInstanceState) {
 	mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher());
    mNavController.enableOnBackPressed(
	 mIsPrimaryBeforeOnCreate != null 
 	 && mIsPrimaryBeforeOnCreate);
	 mIsPrimaryBeforeOnCreate = null;
 }

public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs,
            @Nullable Bundle savedInstanceState) {
        super.onInflate(context, attrs, savedInstanceState);

        final TypedArray navHost = context.obtainStyledAttributes(attrs,
   	     androidx.navigation.R.styleable.NavHost);
        final int graphId = navHost.getResourceId(androidx.navigation.R.styleable.NavHost_navGraph, 0);
        if (graphId != 0) {
            mGraphId = graphId;
        }
        navHost.recycle();

        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);
        final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);
        if (defaultHost) {
            mDefaultNavHost = true;
        }
        a.recycle();
    }

 
//NavHostController
@Override
public final void setOnBackPressedDispatcher(@NonNull OnBackPressedDispatcher dispatcher) {
     super.setOnBackPressedDispatcher(dispatcher);
}

@Override
public final void enableOnBackPressed(boolean enabled) {
   super.enableOnBackPressed(enabled);
}

//NavController
//开启回调
private void updateOnBackPressedCallbackEnabled() {
    mOnBackPressedCallback.setEnabled(mEnableOnBackPressedCallback
    && getDestinationCountOnBackStack() > 1);
}

//注册mOnBackPressedCallback到ComponentActivity的mOnBackPressedDispatcher中。
void setOnBackPressedDispatcher(@NonNull OnBackPressedDispatcher dispatcher) {
    ...
    // Remove the callback from any previous dispatcher
    mOnBackPressedCallback.remove();
    // Then add it to the new dispatcher
    dispatcher.addCallback(mLifecycleOwner, mOnBackPressedCallback);
}

//默认返回按钮是,NavController中的mOnBackPressedCallback会执行出栈操作。
private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {
     @Override
      public void handleOnBackPressed() {
        popBackStack();
      }
};

二 OnBackPressedDispatcher

  • 系统实现的观察这设计模式。
  • 添加OnBackPressedCallback对象到ArrayDeque
  • 从ArrayDeque中删除OnBackPressedCallback
  • 通知队列中的观察者对象事件发生了。
  • 代码解析
    1. 状态判断,LifecycleOwner 是否已经DESTROYED,是则return
    2. addCancellable(LifecycleOnBackPressedCancellable)
    3. LifecycleOnBackPressedCancellable 对象创建。

//androidx.activity.OnBackPressedDispatcher
public void addCallback(@NonNull LifecycleOwner owner,
            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.add(onBackPressedCallback);
        OnBackPressedCancellable cancellable = 
        new OnBackPressedCancellable(onBackPressedCallback);
        onBackPressedCallback.addCancellable(cancellable);
        return cancellable;
}

 
//androidx.activity.ComponentActivity.java 
 @Override
 @MainThread
 public void onBackPressed() {
    mOnBackPressedDispatcher.onBackPressed();
 }
 
//androidx.activity.OnBackPressedDispatcher
@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();
        }
}

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

总结

看完了,先解决一下问题,下周继续更新。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值