Savedstate 源码分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

Android 应用在因系统资源限制进程被杀死时可通过 onSaveInstanceState-onRestoreInstanceState 保存一些必要数据用于在页面重建时恢复页面 savedstate 对此进行了封装,它与 ViewModel 的区别:
用于保留界面状态的选项

源码分析

来看一下 onSaveInstanceState 和 onCreate 两处保存和恢复数据的地方

// androidx.activity.ComponentActivity
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        SavedStateRegistryOwner {

    // 静态方法创建 SavedStateRegistryController 对象
    final SavedStateRegistryController mSavedStateRegistryController =
            SavedStateRegistryController.create(this);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // 恢复数据
        mSavedStateRegistryController.performRestore(savedInstanceState);
    }

    @CallSuper
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        Lifecycle lifecycle = getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);
        }
        super.onSaveInstanceState(outState);
        // 保存数据
        mSavedStateRegistryController.performSave(outState);
    }

    @NonNull
    @Override
    public final SavedStateRegistry getSavedStateRegistry() {
        return mSavedStateRegistryController.getSavedStateRegistry();
    }

}

ComponentActivity 实现了 SavedStateRegistryOwner 接口重写 getSavedStateRegistry 方法返回一个 SavedStateRegistry 并且在 onCreate 和 onSaveInstanceState 中分别调用了 SavedStateRegistryController 保存和恢复数据的方法

public final class SavedStateRegistryController {
    private final SavedStateRegistryOwner mOwner;
    private final SavedStateRegistry mRegistry;

    private SavedStateRegistryController(SavedStateRegistryOwner owner) {
        mOwner = owner;
        // 创建 SavedStateRegistry 对象
        mRegistry = new SavedStateRegistry();
    }

    @NonNull
    public SavedStateRegistry getSavedStateRegistry() {
        // 返回 SavedStateRegistry 对象
        return mRegistry;
    }

    @MainThread
    public void performRestore(@Nullable Bundle savedState) {
        Lifecycle lifecycle = mOwner.getLifecycle();
        if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
            throw new IllegalStateException("Restarter must be created only during "
                    + "owner's initialization stage");
        }
        lifecycle.addObserver(new Recreator(mOwner));
        // 转发给 SavedStateRegistry
        mRegistry.performRestore(lifecycle, savedState);
    }

    @MainThread
    public void performSave(@NonNull Bundle outBundle) {
        // 转发给 SavedStateRegistry
        mRegistry.performSave(outBundle);
    }

    @NonNull
    public static SavedStateRegistryController create(@NonNull SavedStateRegistryOwner owner) {
        return new SavedStateRegistryController(owner);
    }

}

SavedStateRegistryController 就是简单的对 SavedStateRegistry的包装,在构造方法里创建了 SavedStateRegistry 对象,保存和恢复数据的方法直接转发给了 SavedStateRegistry

public final class SavedStateRegistry {
    private static final String SAVED_COMPONENTS_KEY =
            "androidx.lifecycle.BundlableSavedStateRegistry.key";

    private SafeIterableMap<String, SavedStateProvider> mComponents =
            new SafeIterableMap<>();
    @Nullable
    private Bundle mRestoredState;
    private boolean mRestored;
    private Recreator.SavedStateProvider mRecreatorProvider;
    boolean mAllowingSavingState = true;

    SavedStateRegistry() {
    }

    @MainThread
    @Nullable
    // 根据 key 取出在组件被杀死时保存的数据
    public Bundle consumeRestoredStateForKey(@NonNull String key) {
    	// 在数据恢复前消费抛出异常
        if (!mRestored) {
            throw new IllegalStateException("You can consumeRestoredStateForKey "
                    + "only after su
                    + per.onCreate of corresponding component");
        }
        // 如果恢复的数据不为空
        if (mRestoredState != null) {
        	// 根据 key 取出保存的数据
            Bundle result = mRestoredState.getBundle(key);
            // 取出后就移除第二次再取就返回 null 了
            mRestoredState.remove(key);
            // 如果全部取出则置为 null
            if (mRestoredState.isEmpty()) {
                mRestoredState = null;
            }
            return result;
        }
        return null;
    }

    @MainThread
    // 注册要在组件被杀死时保存数据的来源
    public void registerSavedStateProvider(@NonNull String key,
            @NonNull SavedStateProvider provider) {
        // 保存到 map 中    	
        SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
        // 重复注册同一个 key 抛出异常
        if (previous != null) {
            throw new IllegalArgumentException("SavedStateProvider with the given key is"
                    + " already registered");
        }
    }

    @MainThread
    // 解注册
    public void unregisterSavedStateProvider(@NonNull String key) {
        mComponents.remove(key);
    }

	public interface SavedStateProvider {
        // 在组件被杀死之前调用用于返回要在页面重建后恢复的数据
        Bundle saveState();
    }
}

SavedStateRegistry 维护了一个 map 对象 key 是一个字符串 value 是一个 SavedStateProvider 接口只有一个方法,需要在组件被杀死时保存数据的地方实现此方法在组件被杀死前调用,在 performSave 时保存

