Jetpact-activity组件完全解析

Jetpact-activity组件完全解析

前言

Jetpack-activity/fragment 是jetpack架构组件中最基础的部分。

底层对jetpack-lifecycle组件做了支持、为开发者能够直接使用jetpack架构组件提供了支持,因此要想彻底了解jetpack系列,先学习activity/fragment组件很有必要。

注意:
本文中源代码均使用 1.1.0稳定版本

引用

def activity_version = "1.1.0"
// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

继承结构:

在这里插入图片描述

源码解析

/**
 * Base class for activities that enables composition of higher level components.
 * <p>
 * Rather than all functionality being built directly into this class, only the minimal set of
 * lower level building blocks are included. Higher level components can then be used as needed
 * without enforcing a deep Activity class hierarchy or strong coupling between components.
 */
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
    
    
        //....
}        

ComponentActivity 类的注释上可以得出两条信息:

  1. ComponentActivity 是一个支持组合高级组件的基类Activity
  2. 并没有将所有的组件都构建到这个类中,只是包含最基础的底层组件。开发者可以根据需要使用更高级别的组件,无需在组件之间强耦合。

构造器

ComponentActivity在构造器中针对Android不同版本进行了简单兼容处理


public ComponentActivity() {
    
    
    Lifecycle lifecycle = getLifecycle();
    //noinspection ConstantConditions
    //如果在使用 Lifecycle 对象的时候还没有初始化则直接抛错,对于重写 getLifecycle() 方法需要注意
    if (lifecycle == null) {
    
    
        throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                + "constructor. Please make sure you are lazily constructing your Lifecycle "
                + "in the first call to getLifecycle() rather than relying on field "
                + "initialization.");
    }
    //针对API 19以上兼容
    if (Build.VERSION.SDK_INT >= 19) {
    
    
        getLifecycle().addObserver(new LifecycleEventObserver() {
    
    
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
    
    
                if (event == Lifecycle.Event.ON_STOP) {
    
    
                    Window window = getWindow();
                    final View decor = window != null ? window.peekDecorView() : null;
                    if (decor != null) {
    
    
                        decor.cancelPendingInputEvents();
                    }
                }
            }
        });
    }
    //Activity销毁时清除ViewMode中数据
    getLifecycle().addObserver(new LifecycleEventObserver() {
    
    
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
    
    
            if (event == Lifecycle.Event.ON_DESTROY) {
    
    
                if (!isChangingConfigurations()) {
    
    
                    getViewModelStore().clear();
                }
            }
        }
    });
    //针对 19~23 版本 解决 InputMethodManager中 mNextServedView 内存泄漏问题
    if (19 <= SDK_INT && SDK_INT <= 23) {
    
    
        getLifecycle().addObserver(new ImmLeaksCleaner(this));
    }
}

从构造器中代码来看做的事情比较多,但都是兼容性处理,有三个方面的处理:

  • 针对API19以上兼容Activity停止时取消View还未执行的事件
  • 针对API19以上Activity销毁时清除ViewMode中数据
  • 针对API19~23版本Activity销毁时解决InputMethodManager中 mNextServedView持有Activity导致内存泄漏问题

Activity停止时取消View还未执行的事件

Activity 处于stop 时用户是看不到界面的,也没有必要再处理 View的点击、长按、动画等事件。所以有必要将这些事件移除掉。

我们跟随源码看一下具体是怎么做的:

View层处理

上述代码会调用ViewcancelPendingInputEvents() 这是个取消事件的总调度方法,它没有具体做事情,而是调用了 dispatchCancelPendingInputEvents() 来完成工作

public final void cancelPendingInputEvents() {
    
    
    dispatchCancelPendingInputEvents();
}
void dispatchCancelPendingInputEvents() {
    
    
    //位操作设置标志位
    mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER;
    //执行清除事件工作
    onCancelPendingInputEvents();
    //检查标志位是否正确 以确保完成了清除工作
    if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) {
    
    
        throw new SuperNotCalledException("View " + getClass().getSimpleName() +
                " did not call through to super.onCancelPendingInputEvents()");
    }
}

dispatchCancelPendingInputEvents() 方法中调用了 onCancelPendingInputEvents() 来完成具体的清除工作:

onCancelPendingInputEvents() 会清除已发送到消息队列的事件,延迟事件等 如果是自定义View 是可以重写此方法,来自定义指定那些事件是需要清除或保留的,但是需要注意要 super.onCancelPendingInputEvents() 要调用父类方法 完成 mPrivateFlags3变量的位操作

