拦截后退键
先分析非compose组件,再分析compose组件,其实原理是一样的
以前非compose的情况
首先Activity基类里对back键的拦截,代码如下
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.ECLAIR) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
return true;
}
}
return false;
}
然后ComponentActivity里复写了onBackPressed()方法
@MainThread
public void onBackPressed() {
mOnBackPressedDispatcher.onBackPressed();
}
@NonNull
@Override
public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
return mOnBackPressedDispatcher;
}
private final OnBackPressedDispatcher mOnBackPressedDispatcher =
new OnBackPressedDispatcher(new Runnable() {
@Override
public void run() {
// Calling onBackPressed() on an Activity with its state saved can cause an
// error on devices on API levels before 26. We catch that specific error and
// throw all others.
try {
//这个就是回退fragment或者关闭activity
ComponentActivity.super.onBackPressed();
} catch (IllegalStateException e) {
if (!TextUtils.equals(e.getMessage(),
"Can not perform this action after onSaveInstanceState")) {
throw e;
}
}
}
});
可以看到它调用了OnBackPressedDispatcher的onBackpressed方法,下边贴出对应的方法
//构造方法,就是上边传的那个runnalbe,
public OnBackPressedDispatcher(@Nullable Runnable fallbackOnBackPressed) {
mFallbackOnBackPressed = fallbackOnBackPressed;
}
//添加拦截回调
public void addCallback(@NonNull OnBackPressedCallback onBackPressedCallback) {
addCancellableCallback(onBackPressedCallback);
}
//循环处理通过addCallback添加的回调,如果callbac是enable状态那么就交给它处理,完事直接return,也就是回调第一个处理,其他的就无视了。
public void onBackPressed() {
Iterator<OnBackPressedCallback> iterator =
mOnBackPressedCallbacks.descendingIterator();
while (iterator.hasNext()) {
OnBackPressedCallback callback = iterator.next();
if (callback.isEnabled()) {
callback.handleOnBackPressed();
return;
}
}
//默认的情况用户没有添加回调,那么走这里,这个就是构造方法里的那个runnable,系统自己处理
if (mFallbackOnBackPressed != null) {
mFallbackOnBackPressed.run();
}
}
上边的代码简单明了,所以我们要拦截后退键自己处理,非常简单
可以动态修改callback的enable状态,想自己处理设置为ture,不想自己处理就设置false
OnBackPressedCallback callback=new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
//finish();
}
};
getOnBackPressedDispatcher().addCallback(callback);
Fragment里拦截也一样,就是多个requireActivity()
requireActivity().onBackPressedDispatcher.addCallback(callback);
compose情况
如下组件就可以实现了,和普通的activity原理是一样的,就是enable参数和onBack回调方法分开了。
@Composable
public fun BackHandler(enabled: Boolean = true, onBack: () -> Unit) {
// Safely update the current `onBack` lambda when a new one is provided
val currentOnBack by rememberUpdatedState(onBack)
// Remember in Composition a back callback that calls the `onBack` lambda
val backCallback = remember {
//这里又组合成了普通activity里的那个OnBackPressedCallback抽象类
object : OnBackPressedCallback(enabled) {
override fun handleOnBackPressed() {
currentOnBack()
}
}
}
// On every successful composition, update the callback with the `enabled` value
SideEffect {
backCallback.isEnabled = enabled
}
val backDispatcher = checkNotNull(LocalOnBackPressedDispatcherOwner.current) {
"No OnBackPressedDispatcherOwner was provided via LocalOnBackPressedDispatcherOwner"
}.onBackPressedDispatcher
//onBackPressedDispatcher就是activity里那个
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner, backDispatcher) {
// Add callback to the backDispatcher
backDispatcher.addCallback(lifecycleOwner, backCallback)
// When the effect leaves the Composition, remove the callback
onDispose {
backCallback.remove()
}
}
}
看下LocalOnBackPressedDispatcherOwner.current的获取
public object LocalOnBackPressedDispatcherOwner {
private val LocalOnBackPressedDispatcherOwner =
compositionLocalOf<OnBackPressedDispatcherOwner?> { null }
public val current: OnBackPressedDispatcherOwner?
@Composable
get() = LocalOnBackPressedDispatcherOwner.current
?: findOwner<OnBackPressedDispatcherOwner>(LocalContext.current)
可以看到其实最终获取的就是ComponentActivity
internal inline fun <reified T> findOwner(context: Context): T? {
var innerContext = context
while (innerContext is ContextWrapper) {
if (innerContext is T) {
return innerContext
}
innerContext = innerContext.baseContext
}
return null
}
上边忘了贴了ComponentActivity实现了OnBackPressedDispatcherOwner
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
OnBackPressedDispatcherOwner,