Fragment版本变化

FragmentContainerView

FragmentContainerView继承自FrameLayout, 可以动态添加FrameLayout 支持android:name 和 android: tag属性。

 <androidx.fragment.app.FragmentContainerView
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/fragment_container_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:name="com.example.MyFragment"
 android:tag="my_tag">
 </androidx.fragment.app.FragmentContainerView>

ViewModel创建和存储数据

Lifecycle、ViewModel、SaveState集成,通过by ViewModels ,by activityViewModels,ViewModelProvider构造函数,ViewmodelProvider.of与Fragment一起使用时,默认使用SaveStateViewModelFactory。这个类的主要功能可以关联一个SavedStateHandle,先看下创建ViewModel的方式,再看下SaveStateViewModelFactory和SavedStateHandle。

1、在fragment中创建ViewModel
 class MyFragment : Fragment() {
     val viewmodel: MyViewModel by viewmodels()
 }

@MainThread
public inline fun <reified VM : ViewModel> Fragment.viewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this },
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(
    VM::class, { ownerProducer().viewModelStore },
    factoryProducer ?: {
        (ownerProducer() as? HasDefaultViewModelProviderFactory)?.defaultViewModelProviderFactory
            ?: defaultViewModelProviderFactory
    }
)
2、在fragment中创建ViewModel
 class MyFragment : Fragment() {
      val viewmodel: MyViewModel by activityViewModels()
 }

@MainThread
public inline fun <reified VM : ViewModel> Fragment.activityViewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(
    VM::class, { requireActivity().viewModelStore },
    factoryProducer ?: { requireActivity().defaultViewModelProviderFactory }
)
3、在activity中创建ViewModel
 class MyComponentActivity : ComponentActivity() {
     val viewmodel: MyViewModel by viewmodels()
 }

public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        defaultViewModelProviderFactory
    }

    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
4、各自类中创建ViewModel
ViewModelProvider(this).get(TestViewModel::class.java)

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

  fun getDefaultViewModelProviderFactory(): ViewModelProvider.Factory? {
        if (mDefaultFactory == null) {
            mDefaultFactory = SavedStateViewModelFactory(
                    application,
                    this,
                    getArguments())
        }
        return mDefaultFactory
    }

上述1,2,3最终也会调用到4这种方式实现的。可以看到新版本使用了
SavedStateViewModelFactory方式创建ViewModel,看下创建过程。

 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);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel && mApplication != null) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                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);
        } 
    }

可以看到如果传入modelClass的构造参数没有SavedStateHandle,则默认Factory(NewInstanceFactory)创建ViewModel。SavedStateHandle 是做什么的了?
先看下Fragment中数据保存。

5、Fragment数据保存
    void performSaveInstanceState(Bundle outState) {
        onSaveInstanceState(outState);
        mSavedStateRegistryController.performSave(outState);
        Parcelable p = mChildFragmentManager.saveAllStateInternal();
        if (p != null) {
            outState.putParcelable(FragmentManager.SAVED_STATE_TAG, p);
        }
    }

FragmentStateManager,当状态改变,执行saveState,然后执行了performSaveInstanceState方法。
可以看到保存数据,先执行了onSaveInstanceState,再执行了
mSavedStateRegistryController.performSave(outState),也就是我们自定义的存储是在Fragment之后的。然后看下performSave中的执行。

 void performSave(@NonNull Bundle outBundle) {
        Bundle components = new Bundle();
        if (mRestoredState != null) {
            components.putAll(mRestoredState);
        }
        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.putBundle(SAVED_COMPONENTS_KEY, components);
    }

可以看到 components存储了所有通过SavedStateProvider方法返回的Bundle。这个components是通过什么方式存的了?

   public void registerSavedStateProvider(@NonNull String key,
                                           @NonNull SavedStateRegistry.SavedStateProvider provider) {
        SavedStateRegistry.SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
    }

1、components中的SavedStateProvider是通过registerSavedStateProvider添加进来。在frgament和activity中使用:

    fun testSave() {
        savedStateRegistry.registerSavedStateProvider(TAG) {
            var bundle = Bundle()
            bundle.putString("data", "数据")
            Log.d(TAG, " Save: 保存  " + lifecycle.currentState.name)
            bundle
        }
    }

    fun testRestore() {
        var consumeRestoredStateForKey = savedStateRegistry.consumeRestoredStateForKey(TAG)
        Log.d(TAG, "restore: 恢复 " + consumeRestoredStateForKey?.get("data") + " " + lifecycle.currentState.name)
    }

