Android:Viewpager 和 FragmentStatePageAdapter
我正在设计一个应用程序,允许用户在 ViewPager 中的多个页面之间翻转。我一直在努力弄清楚当 Fragment 实例在屏幕上不再可见时如何从页面中删除它,缓存它(例如,HashMap),然后恢复它,以便当用户翻回该页面,其中的视图和其他所有内容都将处于删除之前的相同状态。例如,我的第一页是登录屏幕,成功登录后,该屏幕上的某些布局元素可见/不可见。当我向前翻足够多的页面然后翻回第一页时,布局将被重置。对于我的另一个页面来说,这变得更加成为一个问题,该页面包含一个巨大的水平/垂直滚动数据网格,我在后台使用线程在初始化时进行绘制。我使用进度对话框来通知用户加载进度,每次我必须加载它时,这都变得非常烦人。
所以我做了一些研究...
我浏览了 FragmentStatePageAdapter 的源代码,在 destroyItem() 回调中,被删除的 Fragment 实例的状态被保存到 ArrayList 中。当在 instantiateItem() 回调中创建 Fragment 的新实例时,如果某个项目的实例尚不存在(它们通过使用 ArrayList 来跟踪它),则会创建一个新的 Fragment 实例及其保存的状态使用相应的 Fragment.SavedState 数据进行初始化。不幸的是,这些数据不包括视图所处的状态,尽管我注意到对于具有 GridView/ListView 的页面,视图的状态以某种方式恢复(如果我滚动到某个随机位置,翻转几页然后返回) ,它不会被重置)。
根据API:
保存的状态不能包含对其他片段的依赖-- 也就是说它不能使用 putFragment(Bundle, String, Fragment) 来存储 片段引用,因为该引用可能无效 保存的状态稍后使用。同样Fragment的目标和结果 代码不包含在此状态中。
作为 Android 新手,我不太确定我是否理解最后一句话。
话虽这么说,有什么办法可以缓存 View 状态吗?如果没有,我想我会继续将所有片段页面保留在内存中。
I'm designing an app that allows users to flip between multiple pages in a ViewPager. I've been struggling trying to figure out how it is possible to remove a Fragment instance from a page when it is no longer visible on screen, cache it (to, say, a HashMap), and then restore it so that when the user flips back to that page, the views and everything else in it will be in the same state it was before removal. For example, my first page is a login screen that makes certain layout elements on that particular page visible/invisible on a successful login. When I flip forward enough pages then flip back to the first page, the layout is reset. This becomes more of a problem for another one of my pages which contains a huge, horizontal/vertical scrolling grid of data that I use a thread in the background to draw when it initializes. I use a progress dialog to notify the user of loading progress and that becomes really annoying everytime I have to load it.
So I did some research...
I browsed through the source code for FragmentStatePageAdapter and in the destroyItem() callback, the state of the Fragment instance being removed is saved to an ArrayList. When a new instance of the Fragment is being created in the instantiateItem() callback, if an instance of an item doesn't already exist (they keep track of this by using an ArrayList), a new Fragment instance is created and its saved state is initialized with the corresponding Fragment.SavedState data. Unfortunately, this data does not include the state that the Views were in although I noticed that for pages with a GridView/ListView, the state of the Views were somehow restored (if I scrolled to some random position, flipped a few pages and came back, it would not be reset).
According to the API:
The saved state can not contain dependencies on other fragments --
that is it can't use putFragment(Bundle, String, Fragment) to store a
fragment reference because that reference may not be valid when this
saved state is later used. Likewise the Fragment's target and result
code are not included in this state.
Being a noob to Android, I'm not quite sure I understand the last statement.
That being said, is there any way to cache View state? If not, I think I'll just go ahead and go with leaving all the fragment pages in memory.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我遇到了同样的问题,并通过
在我想要保存的片段上实现这两个函数来解决它。在第一个函数中,您应该在捆绑包中保存恢复视图所需的日期(在我的例子中,我有一堆微调器,所以我使用
一个 int 数组来保存它们的位置)。第二个函数在恢复片段时调用,是实现恢复过程的地方。
我希望这有帮助。我还使我的适配器继承自 FragmentStatePageAdapter,但我不确定这是强制性的。
I had the same problem problem and solved it by implementing these two functions
on the fragments that I wanted to save. On the first function, you should save in the Bundle the date that you need to restore the views ( in my case I had a bunch of spinner so I used
an int array to save their positions). The second function, which is called when restoring your fragment, is where you implement the restoring process.
I hope this helps. I also made my adapter to inherit from FragmentStatePageAdapter but I am not sure that this is mandatory.
main.xml 列表
设置 ViewPager
PagerAdapter
请在此处查看更多详细信息 查看寻呼机示例
Listing of main.xml
Setting up the ViewPager
The PagerAdapter
look here for more details view pager example
查看各种文档片段,我最好的猜测是您正在创建的视图没有附加 ID。假设片段的保存状态是从 Fragment.onSaveInstanceState 创建的,那么片段将自动保存任何具有 id 的视图状态。如果您从布局文件创建 ListView/GridView,则可能有一个与您的 ListView/GridView 关联的默认 ID。您还可以通过调用 setId 将 id 与视图关联起来。
此外,对于自定义填充的片段,您可能还需要在 onSaveInstanceState 中执行一些自定义操作。
Looking at the various documentation pieces, my best guess is that the views you are creating do not have an ID attached to them. Assuming that the fragment's saved state is created from Fragment.onSaveInstanceState, then the fragment will automatically save any view's state that has an id. You probably have a default id associated with your ListView/GridView if you created them from a layout file. You can also associate an id with the views by calling setId.
Also, for your custom filled fragment, you may also have to do something custom in onSaveInstanceState.
下面是我如何在 PagerAdapter 中实现缓存的示例。填充缓存后,所有未来的视图请求都将从缓存中提供,仅替换数据。
Here's an example of how I implemented caching in PagerAdapter. After filling the cache all future view requests are served from cache, only data is replaced.
当我使用 PagerSlidingTabStrip 并使用 FragmentPagerAdapter 实例时,我也遇到了这个问题,切换到 FragmentStatePagerAdapter 肯定有效。
然后我使用 onSaveInstanceState() 来保存状态
I also ran into this problem when I was using PagerSlidingTabStrip and using and instance of FragmentPagerAdapter, switching to FragmentStatePagerAdapter definitely worked.
Then I use onSaveInstanceState() to save sate