首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >NotifyDataSetChanged在使用Viewpager2的FragmentStateAdapter中不起作用

NotifyDataSetChanged在使用Viewpager2的FragmentStateAdapter中不起作用
EN

Stack Overflow用户
提问于 2020-07-14 01:14:20
回答 3查看 3.7K关注 0票数 5

我正在用viewpager2和FragmentStateAdapter制作一个文件选择页面。在其中一个页面中,我显示了所有挂载的存储设备,我希望在这些设备上点击查看内容,但希望内容位于另一个片段上。

我想用viewpager最后一页中的另一个替换片段。但是使用下面的代码,页面只是刷新,并且不会创建新的片段,因为createFragment不会被调用。

我的PagerAdapter

代码语言:javascript
运行
复制
public static class PagerAdapter extends FragmentStateAdapter {


        private Fragment mFragmentAtPos0;
        private final FragmentManager mFragmentManager;
        private final FirstPageListener listener = new FirstPageListener();
        public final class FirstPageListener implements
                FirstPageFragmentListener {
            public void onSwitchToNextFragment() {
                mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
                        .commit();
                if (mFragmentAtPos0 instanceof FilesandFolder_Others_MainPage){
                    mFragmentAtPos0 = new FileExplorer(listener);
                }else{ // Instance of NextFragment
                    mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
                }
                notifyDataSetChanged();
            }
            public void onSwitchToNextFragment(Bundle bundle) {
//                mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
//                        .commit();
                if (mFragmentAtPos0 instanceof FilesandFolder_Others_MainPage){
                    mFragmentAtPos0 = new FileExplorer(listener);
                    mFragmentAtPos0.setArguments(bundle);
                }else{ // Instance of NextFragment
                    mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
                    mFragmentAtPos0.setArguments(bundle);
                }
                notifyDataSetChanged();
//                notifyItemChanged(getItemPosition(mFragmentAtPos0));
            }
        }


//        @Override
//        public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {
//            super.onBindViewHolder(holder, position, payloads);
//            if (position == getItemPosition(mFragmentAtPos0)) {
//
//                Fragment f = mFragmentManager.findFragmentByTag("f" + holder.getItemId());
//                if (f != null) {
//                    mFragmentManager.beginTransaction().replace(holder.getItemId(), )
//                }
//            }
//        }

        private int getItemPosition(Fragment mFragmentAtPos0) {
            for (int i = 0; i < getItemCount(); i++){

                if (createFragment(i).equals(mFragmentAtPos0)){
                    return i;
                }
            }
            return -1;
        }


        public PagerAdapter(FragmentActivity fm) {
            super(fm);
            mFragmentManager = fm.getSupportFragmentManager();
            mFragmentAtPos0 = new FilesandFolder_Others_MainPage(listener);
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            switch (position){
                case 0:
                    return new AppSelectionFragment();
                case 1:
                    return new Photos();
                case 2:
                    return new VideoGalleryFragment();
                case 3:
                    return new Gallery();
                default:
                    return mFragmentAtPos0;
            }
        }

        @Override
        public int getItemCount() {
            return 5;
        }
    }

下面是我想要替换为另一个片段的片段的构造函数:

代码语言:javascript
运行
复制
    private static FileSelection.PagerAdapter.FirstPageListener pageFragmentListener;

    public FilesandFolder_Others_MainPage() {
    }
    public FilesandFolder_Others_MainPage(FileSelection.PagerAdapter.FirstPageListener firstPageFragmentListener) {
        pageFragmentListener = firstPageFragmentListener;
    }

在点击视图时,应该调用以下代码:

代码语言:javascript
运行
复制
Bundle bundle = new Bundle();
bundle.putString("PATH", volumes.get(position).path);
pageFragmentListener.onSwitchToNextFragment(bundle);

我已经搜索了所有的堆栈溢出,但从来没有看到一个正确的答案与Viewpager2和FragmentStateAdapter,因为似乎每个人都在使用Viewpager.

我试图实现这一点:- FragmentStateAdapter for ViewPager2 notifyItemChanged not working as expected

但无法理解如何编辑我的代码。请帮助提前感谢!

EN

回答 3

Stack Overflow用户

发布于 2020-08-26 13:28:02

也有同样的问题,这就是我发现的:

FragmentStateAdapteronBindViewHolder(holder, position, payloads)方法,你可以重写它(与onBindViewHolder(holder, position)不同,它是最终的)。此方法在您调用notify方法时调用,对于notifyItemChanged()notifyItemRangeChanged()方法,您可以访问片段并手动更新它。

下面是访问该片段的代码:

代码语言:javascript
运行
复制
public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {

    String tag = "f" + holder.getItemId();

    Fragment fragment = fragmentManager.findFragmentByTag(tag);

    if (fragment != null) {
        //manual update fragment
    } else {
        // fragment might be null, if it`s call of notifyDatasetChanged() 
        // which is updates whole list, not specific fragment
        super.onBindViewHolder(holder, position, payloads);
    }
}

FragmentStateAdapter"f" + holder.getItemId()标记了他的片段,这就是它工作的原因。

你也可以使用DiffUtil,这是更好的方式。解决这个问题的Here is good example,以及最后的一些链接,以便更好地理解ViewPager2

票数 5
EN

Stack Overflow用户

发布于 2021-01-31 01:52:40

我今天也遇到了同样的问题,我想我会在这里分享我的解决方案。我的解决方案不是拦截onBindViewHolder(),而是简单地替换旧的片段:

代码语言:javascript
运行
复制
OldFragment.instance.containerId?.let {
    replace(it, NewFragment.instance)
}

更具体地说:

我的应用程序有一个包含两个片段的ViewPager2。我们称它们为MainFragmentDetailFragment。在MainFragment中单击按钮时,我想用SecondMainFragment替换它。同样的行为反之亦然:SecondMainFragment中的按钮点击会用MainFragment替换它自己。

代码语言:javascript
运行
复制
class CustomFragmentStateAdapter(
    private val fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity) {

    var displaySecondMainFragment: Boolean = false
        set(value) {
            if (field != value) {
                switchFragments(replaceWithSecondMainFragment = value)
            }
            field = value
        }

    private fun switchFragments(replaceWithSecondMainFragment: Boolean) {
        fragmentActivity.supportFragmentManager.commit {
            if (replaceWithSecondMainFragment) {
                MainFragment.instance.containerId?.let {
                    replace(it, SecondMainFragment.instance)
                }
            } else {
                SecondMainFragment.instance.containerId?.let {
                    replace(it, MainFragment.instance)
                }
            }
        }
    }
        
    // Standard adapter overrides
    override fun getItemCount(): Int = 2

    override fun createFragment(position: Int): Fragment = when (position) {
        0 -> if (displaySecondMainFragment) SecondMainFragment.instance else MainFragment.instance
        else -> DetailFragment.instance
    } 
}

使用此扩展属性来获取片段所在容器的id:

代码语言:javascript
运行
复制
inline val Fragment.containerId: Int?
    get() = (view?.parent as? ViewGroup?)?.id

最后,我只需要做这样的事情:

代码语言:javascript
运行
复制
button.setOnClickListener {
    customFragmentStateAdapter.displaySecondMainFragment = true // Or false for the other way
}
票数 1
EN

Stack Overflow用户

发布于 2021-11-18 13:15:36

您可以重写这两个方法

代码语言:javascript
运行
复制
    override fun getItemId(position: Int): Long {
        // generate new id
        return getItem(position).hashCode().toLong()
    }

    override fun containsItem(itemId: Long): Boolean {
        // false if item is changed
        return dataList.find { it.hashCode().toLong() == itemId } != null
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62880883

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档