美文网首页js css html
Fragment版本变化

Fragment版本变化

作者: freelifes | 来源:发表于2022-06-22 15:30 被阅读0次

    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)。

    相关文章

      网友评论

        本文标题:Fragment版本变化

        本文链接:https://www.haomeiwen.com/subject/dtvjvrtx.html