AndroidX下使用Activity和Fragment的变化详解
过去的一段时间,AndroidX软件包下的Activity/Fragmet的API发生了很多变化。让我们看看它们是如何提升Android的开发效率以及如何适应当下流行的编程规则和模式。
本文中描述的所有功能现在都可以在稳定的AndroidX软件包中使用,它们在去年均已发布或移至稳定版本。
在构造器中传入布局ID
从AndroidX AppCompat1.1.0和Fragment1.1.0(译者注:AppCompat包含Fragment,且Fragment包含Activity,详情见【整理】Jetpack主要组件的依赖及传递关系)开始,您可以使用将layoutId作为参数的构造函数:
classMyActivity:AppCompatActivity(R.layout.my_activity) classMyFragmentActivity:FragmentActivity(R.layout.my_fragment_activity) classMyFragment:Fragment(R.layout.my_fragment)
这种方法可以减少Activity/Fragment中方法重写的数量,并使类更具可读性。无需在Activity中重写onCreate()即可调用setContentView()方法。另外,无需手动在Fragment中重写onCreateView即可手动调用Inflater来扩展视图。
扩展Activity/Fragment的灵活性
借助AndroidX新的API,可以减少在Activity/Fragment处理某些功能的情况。通常,您可以获取提供某些功能的对象并向其注册您的处理逻辑,而不是重写Activity/Fragment中的方法。这样,您现在可以在屏幕上组成几个独立的类,获得更高的灵活性,复用代码,并且通常在不引入自己的抽象的情况下,对代码结构具有更多控制。让我们看看这在两个示例中如何工作。
OnBackPressedDispatcher
有时,您需要阻止用户返回上一级。在这种情况下,您需要在Activity中重写onBackPressed()方法。但是,当您使用Fragment时,没有直接的方法来拦截返回。在Fragment类中没有可用的onBackPressed()方法,这是为了防止同时存在多个Fragment时发生意外行为。
但是,从AndroidXActivity1.0.0开始,您可以使用OnBackPressedDispatcher在您可以访问该Activity的代码的任何位置(例如,在Fragment中)注册OnBackPressedCallback。
classMyFragment:Fragment(){ overridefunonAttach(context:Context){ super.onAttach(context) valcallback=object:OnBackPressedCallback(true){ overridefunhandleOnBackPressed(){ //Dosomething } } requireActivity().onBackPressedDispatcher.addCallback(this,callback) } }
您可能会在这里注意到另外两个有用的功能:
OnBackPressedCallback的构造函数中的布尔类型的参数有助于根据当前状态动态打开/关闭按下的行为
addCallback()方法的可选第一个参数是LifecycleOwner,以确保仅在您的生命周期感知对象(例如,Fragment)至少处于STARTED状态时才使用回调。
通过使用OnBackPressedDispatcher,您不仅可以获得在Activity之外处理返回键的便捷方式。根据您的需要,您可以在任意位置定义OnBackPressedCallback,使其可复用,或根据应用程序的架构进行任何操作。您不再需要重写Activity中的onBackPressed方法,也不必提供自己的抽象的来实现需求的代码。
SavedStateRegistry
如果您希望Activity在终止并重启后恢复之前的状态,则可能要使用savedstate功能。过去,您需要在Activity中重写两个方法:onSaveInstanceState和onRestoreInstanceState。您还可以在onCreate方法中访问恢复的状态。同样,在Fragment中,您可以使用onSaveInstanceState方法(并且可以在onCreate,onCreateView和onActivityCreated方法中恢复状态)。
从AndroidX SavedState1.0.0(它是AndroidXActivity和AndroidX Fragment内部的依赖。译者注:您不需要单独声明它)开始,您可以访问SavedStateRegistry,它使用了与前面描述的OnBackPressedDispatcher类似的机制:您可以从Activity/Fragment中获取SavedStateRegistry,然后注册您的SavedStateProvider:
classMyActivity:AppCompatActivity(){ companionobject{ privateconstvalMY_SAVED_STATE_KEY="my_saved_state" privateconstvalSOME_VALUE_KEY="some_value" } privatelateinitvarsomeValue:String privatevalsavedStateProvider=SavedStateRegistry.SavedStateProvider{ Bundle().apply{ putString(SOME_VALUE_KEY,someValue) } } overridefunonCreate(savedInstanceState:Bundle?){ super.onCreate(savedInstanceState) savedStateRegistry .registerSavedStateProvider(MY_SAVED_STATE_KEY,savedStateProvider) } funsomeMethod(){ someValue=savedStateRegistry .consumeRestoredStateForKey(MY_SAVED_STATE_KEY) ?.getString(SOME_VALUE_KEY) ?:"" } }
如您所见,SavedStateRegistry强制您将密钥用于数据。这样可以防止您的数据被attach到同一个Activity/Fragment的另一个SavedStateProvider破坏。就像在OnBackPressedDispatcher中一样,您可以例如将SavedStateProvider提取到另一个类,通过使用所需的任何逻辑使其与数据一起使用,从而在应用程序中实现清晰的保存状态行为。
此外,如果您在应用程序中使用ViewModel,请考虑使用AndroidX ViewModel-SavedState使你的ViewModel可以保存其状态。为了方便起见,从AndroidX Activity1.1.0和AndroidXFragment1.2.0开始,启用SavedState的SavedStateViewModelFactory是在获取ViewModel的所有方式中使用的默认工厂:委托ViewModelProvider构造函数和ViewModelProviders.of()方法。
FragmentFactory
Fragment最常提及的问题之一是不能使用带有参数的构造函数。例如,如果您使用Dagger2进行依赖项注入,则无法使用Inject注解Fragment构造函数并指定参数。现在,您可以通过指定FragmentFactory类来减少Fragment创建过程中的类似问题。通过在FragmentManager中注册FragmentFactory,可以重写实例化Fragment的默认方法:
classMyFragmentFactory:FragmentFactory(){ overridefuninstantiate(classLoader:ClassLoader,className:String):Fragment{ //CallloadFragmentClass()toobtaintheClassobject valfragmentClass=loadFragmentClass(classLoader,className) //NowyoucanuseclassName/fragmentClasstodetermineyourpreferedway //ofinstantiatingtheFragmentobjectandjustdoithere. //OrjustcallregularFragmentFactorytoinstantiatetheFragmentusing //noargumentsconstructor returnsuper.instantiate(classLoader,className) } }
如您所见,该API非常通用,因此您可以执行想要创建Fragment实例的所有操作。回到Dagger2示例,例如,您可以注入FragmentFactoryProvider
测试Fragment
从AndroidX Fragment1.1.0开始,可以使用Fragment测试组件提供FragmentScenario类,该类可以帮助在测试中实例化Fragment并进行单独测试:
//TolaunchaFragmentwithauserinterface: valscenario=launchFragmentInContainer() //TolaunchaheadlessFragment: valscenario=launchFragment () //Tomovethefragmenttospecificlifecyclestate: scenario.moveToState(CREATED) //Nowyoucane.g.performactionsusingEspresso: onView(withId(R.id.refresh)).perform(click()) //ToobtainaFragmentinstance: scenario.onFragment{fragment->
MoreKotlin!
很高兴看到-ktxAndroidX软件包中提供了许多有用的Kotlin扩展方法,并且定期添加了新的方法。例如,在AndroidXFragment-KTX1.2.0中,使用片段化类型的扩展名可用于FragmentTransaction上的replace()方法。将其与commit()扩展方法结合使用,我们可以获得以下代码:
//Before supportFragmentManager .beginTransaction() .add(R.id.container,MyFragment::class.java,null) .commit() //After supportFragmentManager.commit{ replace(R.id.container) }
FragmentContainerView
一件小而重要的事情。如果您将FrameLayout用作Fragment的容器,则应改用FragmentContainerView。它修复了一些动画z轴索引顺序问题和窗口插入调度。从AndroidXFragment1.2.0开始可以使用FragmentContainerView。
到此这篇关于AndroidX下使用Activity和Fragment的变化详解的文章就介绍到这了,更多相关AndroidX使用Activity和Fragment内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!