	// androidx.savedstate.SavedStateRegistry#performSave
    void performSave(@NonNull Bundle outBundle) {
        Bundle components = new Bundle();
        // 如果还有上次重建时保存并且没有取出的数据再次保存
        if (mRestoredState != null) {
            components.putAll(mRestoredState);
        }
        // 遍历要保存数据的来源 map 调用其 saveState 方法保存
        for (Iterator<Map.Entry<String, SavedStateProvider>> it =
                mComponents.iteratorWithAdditions(); it.hasNext(); ) {
            Map.Entry<String, SavedStateProvider> entry1 = it.next();
            components.putBundle(entry1.getKey(), entry1.getValue().saveState());
        }
        // 保存到 outBundle 中
        // outBundle 是 androidx.activity.ComponentActivity#onSaveInstanceState 方法传过来的
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
    }

    @MainThread
    void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
    	// 重复调用就抛出异常
        if (mRestored) {
            throw new IllegalStateException("SavedStateRegistry was already restored.");
        }
        // savedState 是 androidx.activity.ComponentActivity#onCreate 中传过来的
        if (savedState != null) {
        	// 取出 performSave 中保存的数据
            mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
        }

		// 代码省略 ..
		
		// 标记已恢复
        mRestored = true;
    }

Savedstate 源码比较少也比较简单就是对 onSaveInstanceState-onCreate 的包装扩展给开发者多一种选择来处理应用被杀死需要保存数据的场景

SavedStateHandle

ViewModel 只能处理系统配置更改引起的页面重建,当系统资源限制应用被杀死时 ViewModel 也被杀死了 SavedStateHandle 的引入使得开发者可以通过 ViewModel 来处理系统资源限制保存恢复数据相当于是对 ViewModel 功能的扩展。之前分析 ViewModel 的时候已经看到了
androidx.activity.ComponentActivity 实现了 HasDefaultViewModelProviderFactory 接口重写了 getDefaultViewModelProviderFactory 方法返回了 SavedStateViewModelFactory 对象并且在 create 中创建 ViewModel 对象时判断构造方法中是否有 SavedStateHandle 参数

	// androidx.lifecycle.SavedStateViewModelFactory#create(java.lang.String, java.lang.Class<T>)
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel && mApplication != null) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        if (constructor == null) {
        	// 如果构造方法里没有 ViewModel 参数到这里就返回了
            return mFactory.create(modelClass);
        }

		// 静态方法创建 SavedStateHandleController 对象
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            // 如果是 AndroidViewModel 子类
            if (isAndroidViewModel && mApplication != null) {
      			// 构造方法中传入 SavedStateHandle
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
            	// 构造方法中传入 SavedStateHandle
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

	// androidx.lifecycle.SavedStateHandleController#create
    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
        // 根据 key 恢复数据    
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        // 使用恢复的数据创建 SavedStateHandle 对象
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        // 关联生命周期注册要保存的数据源
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

在创建有以 SavedStateHandle 为构造参数的 ViewModel 时会使用恢复的数据创建
SavedStateHandle 对象作为参数用于创建 ViewModel 对象

	// androidx.lifecycle.SavedStateHandleController#attachToLifecycle
    void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
        if (mIsAttached) {
            throw new IllegalStateException("Already attached to lifecycleOwner");
        }
        mIsAttached = true;
        lifecycle.addObserver(this);
        // 注册要保存的数据源,第二个参数是 SavedStateHandle 中的 SavedStateProvider
        registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
    }

当应用被杀死时会调用所有 SavedStateProvider 的 saveState 方法

public final class SavedStateHandle {
	// 最终要保存的数据
    final Map<String, Object> mRegular;
    // SavedStateHandle 也支持直接设置 SavedStateProvider 会存到这个 map 里
    final Map<String, SavedStateProvider> mSavedStateProviders = new HashMap<>();
    // 可以通过 key 返回一个 LiveData 对象在创建对象后会保存到这里下次不用重复创建
    private final Map<String, SavingStateLiveData<?>> mLiveDatas = new HashMap<>();

    private static final String VALUES = "values";
    private static final String KEYS = "keys";

