PagerAdapter.notifyDataSetChanged不刷新碎片
PagerAdapter.notifyDataSetChanged does not refresh fragments
我的 Activity
包含一个 ViewPager
并且它是扩展 FragmentStatePagerAdapter
的自定义 Adapter
。 ViewPager
包含 3 个片段
从 ViewPager 中删除片段的代码
MainActivity
public void deleteElement(){
final int currentItem = mViewPager.getCurrentItem();
mPagerAdapter.removeItem(currentItem);
mPagerAdapter.notifyDataSetChanged();
}
CustomPagerAdapter
private ArrayList<Item> data;
public void removeItem(int index){
data.remove(index);
}
删除中间的 Fragment
(索引 1)时:
- 来自
data
我正在删除正确的 item
。
- 问题是我(我猜)
Fragment
3在notifyDataSetChanged
之后被删除了,当前的Fragment
仍然是用户看到的片段和正在加载的数据来自 SavedInstance
捆绑包
因此,用户仍然看到他试图删除的相同 Fragment
的最终结果,这对他来说有点糟糕。
想法?
***** 编辑 ******
似乎 ViewPager2 可以解决这个问题以及许多其他问题
尝试添加这个:
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
@Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}
您别无选择,只能执行 PagerAdapter#getItemPosition
。查看源代码,这正是 ViewPager 确定如何更新其位置、添加新片段或在 notifyDataSetChanged
之后删除死片段的方式。这不应该太难,你只需要访问传递的片段的状态,你还需要访问你的 activity 中保存你的订单的主状态。
还需要您实施 getItemId
到 return 每个片段的一致 ID,因为它们可以重新排序。
这就是我在照片的 ViewPager 中处理它的方式。
private inner class PhotoPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int): PhotoViewFragment {
// getItem is called to instantiate the fragment for the given page.
return PhotoViewFragment.newInstance(position, this@PhotoPagerActivity.photos[position])
}
override fun getItemId(position: Int): Long {
return this@PhotoPagerActivity.photos[position].ID!!.hashCode().toLong()
}
override fun getItemPosition(`object`: Any): Int {
val frag = `object` as PhotoViewFragment
val idx = this@PhotoPagerActivity.photos.indexOfFirst { ph -> ph.ID == frag.dataBinding.photo.ID }
return if (idx >= 0) idx else PagerAdapter.POSITION_NONE
}
override fun getCount(): Int {
return this@PhotoPagerActivity.photos.size
}
}
您可以尝试使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter。问题是,我也 运行 关注这个问题,它帮助了我。
您必须先将适配器设置为空,然后再将其设置回去:
int currentPosition = mViewPager.getCurrentItem();
mPagerAdapter.notifyDataSetChanged();
mViewPager.setAdapter(null);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(currentPosition);
您可以尝试使用 FragmentStatePagerAdapter 而不是 FragmentPagerAdapterpublic
它对我有用..!
我知道这个问题有点老了,但是知道 Google 最近用 ViewPager2. See examples here
解决了这个问题可能会很有趣
首先,在您的 build.gradle 文件中添加以下依赖项:
dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
}
现在您可以将 xml 文件中的 ViewPager 替换为:
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
然后您需要将 activity
中的 ViewPager 替换为 ViewPager2
ViewPager2 需要 RecycleView.Adapter 或 FragmentStateAdapter :
public class TabAdapter extends FragmentStateAdapter {
private final List<Tab> tabs;
public TabAdapter(@NonNull FragmentManager fm, List<Tab> tabs, Lifecycle lifecycle) {
super(fm, lifecycle);
this.tabs = tabs;
}
@NonNull
@Override
public Fragment createFragment(int position) {
//create your fragment here
}
@Override
public int getItemCount() {
return tabs.size();
}
@Override
public long getItemId(int position) {
// use a distinct id for each item to allow the adapter to see the changes
}
}
如果您使用的是 TabLayout,则可以使用 TabLayoutMediator:
TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
@Override
public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
// configure your tab here
tab.setText(tabs.get(position).getTitle());
}
});
tabLayoutMediator.attach();
为了删除数据,从您的集合中删除项目后,您可以调用 notifyDataSetChanged()
方法或更具体地说 notifyItemRemoved()
以及已删除项目的位置
区分片段然后android系统将负责回收片段。
例如 - 覆盖 getItemId 提供唯一 ID。
FragmentStateAdapter (ViewPager2) - Kotlin 版本。
class HomeViewPagerAdapter(
fa: FragmentActivity
) : FragmentStateAdapter(fa) {
lateinit var fragments: ArrayList<Fragments>
override fun getItemCount(): Int {
return fragments.size
}
override fun getItemId(position: Int): Long {
return fragments[position].id.ordinal.toLong()
}
override fun createFragment(position: Int): Fragment {
return fragments[position].fragment
}
}
data class Fragments (val id: FragmentId, val fragment: Fragment)
enum class FragmentId {
PageOne,
PageTwo,
PageThree
}
更新适配器
private fun setupAdapter(fragments: ArrayList<Fragments>) {
if (adapter != null) {
adapter?.fragments = fragments
adapter?.notifyDataSetChanged()
} else {
adapter = HomeViewPagerAdapter(requireActivity())
adapter?.fragments = fragments
binding.homeViewPager.adapter = adapter
binding.locationDisabledLl.setOnClickListener {
findNavController().navigate(HomeFragmentDirections.actionHomeToPermission())
}
}
}
我的 Activity
包含一个 ViewPager
并且它是扩展 FragmentStatePagerAdapter
的自定义 Adapter
。 ViewPager
包含 3 个片段
从 ViewPager 中删除片段的代码
MainActivity
public void deleteElement(){
final int currentItem = mViewPager.getCurrentItem();
mPagerAdapter.removeItem(currentItem);
mPagerAdapter.notifyDataSetChanged();
}
CustomPagerAdapter
private ArrayList<Item> data;
public void removeItem(int index){
data.remove(index);
}
删除中间的 Fragment
(索引 1)时:
- 来自
data
我正在删除正确的item
。 - 问题是我(我猜)
Fragment
3在notifyDataSetChanged
之后被删除了,当前的Fragment
仍然是用户看到的片段和正在加载的数据来自SavedInstance
捆绑包
因此,用户仍然看到他试图删除的相同 Fragment
的最终结果,这对他来说有点糟糕。
想法?
***** 编辑 ******
似乎 ViewPager2
尝试添加这个:
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
@Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}
您别无选择,只能执行 PagerAdapter#getItemPosition
。查看源代码,这正是 ViewPager 确定如何更新其位置、添加新片段或在 notifyDataSetChanged
之后删除死片段的方式。这不应该太难,你只需要访问传递的片段的状态,你还需要访问你的 activity 中保存你的订单的主状态。
还需要您实施 getItemId
到 return 每个片段的一致 ID,因为它们可以重新排序。
这就是我在照片的 ViewPager 中处理它的方式。
private inner class PhotoPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int): PhotoViewFragment {
// getItem is called to instantiate the fragment for the given page.
return PhotoViewFragment.newInstance(position, this@PhotoPagerActivity.photos[position])
}
override fun getItemId(position: Int): Long {
return this@PhotoPagerActivity.photos[position].ID!!.hashCode().toLong()
}
override fun getItemPosition(`object`: Any): Int {
val frag = `object` as PhotoViewFragment
val idx = this@PhotoPagerActivity.photos.indexOfFirst { ph -> ph.ID == frag.dataBinding.photo.ID }
return if (idx >= 0) idx else PagerAdapter.POSITION_NONE
}
override fun getCount(): Int {
return this@PhotoPagerActivity.photos.size
}
}
您可以尝试使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter。问题是,我也 运行 关注这个问题,它帮助了我。
您必须先将适配器设置为空,然后再将其设置回去:
int currentPosition = mViewPager.getCurrentItem();
mPagerAdapter.notifyDataSetChanged();
mViewPager.setAdapter(null);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(currentPosition);
您可以尝试使用 FragmentStatePagerAdapter 而不是 FragmentPagerAdapterpublic
它对我有用..!
我知道这个问题有点老了,但是知道 Google 最近用 ViewPager2. See examples here
解决了这个问题可能会很有趣首先,在您的 build.gradle 文件中添加以下依赖项:
dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
}
现在您可以将 xml 文件中的 ViewPager 替换为:
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
然后您需要将 activity
中的 ViewPager 替换为 ViewPager2ViewPager2 需要 RecycleView.Adapter 或 FragmentStateAdapter :
public class TabAdapter extends FragmentStateAdapter {
private final List<Tab> tabs;
public TabAdapter(@NonNull FragmentManager fm, List<Tab> tabs, Lifecycle lifecycle) {
super(fm, lifecycle);
this.tabs = tabs;
}
@NonNull
@Override
public Fragment createFragment(int position) {
//create your fragment here
}
@Override
public int getItemCount() {
return tabs.size();
}
@Override
public long getItemId(int position) {
// use a distinct id for each item to allow the adapter to see the changes
}
}
如果您使用的是 TabLayout,则可以使用 TabLayoutMediator:
TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
@Override
public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
// configure your tab here
tab.setText(tabs.get(position).getTitle());
}
});
tabLayoutMediator.attach();
为了删除数据,从您的集合中删除项目后,您可以调用 notifyDataSetChanged()
方法或更具体地说 notifyItemRemoved()
以及已删除项目的位置
区分片段然后android系统将负责回收片段。
例如 - 覆盖 getItemId 提供唯一 ID。
FragmentStateAdapter (ViewPager2) - Kotlin 版本。
class HomeViewPagerAdapter(
fa: FragmentActivity
) : FragmentStateAdapter(fa) {
lateinit var fragments: ArrayList<Fragments>
override fun getItemCount(): Int {
return fragments.size
}
override fun getItemId(position: Int): Long {
return fragments[position].id.ordinal.toLong()
}
override fun createFragment(position: Int): Fragment {
return fragments[position].fragment
}
}
data class Fragments (val id: FragmentId, val fragment: Fragment)
enum class FragmentId {
PageOne,
PageTwo,
PageThree
}
更新适配器
private fun setupAdapter(fragments: ArrayList<Fragments>) {
if (adapter != null) {
adapter?.fragments = fragments
adapter?.notifyDataSetChanged()
} else {
adapter = HomeViewPagerAdapter(requireActivity())
adapter?.fragments = fragments
binding.homeViewPager.adapter = adapter
binding.locationDisabledLl.setOnClickListener {
findNavController().navigate(HomeFragmentDirections.actionHomeToPermission())
}
}
}