2、在SavedStateHandleController中也调用了registerSavedStateProvider,而这个SavedStateHandleController的getHandle()就是创建ViewModel的构造函数参数。

  void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
        if (mIsAttached) {
            throw new IllegalStateException("Already attached to lifecycleOwner");
        }
        mIsAttached = true;
        lifecycle.addObserver(this);
        registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
    }

这个方法在创建ViewModel时和屏幕旋转从ViewModelStore中获得ViewModel时调用,保证 registry.registerSavedStateProvider。
上面的mHandle 就是 SavedStateHandle。并且提供了一个savedStateProvider用来获取Bundle。看下这个provider

private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public Bundle saveState() {
            // Get the saved state from each SavedStateProvider registered with this
            // SavedStateHandle, iterating through a copy to avoid re-entrance
            Map<String, SavedStateProvider> map = new HashMap<>(mSavedStateProviders);
            for (Map.Entry<String, SavedStateProvider> entry : map.entrySet()) {
                Bundle savedState = entry.getValue().saveState();
                set(entry.getKey(), savedState);
            }
            // Convert the Map of current values into a Bundle
            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();
            // "parcelable" arraylists - lol
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
    };

可以看到这个类在提供Bundle之前,将原始数据转化成Bundle。那么使用者如何把数据给这个SavedStateHandle了? 看下这个类提供的方法和使用:
1、第一种方式 : 主动存Bundle对象。

class TestViewModel1 : ViewModel {

    private val TAG = "TestViewModel1"

    private var handle: SavedStateHandle? = null

    constructor(handle: SavedStateHandle) {
        this.handle = handle
    }

    fun testResore() {
        var bundle = handle?.get<Bundle>("mahao")
        var age = bundle?.getString("age")
        Log.d(TAG, "testResore: " + age)
        var liveData = handle?.getLiveData<Bundle>("mahao")
        Log.d(TAG, "testResore: >>>> " + liveData?.value?.get("age"))
        liveData?.observeForever {
            var stringAge = it.get("age")
            Log.d(TAG, "testResore: ----- " + stringAge)
        }
    }

    fun testSave() {
        handle?.setSavedStateProvider("mahao", object : SavedStateRegistry.SavedStateProvider {
            override fun saveState(): Bundle {
                var bundle = Bundle()
                bundle.putString("age", "27")
                Log.d(TAG, "saveState:   viewmodel 数据保存了")
                return bundle
            }
        })
    }

    fun testModify() {
        var liveData = handle?.getLiveData<Bundle>("mahao")
        var bundle = Bundle()
        bundle.putString("age", "23")
        liveData?.postValue(bundle)
    }
}

向该类提供数据也是使用的SavedStateProvider 。传递该类后,当数据保存时,将改数据转成Map存储在内存中,恢复数据的时候可以通过
handle.get(key) 和 handle?.getLiveData<Bundle>(key) 获取bundle。
2、第二种方式:任意对象
上面主动通过bundle保存,还可以通过SavingStateLiveData保存,因为mRegular中记录了key,存储就根据key值来存储的。

        @Override
        public void setValue(T value) {
            if (mHandle != null) {
                mHandle.mRegular.put(mKey, value);
            }
            super.setValue(value);
        }

所以创建一个SavingStateLiveData对象,并且调用记录key。

constructor(handle: SavedStateHandle) {
        this.handle = handle
        initData()
    }
    fun initData() {
        liveData = handle?.getLiveData<String>("key", "1223")
        liveData?.value = "1224"
        var myValue = handle?.get<String>("key")
        Log.d(TAG, ": key  = " + myValue)
    }

FramentManager弃用API

弃用了getFragmentManager,requireFragmentManager ,使用getParentFragmentManager。如果fragment没有添加,则会抛出异常,可以使用isAdded()判断。

 public final FragmentManager getParentFragmentManager() {
        FragmentManager fragmentManager = mFragmentManager;
        if (fragmentManager == null) {
            throw new IllegalStateException(
                    "Fragment " + this + " not associated with a fragment manager.");
        }
        return fragmentManager;
    }
 
   if (this.isAdded) {
            parentFragmentManager
        }