public void onCancelPendingInputEvents() {
    
    
    //移除点击事件回调
    removePerformClickCallback();
    //取消等待的长按事件
    cancelLongPress();
    //对标识变量进行操作 在 dispatchCancelPendingInputEvents()对此变量有检查操作
    mPrivateFlags3 |= PFLAG3_CALLED_SUPER;
}
移除点击事件回调

removePerformClickCallback() 中直接调用 removeCallbacksmPerformClick点击事件传入

 @UnsupportedAppUsage
 private void removePerformClickCallback() {
    
    
     if (mPerformClick != null) {
    
    
         removeCallbacks(mPerformClick);
     }
 }

removeCallbacks(Runnable action)才是真正移除事件处理的方法,凡是以下几种方式添加的事件或延迟事件都会移除

  1. post()
  2. postDelayed()
  3. postOnAnimation()
  4. postOnAnimationDelayed()
public boolean removeCallbacks(Runnable action) {
    
    
    if (action != null) {
    
    
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
    
    
            //移除指定回调
            attachInfo.mHandler.removeCallbacks(action);
            //移除Choreographer中动画回调
            attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
                    Choreographer.CALLBACK_ANIMATION, action, null);
        }
        //移除等待队列中事件
        getRunQueue().removeCallbacks(action);
    }
    return true;
}
移除长按事件

cancelLongPress()中会分别调用 removeLongPressCallback() 清除长按回调 和 removeTapCallback()移除长按产生的超时事件

removeLongPressCallback()removeTapCallback() 都会调用 removeCallbacks(Runnable action) 来移除指定的事件,前面我们已经分析过了,就不再赘述了。

public void cancelLongPress() {
    
    
    //移除长按回调事件
    removeLongPressCallback();
    //移除长按超时回调事件
    removeTapCallback();
}
//移除长按回调
private void removeLongPressCallback() {
    
    
    if (mPendingCheckForLongPress != null) {
    
    
        removeCallbacks(mPendingCheckForLongPress);
    }
}
//移除长按超时事件、修改标志位
private void removeTapCallback() {
    
    
    if (mPendingCheckForTap != null) {
    
    
        mPrivateFlags &= ~PFLAG_PREPRESSED;
        removeCallbacks(mPendingCheckForTap);
    }
}

Activity销毁时清除ViewMode中数据

Activity销毁时清除ViewMode中数据,需要依赖另一个组件-Lifecycle支持。不仅是 ViewModel 在Jetpack 架构组件中很多组件都需要依赖 Lifecycle组件。

我们重新看一下以下代码

//Activity销毁时清除ViewMode中数据
getLifecycle().addObserver(new LifecycleEventObserver() {
    
    
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
    
    
        if (event == Lifecycle.Event.ON_DESTROY) {
    
    
            if (!isChangingConfigurations()) {
    
    
                getViewModelStore().clear();
            }
        }
    }
});

我们看到 !isChangingConfigurations() 为 true ,也就是Activity配置没有修改情况下,在Activity销毁时会调用 getViewModelStore().clear()

这里我们先将ViewModel放一放,来看一下为什么在清除 ViewModel中数据还有一个前置条件?这个条件什么时候满足条件?

isChangingConfigurations() 相关

isChangingConfigurations()Activity类中方法,用来判断 Activity 的配置信息是否更改了,(比如 横竖屏切换、语言发生变化等)需要重新启动该Activity的时候 这个方法会返回 true 、没有更改和默认情况都是 false

/** true if the activity is being destroyed in order to recreate it with a new configuration */
/*package*/ boolean mChangingConfigurations = false;

public boolean isChangingConfigurations() {
    
    
    return mChangingConfigurations;
}

我们看到 mChangingConfigurations变量是包级访问权限,我们知道 Activity资源发生变化时会重新启动,在 framework层经过一系列调用,最终会调用 ActivityThreadhandleRelaunchActivity() 将 mChangingConfigurations 设置为 true

@Override
public void handleRelaunchActivity(ActivityClientRecord tmp,
                                   PendingTransactionActions pendingActions) {
    
    
    //.....
    int configChanges = 0;
    ActivityClientRecord r = mActivities.get(tmp.token);
    r.activity.mConfigChangeFlags |= configChanges;
    r.mPreserveWindow = tmp.mPreserveWindow;
    //将标识设置为修改
    r.activity.mChangingConfigurations = true;
    //重新启动Activity
    handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
            pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
    //.....
}                                                                                                  