    private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public Bundle saveState() {
            // 遍历设置的 SavedStateProvider 调用其 saveState 方法返回一个 Bundle 
            // 保存到 mRegular 中
            Map<String, SavedStateProvider> map = new HashMap<>(mSavedStateProviders);
            for (Map.Entry<String, SavedStateProvider> entry : map.entrySet()) {
                Bundle savedState = entry.getValue().saveState();
                set(entry.getKey(), savedState);
            }
            // 遍历 mRegular 把 key-value 分别保存到两个列表中
            Set<String> keySet = mRegular.keySet();
            ArrayList keys = new ArrayList(keySet.size());
            ArrayList value = new ArrayList(keys.size());
            for (String key : keySet) {
                keys.add(key);
                value.add(mRegular.get(key));
            }
            Bundle res = new Bundle();
            // 把两个列表存储到 Bundle 中返回出去存储到 
            // androidx.activity.ComponentActivity#onSaveInstanceState 方法的 Bundle
            // Bundle 存 Bundle 一层套一层 
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
    };


    public SavedStateHandle(@NonNull Map<String, Object> initialState) {
        mRegular = new HashMap<>(initialState);
    }

    public SavedStateHandle() {
        mRegular = new HashMap<>();
    }

	// 上面已经分析过 androidx.activity.ComponentActivity 默认返回的 ViewModelFactory 是 
	// androidx.lifecycle.SavedStateViewModelFactory 在 create 里会创建 SavedStateHandleController 对象
	// 在 SavedStateHandleController 的 create 方法里会调用此方法创建 SavedStateHandle 对象
    static SavedStateHandle createHandle(@Nullable Bundle restoredState,
            @Nullable Bundle defaultState) {
         // restoredState 是通过 androidx.savedstate.SavedStateRegistry#consumeRestoredStateForKey 返回的 Bundle 
         //  如果 restoredState 为 null 说明是正常打开页面或者页面销毁时并没有保存此 key
        if (restoredState == null && defaultState == null) {
            return new SavedStateHandle();
        }

        Map<String, Object> state = new HashMap<>();
        // 默认值在 androidx.activity.ComponentActivity#getDefaultViewModelProviderFactory
        // 方法里会尝试从 getIntent 方法中取
        if (defaultState != null) {
            for (String key : defaultState.keySet()) {
                state.put(key, defaultState.get(key));
            }
        }

        if (restoredState == null) {
        	// 如果 restoredState 就使用默认值创建一个 SavedStateHandle 对象返回
            return new SavedStateHandle(state);
        }

		// 取出上面分析保存的 key-value
        ArrayList keys = restoredState.getParcelableArrayList(KEYS);
        ArrayList values = restoredState.getParcelableArrayList(VALUES);
        if (keys == null || values == null || keys.size() != values.size()) {
            throw new IllegalStateException("Invalid bundle passed as restored state");
        }
        for (int i = 0; i < keys.size(); i++) {
            state.put((String) keys.get(i), values.get(i));
        }
        // 返回 SavedStateHandle 对象 
        return new SavedStateHandle(state);
    }

    @NonNull
    SavedStateProvider savedStateProvider() {
        return mSavedStateProvider;
    }

}

SavedStateHandle 中有一个 SavedStateProvider 对象 mSavedStateProvider 并且也支持额外设置 SavedStateProvider 在页面被销毁调用 mSavedStateProvider 的 saveState 方法时遍历所有设置的 SavedStateProvider 调用 saveState 保存数据,并且每一层返回的都是 Bundle 对象,在创建 ViewModel 对象时会创建 SavedStateHandle 对象并且尝试恢复之前保存的数据,这样就可以通过 ViewModel 对象拿到之前保存的数据了


总结

SavedState 是对 onSaveInstanceState-onRestoreInstanceState 机制的封装可以处理因为系统资源限制应用被杀死时保存简单数据在页面重建时恢复
因为 ViewModel 只能处理系统配置更改引起的页面重建上述情况并不能处理 SavedStateHandle 是利用 SavedState 对 ViewModel 的扩展让开发者可以通过 ViewModel 处理上述场景,当 ViewModel 的构造方法中有 SavedStateHandle 参数时系统默认就会尝试恢复上次应用被杀死时保存的数据

参考与感谢

从源码看 Jetpack(7)- SavedStateHandle 源码详解
【背上Jetpack】绝不丢失的状态 androidx SaveState ViewModel-SaveState 分析
【安卓开发系列 – APP】JetPack – SavedState