ViewTree中支持API

获取LifecycleOwner、ViewModelStoreOwner savedStateRegistryOwner

    init {
        var findViewTreeLifecycleOwner = findViewTreeLifecycleOwner()
        var lifecyclerOwner = ViewTreeLifecycleOwner.get(this)
        lifecyclerOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            }
        })

        var viewModelStoreOwner = ViewTreeViewModelStoreOwner.get(this)
        var viewModel1 = ViewModelProvider(viewModelStoreOwner!!).get(TestViewModel1::class.java)
        viewModel1.testSave()

        var savedStateRegistryOwner = ViewTreeSavedStateRegistryOwner.get(this)
        savedStateRegistryOwner?.savedStateRegistry?.registerSavedStateProvider(TAG, object : SavedStateRegistry.SavedStateProvider {
            override fun saveState(): Bundle {
                var bundle = Bundle()
                bundle.putString("name", "haha")
                return bundle;
            }
        })
    }

Activity Result API

Activity Result API 提供了用于注册result、启动result以及在系统分派result后对其进行处理的组件。

registerForActivityResult(StartActivityForResult(),
                ActivityResultCallback<ActivityResult> { result ->
                    if (result.getResultCode() === RESULT_OK) {
                        val intent: Intent = result.data!!
                    }
                })
registerForActivityResult = fragmentOne!!.registerForActivityResult(object : ActivityResultContract<String, String>() {
            override fun createIntent(context: Context, input: String?): Intent {
                var intent = Intent(context, MainActivity::class.java)
                intent.putExtra("name", input)
                return intent
            }
            override fun getSynchronousResult(context: Context, input: String?): SynchronousResult<String>? {
                if (input.equals("age")) {
                    return SynchronousResult("27")
                }
                return super.getSynchronousResult(context, input)
            }

            override fun parseResult(resultCode: Int, intent: Intent?): String {
                return "zhangsan"
            }
        }
        /*, object : ActivityResultRegistry() {

            override fun <I : Any?, O : Any?> onLaunch(requestCode: Int, contract: ActivityResultContract<I, O>, input: I, options: ActivityOptionsCompat?) {
                Log.d(TAG, "onLaunch: " + requestCode + "   "  + "  " + input)
               // ActivityCompat.startActivityForResult(this@FragmentContainerActivity, intent, requestCode, null)
                 dispatchResult(requestCode, expectedResult)
            }

        }*/, activityResultRegistry, object : ActivityResultCallback<String> {

            override fun onActivityResult(result: String?) {
                Log.d(TAG, "onActivityResult:  1   " + result)
            }
        })

//启动
registerForActivityResult?.launch("aaa1")

如果上述不使用activityResultRegistry,创建一个对象,我们需要使用 dispatchResult(requestCode, expectedResult) 传递给ActivityResultCallback,看下完整的调用过程。
调用registerForActivityResult?.launch("aaa1") 最终调用到 ComponentActivity类中

 private final ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {

        @Override
        public <I, O> void onLaunch(
                final int requestCode,
                @NonNull ActivityResultContract<I, O> contract,
                I input,
                @Nullable ActivityOptionsCompat options) {
            ComponentActivity activity = ComponentActivity.this;
            final ActivityResultContract.SynchronousResult<O> synchronousResult =
                    contract.getSynchronousResult(activity, input);
            if (synchronousResult != null) {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        dispatchResult(requestCode, synchronousResult.getValue());
                    }
                });
                return;
            }
            // Start activity path
            Intent intent = contract.createIntent(activity, input);
            Bundle optionsBundle = null;
            if (ACTION_REQUEST_PERMISSIONS.equals(intent.getAction())) {

                // requestPermissions path
                String[] permissions = intent.getStringArrayExtra(EXTRA_PERMISSIONS);

                if (permissions == null) {
                    permissions = new String[0];
                }
                ActivityCompat.requestPermissions(activity, permissions, requestCode);
            } else {
                // startActivityForResult path
                ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
            }
        }
    };