所以这就是为什么ViewModel能够在Activity横竖屏切换,还能保存数据不丢失的原因。

getViewModelStore()

再回到 ComponentActivity 中我们看一下 getViewModelStore() 是如何实现的

@NonNull
@Override
public ViewModelStore getViewModelStore() {
    
    
    if (getApplication() == null) {
    
    
        throw new IllegalStateException("Your activity is not yet attached to the "
                + "Application instance. You can't request ViewModel before onCreate call.");
    }
    if (mViewModelStore == null) {
    
    
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        //从上一次保存的配置修改中恢复 ViewModelStore 实例       
        if (nc != null) {
    
    
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        //如果还是null new出一个ViewModelStore实例
        if (mViewModelStore == null) {
    
    
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

我们看到 mViewModelStore是个全局变量,在进行实例化时会先从 上一次保存的 NonConfigurationInstances 对象中恢复,如果为null 最终会重新 new 出来一个新的 ViewModelStore 实例并赋值给 mViewModelStore

NonConfigurationInstancesComponentActivity 中的静态内部类 定义如下

static final class NonConfigurationInstances {
    
    
    Object custom;
    ViewModelStore viewModelStore;
}

Activity 非正常销毁时会触发 onRetainNonConfigurationInstance() 来保存一些数据,上面 NonConfigurationInstances 类中 viewModelStore 实例就是这样保存的

@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
    
    
    //取出自定义数据
    Object custom = onRetainCustomNonConfigurationInstance();
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
    
    
        // No one called getViewModelStore(), so see if there was an existing
        // ViewModelStore from our last NonConfigurationInstance
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
    
    
            viewModelStore = nc.viewModelStore;
        }
    }
    if (viewModelStore == null && custom == null) {
    
    
        return null;
    }
    //创建NonConfigurationInstances对象保存 自定义数据和 viewModelStore 实例对象
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

我们看到 onRetainNonConfigurationInstance() 已被标记为 final,官方不建议我们自己再复写此方法,而 onRetainCustomNonConfigurationInstance() 和与之对应的 getLastCustomNonConfigurationInstance()也都被标记为废弃,可以看出官方还没有提供成熟方案。

@Deprecated
@Nullable
public Object onRetainCustomNonConfigurationInstance() {
    
    
    return null;
}

@Deprecated
@Nullable
public Object getLastCustomNonConfigurationInstance() {
    
    
    NonConfigurationInstances nc = (NonConfigurationInstances)
            getLastNonConfigurationInstance();
    return nc != null ? nc.custom : null;
}
ViewModelStore.clear()

重新回到 ViewModelStore类的 clear()这里,ViewModelStore类代码比较简单,我们着重看一下 clear(),其实就是遍历 HashMap,并调用ViewModel中的clear()

public class ViewModelStore {
    
    

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
    
    
        for (ViewModel vm : mMap.values()) {
    
    
            vm.clear();
        }
        mMap.clear();
    }
}

ViewModelclear()方法如下:

@MainThread
final void clear() {
    
    
    //设置标志位
    mCleared = true;
   
   //清除缓存的tag map集合
    if (mBagOfTags != null) {
    
    
        synchronized (mBagOfTags) {
    
    
            for (Object value : mBagOfTags.values()) {
    
    
                // see comment for the similar call in setTagIfAbsent
                closeWithRuntimeException(value);
            }
        }
    }
    //供子类使用清除子类数据
    onCleared();
}

我们看到 clear()一共干了三件事:

  1. 设置清除标志位
  2. 清除缓存在HashMap中的tag数据
  3. 调用onCleared() 子类可以重写此方法完成清除数据

解决InputMethodManager中 mNextServedView 持有Activity导致内存泄漏

在Android 4.4~6.0之间一直存在一个比较常见的系统bug,那就是 InputMethodManager类中 mNextServedViewactivity销毁后也会一直持有Activity引用从而导致内存泄漏,使用LeakCanary很容易检测出来

在这里插入图片描述

常见的解决方式是通过反射得到 InputMethodManagermNextServedViewActivity销毁后置为null,把引用链给断开 比如可以参考这篇文章传统解决方式、下面我们看一下 ComponentActivity 是怎么解决这个问题的

前面我们已经在构造器中看到如下代码:

if (19 <= SDK_INT && SDK_INT <= 23) {
    
    
    getLifecycle().addObserver(new ImmLeaksCleaner(this));
}

利用 Lifecyle添加一个观察者对象,创建了一个 ImmLeaksCleaner并将当前 Activity对象传入

@RequiresApi(19)
final class ImmLeaksCleaner implements LifecycleEventObserver {
    
    
    //变量初始化状态枚举值
    private static final int NOT_INITIALIAZED = 0;
    private static final int INIT_SUCCESS = 1;
    private static final int INIT_FAILED = 2;
    
    //初始化状态
    private static int sReflectedFieldsInitialized = NOT_INITIALIAZED;
    
    //反射对应的字段值
    private static Field sHField;
    private static Field sServedViewField;
    private static Field sNextServedViewField;

    private Activity mActivity;

    ImmLeaksCleaner(Activity activity) {
    
    
        mActivity = activity;
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    
    
        //activity生命周期走到 onDestory() 时才会往下执行
        if (event != Lifecycle.Event.ON_DESTROY) {
    
    
            return;
        }
        //发现没有初始化进行初始化反射出指定字段
        if (sReflectedFieldsInitialized == NOT_INITIALIAZED) {
    
    
            initializeReflectiveFields();
        }
        //反射成功
        if (sReflectedFieldsInitialized == INIT_SUCCESS) {
    
    
            //获取当前InputMethodManager对象
            InputMethodManager inputMethodManager = (InputMethodManager)
                    mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
            //拿到当前lock锁对象
            final Object lock;
            try {
    
    
                lock = sHField.get(inputMethodManager);
            } catch (IllegalAccessException e) {
    
    
                return;
            }
            if (lock == null) {
    
    
                return;
            }
            //进入同步锁
            synchronized (lock) {
    
    
                final View servedView;
                try {
    
    
                    servedView = (View) sServedViewField.get(inputMethodManager);
                } catch (IllegalAccessException e) {
    
    
                    return;
                } catch (ClassCastException e) {
    
    
                    return;
                }
                if (servedView == null) {
    
    
                    return;
                }
                if (servedView.isAttachedToWindow()) {
    
    
                    return;
                }
                //将mNextServedView对象设置为null
                try {
    
    
                    sNextServedViewField.set(inputMethodManager, null);
                } catch (IllegalAccessException e) {
    
    
                    return;
                }
            }
            inputMethodManager.isActive();
        }
    }

    @MainThread
    private static void initializeReflectiveFields() {
    
    
        try {
    
    
            //设置标识位标识开始反射
            sReflectedFieldsInitialized = INIT_FAILED;
            sServedViewField = InputMethodManager.class.getDeclaredField("mServedView");
            sServedViewField.setAccessible(true);
            sNextServedViewField = InputMethodManager.class.getDeclaredField("mNextServedView");
            sNextServedViewField.setAccessible(true);
            //对应是Handler实现类
            sHField = InputMethodManager.class.getDeclaredField("mH");
            sHField.setAccessible(true);
            //反射成功重置标识位
            sReflectedFieldsInitialized = INIT_SUCCESS;
        } catch (NoSuchFieldException e) {
    
    
            // very oem much custom ¯\_(ツ)_/¯
        }
    }
}

以上就是 ImmLeaksCleaner类解决方式,代码比较简单有详细的注释,就不再赘述了


对Lifecycle的支持

我们上面看到 ComponentActivity实现了 LifecycleOwner接口,内部创建了 LifecycleRegistry 对象并将当前Activity实例传入

//创建 LifecycleRegistry 对象
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

getLifecycle()返回的值即 mLifecycleRegistry

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

getLifecycle()实现很简单,就是将new出来的mLifecycleRegistry返回,我们从getLifecycle() 的注释上我们提取到两点信息:

  • 官方不推荐重写 getLifecycle() 而且会在未来高版本中会将此方法标记为 final
  • 如果你想重写 getLifecycle() 就需要遵循以下两条
    1. 必须返回一个 LifecycleRegistry 对象
    2. LifecycleRegistry 对象进行懒初始化
      注意:在LifecycleRegistry 对象初始化完成之前,这个对象将会在父类的构造器中调用

对fragment返回键调度支持

什么是对fragment返回键的调度支持? 其本质就是让fragment 能像Activity一样在按下返回键时能够回调onBackPressed() 所以BackPressedDispatcher调度器本质也是将onBackPressed()回调到fragment里面实现而已

下面我们先看一个在fragment里面具体如何使用返回调度?

使用BackPressedDispatcher

1.创建Activity

第一步创建一个测试Activity内部布局和相关代码如下:

class BackMainActivity : BaseEasyActivity() {
    
    


    override fun getLayoutId(): Int {
    
    
        return R.layout.activity_jetpack_back_main
    }

    override fun initView() {
    
    

        supportFragmentManager.beginTransaction()
            .replace(R.id.backContent, BackListFragment())
            .commitNowAllowingStateLoss()

    }

    override fun onBackPressed() {
    
    
        super.onBackPressed()
        Logger.d("onBackPressed")
    }
}

activity_jetpack_back_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/backContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

BackListFragment:

class BackListFragment : BaseEasyListFragment() {
    
    


    override fun initView() {
    
    
        super.initView()

        requireActivity().onBackPressedDispatcher
            .addCallback(this, object : OnBackPressedCallback(true) {
    
    
                override fun handleOnBackPressed() {
    
    
                    Logger.i("back 1")
                    back()
                }
            })
        requireActivity().onBackPressedDispatcher.addCallback(this,object :OnBackPressedCallback(true){
    
    
            override fun handleOnBackPressed() {
    
    
                Logger.i("back 2")

                back2()
            }
        })


    }

    private fun back2() {
    
    
        activity?.let {
    
    
            AlertDialog.Builder(it).setTitle("EasyTitle 2")
                .setMessage("你确定退出吗?")
                .setNegativeButton(
                    "取消"
                ) {
    
     dialog, _ ->
                    dialog?.dismiss()
                }
                .setPositiveButton(
                    "确定"
                ) {
    
     dialog, _ ->
                    dialog?.dismiss()
                    requireActivity().finish()
                }
                .create()
                .show()
        }

    }

    private fun back() {
    
    
        activity?.let {
    
    
            AlertDialog.Builder(it).setTitle("EasyTitle 1")
                .setMessage("你确定退出吗?")
                .setNegativeButton(
                    "取消"
                ) {
    
     dialog, _ ->
                    dialog?.dismiss()
                }
                .setPositiveButton(
                    "确定"
                ) {
    
     dialog, _ ->
                    dialog?.dismiss()
                    requireActivity().finish()
                }
                .create()
                .show()
        }
    }
}

fragment里面我们调用requireActivity().onBackPressedDispatcher.addCallback()添加了两个回调,并在handleOnBackPressed()回调中我们弹出一个确认弹框

addCallback() 这个方法有两个参数含义分别是:

  1. @NonNull LifecycleOwner owner : 当前的lifecycle实现对象 ActiivtyFragment顶级类都实现了LifecycleOwner接口,所以第一个参数一般传入this就可以了
  2. @NonNull OnBackPressedCallback onBackPressedCallback : OnBackPressedCallback接收返回键回调抽象类,子类需要继承此类,其中构造方法中的 boolean enabled 参数必须传入 true如果 传入 false此回调不会执行,默认值为 false

以上就是我们Demo全部代码了,当我们运行程序,点击返回键 我们看到 back2()里的弹框显示出来了,点击确定按钮将会调用finish()关闭当前页面

你可能会疑问我们注册了两个回调,但是back()弹框并没有显示,是怎么回事呢?那就只能看一下源码才能知道答案

返回调度源码解析

返回键调度代码的源头还是在 ComponentActivity中,让我们重新将注意力转移到此类中,前文中我们看到 ComponentActivity实现的接口有一个 OnBackPressedDispatcherOwner :

public interface OnBackPressedDispatcherOwner extends LifecycleOwner {
    
    

    /**
     * Retrieve the {@link OnBackPressedDispatcher} that should handle the system back button.
     *
     * @return The {@link OnBackPressedDispatcher}.
     */
    @NonNull
    OnBackPressedDispatcher getOnBackPressedDispatcher();
}

可以看到 OnBackPressedDispatcherOwner继承与 LifecycleOwner 那么他自然也拥有lifecycle相关的功能 getOnBackPressedDispatcher() 是返回一个返回键路由类,这个类会将系统返回键触发路由到指定回调中

下面我们看一下 ComponentActivity类返回键路由相关代码和实现逻辑

private final OnBackPressedDispatcher mOnBackPressedDispatcher =
        new OnBackPressedDispatcher(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                ComponentActivity.super.onBackPressed();
            }
        });

