写点什么

全网都刷爆了,不会只有你不知道吧—,android 智能手机编程答案

用户头像
Android架构
关注
发布于: 12 小时前

}


}


这个时候,你会发现,页面好像没有重建一样。我这才理解了谷歌的用意。它这步棋下的很巧啊。


也里所当然的我抛弃了[FragmentNavigatorHideShow](


),又拥抱回了谷歌爸爸。


说回上面那个问题,当一个页面中可以打开自己的时候,在FragmentNavigator源码中只要是导航到下一个目的地就会重新创建一个新的Fragment,上一个Fragment会被加入回退栈里,所以才可以在Fragment中打开一个新的自己,来展示不同的信息。而hideshow的方式会每次都去查找之前有没有创建过这个页面,如果有,就 Show,如果没有就创建。所以才会导致自己打开自己,永远都是同一个Fragment对象。


[](


)4. 那么到底该如何正确使用




到底该如何正确使用[Navigation](


),这也是我这段时间使用的一点点经验。


Fragment中的所有动态数据都由[ViewModel](


)中的[LiveData](


)保存。我们只监听[LiveData](


)的数据变化,这也符合[MVVM](


) 的架构麻,当然还有一个 Model 我没说Repository,这个我就不解释了。



Fragment之间传递的数据都交给Bundle页面重建的时候这些数据也会被保存,再次走一遍从Bundle中取数据的过程是完全不会报错的。所以页面上的数据不会被丢失了,而像 RecyclerView,ViewPager 之类的控件它们也会保存自己之前的状态,页面重建后,RecyclerView,ViewPager 会记录自己滑动的位置的,这个不用担心,还有一点就是有一些控件,比如CoordinatorLayout你可能需要给它和它的子 View 控件一个 Id 才能保存滑动状态。


遵循这样的一个规则之后呢,就可以忽略这个页面重建的问题了。


[](


)5. Navigation 的页面转场动画的一些问题




用过[Navigation](


)的都知道,页面转场动画要一个一个的添加,就像这样:


<fragment


android:id="@+id/title_screen"


android:name="com.example.android.navigationsample.TitleScreen"


android:label="fragment_title_screen"


tools:layout="@layout/fragment_title_screen">


<action


android:id="@+id/action_title_screen_to_register"


app:destination="@id/register"


app:popEnterAnim="@anim/slide_in_left"


app:popExitAnim="@anim/slide_out_right"


app:enterAnim="@anim/slide_in_right"


app:exitAnim="@anim/slide_out_left"/>


<action


android:id="@+id/action_title_screen_to_leaderboard"


app:destination="@id/leaderboard"


app:popEnterAnim="@anim/slide_in_left"


app:popExitAnim="@anim/slide_out_right"


app:enterAnim="@anim/slide_in_right"


app:exitAnim="@anim/slide_out_left"/>


</fragment>


复制代码


每一个标签都要写一遍一样的代码,让我很头疼。于是我还是想到了,重写FragmentNavigator将所有的增加一个判断如果标签中没有设置专场动画,那么我就给这个Fragment添加上专场动画。


//我一开始设想的载源码位置处添加的动画操作


int enterAnim = navOptions != null ? navOptions.getEnterAnim() : 动画 id;


int exitAnim = navOptions != null ? navOptions.getExitAnim() : 动画 id;


int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : 动画 id;


int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : 动画 id;


if (enterAnim != -1 || exitAnim != -1 || popEnterA


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


nim != -1 || popExitAnim != -1) {


enterAnim = enterAnim != -1 ? enterAnim : 0;


exitAnim = exitAnim != -1 ? exitAnim : 0;


popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;


popExitAnim = popExitAnim != -1 ? popExitAnim : 0;


ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);


}


复制代码


然而我太天真了,我们想到的,谷歌爸爸都考虑过了。因为如果像我一样天真的加上这样的判断之后,你会发现,第一个默认Fragment也拥有了动画属性。而且做隐式链接跳转的时候,这个动画会非常影响观感。所以第一个默认Fragment不能有转场动画。当然后来我想到了判断返回栈是否存在为空,通过这个判断是否是第一个页面。但是我都能想到谷歌爸爸肯定也想到了。他们不这么做肯定是有原因的。于是我放弃了,老老实实的挨个复制粘贴,