上面看到最终调用startActivityForResult , requestPermissions,那么数据返回肯定也是通过mActivityResultRegistry处理。

    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

接下来就是回调给callback

  private <O> void doDispatch(String key, int resultCode, @Nullable Intent data,
            @Nullable CallbackAndContract<O> callbackAndContract) {
        if (callbackAndContract != null && callbackAndContract.mCallback != null) {
            ActivityResultCallback<O> callback = callbackAndContract.mCallback;
            ActivityResultContract<?, O> contract = callbackAndContract.mContract;
            callback.onActivityResult(contract.parseResult(resultCode, data));
        } else {
            mParsedPendingResults.remove(key);
            mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));
        }
    }

可以看到上述callbackAndContract可能为null,这是因为在注册的监听的时候ActivityResultRegistry的这个register参数不同导致,看下注册的代码。

  public final <I, O> ActivityResultLauncher<I> register(
            @NonNull final String key,
            @NonNull final LifecycleOwner lifecycleOwner,
            @NonNull final ActivityResultContract<I, O> contract,
            @NonNull final ActivityResultCallback<O> callback) {

        Lifecycle lifecycle = lifecycleOwner.getLifecycle();

        if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
            throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
                    + "attempting to register while current state is "
                    + lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
                    + "they are STARTED.");
        }

        final int requestCode = registerKey(key);
        LifecycleContainer lifecycleContainer = mKeyToLifecycleContainers.get(key);
        if (lifecycleContainer == null) {
            lifecycleContainer = new LifecycleContainer(lifecycle);
        }
        LifecycleEventObserver observer = new LifecycleEventObserver() {
            @Override
            public void onStateChanged(
                    @NonNull LifecycleOwner lifecycleOwner,
                    @NonNull Lifecycle.Event event) {
                if (Lifecycle.Event.ON_START.equals(event)) {
                    mKeyToCallback.put(key, new CallbackAndContract<>(callback, contract));
                    if (mParsedPendingResults.containsKey(key)) {
                        @SuppressWarnings("unchecked")
                        final O parsedPendingResult = (O) mParsedPendingResults.get(key);
                        mParsedPendingResults.remove(key);
                        callback.onActivityResult(parsedPendingResult);
                    }
                    final ActivityResult pendingResult = mPendingResults.getParcelable(key);
                    if (pendingResult != null) {
                        mPendingResults.remove(key);
                        callback.onActivityResult(contract.parseResult(
                                pendingResult.getResultCode(),
                                pendingResult.getData()));
                    }
                } else if (Lifecycle.Event.ON_STOP.equals(event)) {
                    mKeyToCallback.remove(key);
                } else if (Lifecycle.Event.ON_DESTROY.equals(event)) {
                    unregister(key);
                }
            }
        };
        lifecycleContainer.addObserver(observer);
        mKeyToLifecycleContainers.put(key, lifecycleContainer);

        return new ActivityResultLauncher<I>() {
            @Override
            public void launch(I input, @Nullable ActivityOptionsCompat options) {
                mLaunchedKeys.add(key);
                Integer innerCode = mKeyToRc.get(key);
                onLaunch((innerCode != null) ? innerCode : requestCode, contract, input, options);
            }

            @Override
            public void unregister() {
                ActivityResultRegistry.this.unregister(key);
            }

            @NonNull
            @Override
            public ActivityResultContract<I, ?> getContract() {
                return contract;
            }
        };
    }

上述代码
1、如果参数有lifecyclerOwner,注册必须在OnStart之前。
2、注册register,如果参数有lifecyclerOwner,则Lifecycle.Event.ON_START状态时,才从pendingResult中取出数据。
3、 mKeyToCallback.put(key, new CallbackAndContract<>(callback, contract)); 这个方法为什么添加在这里?如果当前页面没有跳转,也能通过activityResultRegistry.dispatchResult回调数据给callback。
4、注册register,如果参数有lifecyclerOwner,则ActivityResultLauncher会在onDestroy时unregister。
总结: 由于Activity Result API 的封装,提供了多种Intent, 更方便在activity和fragment中启动activity,更加解耦,支持在单独的类中处理Activity的返回结果(需要传递activityResultRegistry)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容