@Override
@MainThread
public void onBackPressed() {
    
    
    mOnBackPressedDispatcher.onBackPressed();
}

@NonNull
@Override
public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
    
    
    return mOnBackPressedDispatcher;
}        
  • ComponentActivity创建出返回键路由类。并传入了一个默认任务,run()中并将此次点击返回键任务交由父类来实现,这个默认逻辑只有在不存在任何自定义回调的情况下执行
  • onBackPressed()中就是将任务交由 OnBackPressedDispatcher来执行
  • getOnBackPressedDispatcher()只是将当前创建出来的实例进行返回,不过这个方法被标记为 final
OnBackPressedCallback 回调

下面看一下 OnBackPressedCallback的具体实现

public abstract class OnBackPressedCallback {
    
    
    
    private boolean mEnabled;
    
    //存储Cancellable接口集合
    private CopyOnWriteArrayList<Cancellable> mCancellables = new CopyOnWriteArrayList<>();
    
    public OnBackPressedCallback(boolean enabled) {
    
    
        mEnabled = enabled;
    }
    
    @MainThread
    public final void setEnabled(boolean enabled) {
    
    
        mEnabled = enabled;
    }
    
    @MainThread
    public final boolean isEnabled() {
    
    
        return mEnabled;
    }
    
    //调用所有 Cancellable的cancel()函数
    @MainThread
    public final void remove() {
    
    
        for (Cancellable cancellable: mCancellables) {
    
    
            cancellable.cancel();
        }
    }
    