[](


)6. Replace 在重建 Fragment 的时候,过度动画卡顿




在使用 [Navigation](


)的时候,按下返回键回到上个页面,页面重建,这个时候会发现过度动画会有那么几百毫秒卡那么一下,一个转场动画也就 400 毫秒左右,卡那么一下效果是非常明显的。这也归功于Fragment重建的原因了,页面展示的数据量巨大的时候,重建时的绘制工作量也是相当的大,所以肯定会卡那么一下下啦。


那么延迟初始化数据能解决吗?


当然能,感觉多次一举,延迟初始化数据页面,数据会突然的从无到有,虽然不影响转场动画了,但是界面会闪一下,用户也会感到莫名其妙:这啥情况?页面怎么闪一下?


后来我仔细的观察发现,Activity 进行跳转的时候会有那么 100 毫秒的延迟,Fragment 进行切换的时候是没有延迟的,cua 的一下,很快啊。


后来我发现了一个方法:


override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {


return super.onCreateAnimation(transit, enter, nextAnim)


}


复制代码


吼~~ 我好像发现了什么ψ(`?′)ψ。


我让它转场动画延迟几百毫秒执行不就行了,给 Fragment 重建填充数据时预留个时间,等它差不多重建 ok 了,再执行动画不就不卡了。


于是我再BaseFragment中重写了这个方法,并给动画 100 毫秒的延迟时间。


override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {


if (enter) {


//如何 nextAnim 是-1 或 0 那么就是没有设置转场动画,直接走 super 就行了


if (nextAnim > 0) {


val animation = AnimationUtils.loadAnimation(requireActivity(), nextAnim)


//延迟 100 毫秒执行让 View 有一个初始化的时间,防止初始化时刷新页面与动画刷新冲突造成卡顿


animation.startOffset = 100


animation.setAnimationListener(object : Animation.AnimationListener{


override fun onAnimationStart(animation: Animation?) {


}


override fun onAnimationEnd(animation: Animation?) {


onEnterAnimEnd()


}


override fun onAnimationRepeat(animation: Animation?) {


}


})


return animation


} else {


onEnterAnimEnd()


}


} else {


if (nextAnim > 0) {


val animation = AnimationUtils.loadAnimation(requireActivity(), nextAnim)


//延迟 100 毫秒执行让 View 有一个初始化的时间,防止初始化时刷新页面与动画刷新冲突造成卡顿


animation.startOffset = 100


return animation


}


}


return super.onCreateAnimation(transit, enter, nextAnim)


}


/**


  • 如果真的要延迟初始化,那么重写这个方法,等动画结束了再初始化


*/


fun onEnterAnimEnd(){


}


只需要监听进入动画就可以了,退出动画只给它延迟但不给任何的事件监听。


这样搞完之后,页面转场动画果然不卡了,延迟 100 毫秒也完全没有影响使用体验。效果很接近 Activity 转场。


我可真是个机灵鬼。


我分享的内容,和我是如何使用的就到这里,我不确定我的方式是不是完全的正确,但目前来看,项目跑的也是挺 ok 的。没出什么问题。


如果我有什么说的不正确的地方,大家也可以多多指点,交流一下经验。

[](

)尾声


Jetpack 架构组件 并不是一项复杂的技术,很多开发者都可以快速上手。但也正是简单易懂,开发者却很容易忽视注解背后的底层技术。在面试和实际架构的过程中,对技术理解肤浅、缺少细节成为无数开发者的致命伤。最近整理收集了 Jetpack 架构组件 基础到实战底层学习手册,对于上面这些实战问题讲解很透彻,今天分享给大家。


[](

)**【[点击获取](


)】**

[](

)Jetpack 架构组件从入门到精通学习手册入门篇


这几个模块是 Jetpack 架构组件 入门篇, 主要介绍 Jetpack 架构组件 特性,分类、应用架构 、实战本节内容主要如下:



[](

)Jetpack 架构组件实战到原理手册—Data Binding 篇

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
全网都刷爆了,不会只有你不知道吧—,android智能手机编程答案