<think>嗯,用户的问题是关于JDK17中AQS的await方法源码中,为什么在enableWait方法里将ConditionNode的状态设置为3,也就是COND | WAITING,而不是单独的COND。我需要先理解这些常量的定义,以及为什么要用位或操作组合它们。 首先,我得回忆一下AQS中状态标志位的设计。通常,像AQS这样的同步框架会用位掩码来表示不同的状态,这样可以高效地利用一个整型变量的各个位。比如,每个位可能代表不同的状态标志,如等待状态、取消状态等。 用户提到的COND和WAITING应该是两个不同的状态标志。假设COND的值为1(二进制0001),而WAITING的值为2(二进制0010),那么COND | WAITING的结果就是3(二进制0011)。这样,通过一个整型变量就能同时表示两个状态:该节点属于条件队列(COND),并且当前正在等待(WAITING)。 接下来,我需要查看源码中这些常量的定义。例如,ConditionNode可能继承自Node,而Node类中可能有不同的状态常量。比如,在AQS的Node类中,通常会有CANCELLED(1)、SIGNAL(-1)等状态,但条件队列可能有自己的状态标识。比如,COND可能表示节点在条件队列中,而WAITING表示线程正在等待被唤醒。 使用位或操作的好处是可以在一个字段中存储多个状态,而不需要多个变量。这样不仅节省空间,还能在后续的判断中通过位运算快速检查多个状态。例如,当需要判断一个节点是否处于等待状态时,只需要检查对应的位是否为1即可。 另外,用户可能疑惑为什么不单独使用COND。可能的情况是,仅仅标记节点属于条件队列是不够的,还需要额外的状态信息,比如该节点是否处于等待中。因此,将两个状态合并为一个值,可以更精确地描述节点的当前状态。 还需要考虑源码中其他部分如何处理这个状态值。例如,在唤醒节点时,可能会检查是否同时具有COND和WAITING标志,以确定是否需要执行特定的操作。如果只设置COND,可能无法正确触发后续的处理逻辑。 总结来说,使用COND | WAITING(即3)是为了同时表示节点处于条件队列且正在等待的状态,这样的位掩码设计高效且灵活,允许在一个字段中存储多个状态信息,便于后续的状态判断和处理。</think>在分析这个问题前,我们首先需要理解AQS(AbstractQueuedSynchronizer)中状态位的设计机制。以下是逐步解释: --- ### **1. 状态位的位掩码设计** 在AQS的底层实现中,`status`字段采用位掩码(bitmask)技术来高效存储多个状态标志。这是通过以下常量定义的: ```java // 条件队列节点标志 (二进制 0000 0001) static final int COND = 1; // 等待状态标志 (二进制 0000 0010) static final int WAITING = 2; // 取消状态标志 (二进制 0000 0100) static final int CANCELLED = 4; ``` --- ### **2. 为什么是 `COND | WAITING` (即3)** `node.setStatusRelaxed(COND | WAITING)` 的核心逻辑如下: #### **2.1 同时标记两个状态** - `COND` 标志:标识该节点属于条件队列(Condition Queue) - `WAITING` 标志:标识该节点处于等待状态(等待被signal唤醒) - 通过位或运算 `|` 将两个状态合并到同一个`status`字段中,**二进制表现为 `0011`** #### **2.2 位运算的高效性** 这种设计允许: - **快速状态检查**:通过 `(status & COND) != 0` 判断是否在条件队列 - **多状态共存**:单个`status`字段可携带多个状态信息 - **内存紧凑**:避免为每个状态分配独立字段 --- ### **3. 与后续操作的关联** 设置`COND | WAITING`是后续操作的必要前提: #### **3.1 signal操作依赖** 当调用`signal()`时,会遍历条件队列,寻找`status`包含`COND`标志的节点。但**仅当节点同时处于WAITING状态时**才会被迁移到同步队列。 #### **3.2 超时/中断处理** 如果线程在等待过程中被中断或超时,会通过修改`status`(如设置为`CANCELLED`)来快速判断是否需要移除节点。 --- ### **4. 源码验证** 在OpenJDK 17源码中,相关逻辑可见: ```java // java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionNode final boolean isWaiting() { return (status & WAITING) != 0; } final boolean isInConditionQueue() { return (status & COND) != 0; } ``` 这两个方法验证了`WAITING`和`COND`标志需要被独立检测。 --- ### **5. 为什么不单独用COND?** 如果仅设置`COND`: - 无法区分"新建的未等待节点"和"正在等待的节点" - 无法正确处理超时/中断场景(需要WAITING状态作为前置条件) --- ### **总结** 设置`COND | WAITING`(即3)是为了: 1️⃣ 用位掩码高效存储多状态 2️⃣ 明确区分节点的生命周期阶段 3️⃣ 为后续的signal/transfer操作提供必要状态标记 这种设计是AQS实现高性能同步器的经典技巧,通过位运算在保证线程安全的前提下最大化性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值