    //子类需要实现的返回键逻辑
    @MainThread
    public abstract void handleOnBackPressed();
    
    //添加和移除 Cancellable 的方法,主要是组件库代码内部调用(包访问权限)
    void addCancellable(@NonNull Cancellable cancellable) {
    
    
        mCancellables.add(cancellable);
    }
    void removeCancellable(@NonNull Cancellable cancellable) {
    
    
        mCancellables.remove(cancellable);
    }
}

上述OnBackPressedCallback 代码逻辑比较简单,有比较详细的注释就不再赘述了

Cancellable

Cancellable 是一个组件库代码内部(包访问权限),取消接口定义如下:

interface Cancellable {
    
    

    /**
     * Cancel the subscription. This call should be idempotent, making it safe to
     * call multiple times.
     */
    void cancel();
}
OnBackPressedDispatcher 返回调度路由

下面我们看一下 OnBackPressedDispatcher 类具体实现

public final class OnBackPressedDispatcher {
    
    

    //默认返回任务
    @Nullable
    private final Runnable mFallbackOnBackPressed;

    //返回键任务队列
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    final ArrayDeque<OnBackPressedCallback> mOnBackPressedCallbacks = new ArrayDeque<>();

    //默认、有参构造器
    public OnBackPressedDispatcher() {
    
    
        this(null);
    }
    public OnBackPressedDispatcher(@Nullable Runnable fallbackOnBackPressed) {
    
    
        mFallbackOnBackPressed = fallbackOnBackPressed;
    }

    //添加返回键任务
    @MainThread
    public void addCallback(@NonNull OnBackPressedCallback onBackPressedCallback) {
    
    
        //调用addCancellableCallback()下面方法,将返回任务包装成可需要性质的任务,
        //子类可以调用 OnBackPressedCallback中remove() 将此任务移除掉
        addCancellableCallback(onBackPressedCallback);
    }
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    @MainThread
    @NonNull
    Cancellable addCancellableCallback(@NonNull OnBackPressedCallback onBackPressedCallback) {
    
    
        //添加到全局集合中
        mOnBackPressedCallbacks.add(onBackPressedCallback);
        //将普通任务包装成可需要性质的任务
        OnBackPressedCancellable cancellable = new OnBackPressedCancellable(onBackPressedCallback);
        onBackPressedCallback.addCancellable(cancellable);
        return cancellable;
    }
    
    //添加任务,并指定了lifecycle对象
    @SuppressLint("LambdaLast")
    @MainThread
    public void addCallback(@NonNull LifecycleOwner owner,
            @NonNull OnBackPressedCallback onBackPressedCallback) {
    
    
        Lifecycle lifecycle = owner.getLifecycle();
        //不能在 DESTROYED 状态时注册
        if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {
    
    
            return;
        }
        //添加一个LifecycleOnBackPressedCancellable 具有生命周期观察能力,可需要性质的任务
        onBackPressedCallback.addCancellable(
                new LifecycleOnBackPressedCancellable(lifecycle, onBackPressedCallback));
    }

    //判断是否存在打开的回调任务
    @MainThread
    public boolean hasEnabledCallbacks() {
    
    
        Iterator<OnBackPressedCallback> iterator =
                mOnBackPressedCallbacks.descendingIterator();
        while (iterator.hasNext()) {
    
    
            if (iterator.next().isEnabled()) {
    
    
                return true;
            }
        }
        return false;
    }

    //ComponentActivity 类中onBackPressed()会代理到这个方法里执行 
    @MainThread
    public void onBackPressed() {
    
    
        //倒序遍历
        Iterator<OnBackPressedCallback> iterator =
                mOnBackPressedCallbacks.descendingIterator();
        while (iterator.hasNext()) {
    
    
            OnBackPressedCallback callback = iterator.next();
            //如果OnBackPressedCallback中mEnabled值为 true才会执行
            //且只会执行任务队列中第一个任务,所以一个fragment如果添加多个任务,只会执行最后添加的任务
            if (callback.isEnabled()) {
    
    
                callback.handleOnBackPressed();
                return;
            }
        }
        //上述任务队列中没有找到可执行的自定义任务,则会将此次事件交给ComponentActivity来执行 
        if (mFallbackOnBackPressed != null) {
    
    
            mFallbackOnBackPressed.run();
        }
    }
    
    //对普通返回任务进行包装成可取消性质的
    private class OnBackPressedCancellable implements Cancellable {
    
    
        private final OnBackPressedCallback mOnBackPressedCallback;
        OnBackPressedCancellable(OnBackPressedCallback onBackPressedCallback) {
    
    
            mOnBackPressedCallback = onBackPressedCallback;
        }

        @Override
        public void cancel() {
    
    
            //从队列中移除和移除自身回调
            mOnBackPressedCallbacks.remove(mOnBackPressedCallback);
            mOnBackPressedCallback.removeCancellable(this);
        }
    }

    //对指定Lifecycle实现类进行包装,内部自动处理生命周期相关状态
    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监听
            lifecycle.addObserver(this);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
    
    
            if (event == Lifecycle.Event.ON_START) {
    
    
                //在fragment启动的时候将任务添加进去,并将任务包装成可需要的任务
                mCurrentCancellable = addCancellableCallback(mOnBackPressedCallback);
            } else if (event == Lifecycle.Event.ON_STOP) {
    
    
                
                //在fragment stop的时候取消任务
                if (mCurrentCancellable != null) {
    
    
                    mCurrentCancellable.cancel();
                }
            } else if (event == Lifecycle.Event.ON_DESTROY) {
    
    
                //fragment销毁时将任务取消
                cancel();
            }
        }

        @Override
        public void cancel() {
    
    
            //移除lifecycle回调
            mLifecycle.removeObserver(this);
            //移除回调
            mOnBackPressedCallback.removeCancellable(this);
            if (mCurrentCancellable != null) {
    
    
                mCurrentCancellable.cancel();
                mCurrentCancellable = null;
            }
        }
    }
}

以上就是OnBackPressedDispatcher返回调度路由类的全部代码,有详细的注释应该看明白。

OnBackPressedDispatcher 是实现返回调度人主要类,内部处理了添加任务,移除任务,将任务路由到指定的 fragment中,这里在添加任务时 推荐使用addCallback(@NonNull LifecycleOwner owner, @NonNull OnBackPressedCallback onBackPressedCallback) 来添加任务,这样就能和 lifecycle关联起来,内部已经处理了和fragment生命周期相关的逻辑了。

activity-ktx扩展库功能

activity-ktx扩展库是 Google 使用kotlin语言开发的辅助库,同时支持了kotlin协程,对于使用jetpack库很有帮助

activity-ktx扩展库主要包含两个kotlin文件:

  • OnBackPressedDispatcherKt
  • ActivityViewModelLazyKt

OnBackPressedDispatcherKt

是专门对 OnBackPressedDispatcher类的一个扩展和包装来看看具体怎么做的

//继承OnBackPressedCallback并对 OnBackPressedDispatcher的addCallback()进行扩展
fun OnBackPressedDispatcher.addCallback(
    owner: LifecycleOwner? = null,
    enabled: Boolean = true,
    onBackPressed: OnBackPressedCallback.() -> Unit
): OnBackPressedCallback {
    
    
    //内部实现类
    val callback = object : OnBackPressedCallback(enabled) {
    
    
        override fun handleOnBackPressed() {
    
    
            //执行传过来的函数式方法
            onBackPressed()
        }
    }
    //对LifecycleOwner不同情况调用不同API
    if (owner != null) {
    
    
        addCallback(owner, callback)
    } else {
    
    
        addCallback(callback)
    }
    return callback
}

从上述源码中我们看到这个方法功能还是比较多的,再具体使用时就比较方便了

使用:

//添加返回回调
requireActivity().onBackPressedDispatcher.addCallback(owner = this,enabled = true,{
    
    
    //...
})

当然根据kotlin具名函数的特点,也可以省略前两个参数:

requireActivity().onBackPressedDispatcher.addCallback(onBackPressed = {
    
    
    //...
})

所以在使用上比之前的方式要简单很多

ActivityViewModelLazyKt

这个扩展类是为了帮助我们方便的使用ViewModel类,想想一下我们是如何创建ViewModel

这里先创建出来一个自定义ViewModel,看一下有多少种方式创建实例

class BackViewModel(application: Application) : AndroidViewModel(application) {
    
    }

ViewModelProviders 方式

viewModel = ViewModelProviders.of(this).get(BackViewModel::class.java)

使用ViewModelProviders调用of()并调用get()就能创建实例,很方便的,但是很不幸在后来的版本中Google 先是将 ViewModelProviders标记为过时,再后来就直接删除了

所以Google推荐直接使用ViewModelProvider来创建实例,其实 ViewModelProvidersof()get()也是对 ViewModelProvider的简单封装

ViewModelProvider 方式

val viewModel = ViewModelProvider(
    this,
    ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(BackViewModel::class.java)

看着是有点麻烦哈…不过代码逻辑还是很好懂的

viewModels() 方式

下面看看利用 ActivityViewModelLazyKt 扩展组件创建ViewModel实例

只需要调用 viewModels() 函数就可以了

val backViewModel = viewModels<BackViewModel> {
    
    
    ViewModelProvider.AndroidViewModelFactory.getInstance(application)
}

当然上面方式是有点麻烦,还需要传入一个 lambda 表达式感觉还不好理解,不过使用默认的 ViewModelFactory 就比较简单了

val viewModel: BackViewModel by viewModels()

或者这样写

val viewModel by viewModels<BackViewModel>()

不过意思是一样的相对以上方式就简单很多了,几乎感受不到 ViewModelProviderAndroidViewModelFactory 等类的存在

接下来看一下viewModels()是如何实现的

viewModels()简要源码分析

//实现了Lazy接口具备懒加载字段的功能
//ComponentActivity类的扩展函数
@MainThread
inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    
    
    //①
    val factoryPromise = factoryProducer ?: {
    
    
        defaultViewModelProviderFactory
    }
    //②
    return ViewModelLazy(VM::class, {
    
    
        viewModelStore
    }, factoryPromise)
}

上述代码虽然简短但是功能比较多,我们具体看一下

  1. 根据参数是否为null来选择是使用自定义 ViewModelProviderFactory 还是 默认的 ViewModelProviderFactory , defaultViewModelProviderFactory 变量对应是 mDefaultFactory (SavedStateViewModelFactory类型)
  2. 根据参数构建一个 ViewModelLazy对象返回

注意: 源码中有如下注释

This property can be accessed only after the Activity is attached to the Application,
and access prior to that will result in IllegalArgumentException.

这里的意思是,如果使用扩展函数初始化的属性只能在Actiivty添加了Application后才能访问,在此之前的访问将会抛出IllegalArgumentException异常

我们知道在启动Activity 会调用 Activityattach()Application上下文对象赋予Activity上,所以我们应该保证变量不能在 ActivityonCreate()之前调用就可以了

总结

本文主要以 jetpack-activity 组件为切入点分析了该组件的主要功能,并根据源码了解了内部实现原理。
简单来说 jetpack-activity 组件有如下功能:

  • 解决一些Android碎片化适配问题
  • Lifecycle系列组件提供了支持
  • 提供了返回键路由,对Fragment处理返回键提供了支持

同时 ktx 扩展组件也是对jetpack-activity 组件库的一个补充,在其他的组件库中 ktx 更是比较重要。

参考

https://developer.android.com/jetpack

https://developer.android.com/jetpack/androidx/releases/activity

https://www.jianshu.com/p/f2aa4cf53abd

猜你喜欢

转载自blog.csdn.net/ForwardSailing/article/details/109639992