【问题标题】:FragmentStateAdapter for ViewPager2 notifyItemChanged not working as expectedViewPager2 notifyItemChanged 的​​ FragmentStateAdapter 未按预期工作
【发布时间】:2020-02-26 06:49:19
【问题描述】:

我将 ViewPager2 与 FragmentStateAdapter 一起使用,并且我正在调用 notifyItemChanged(position)。但正如预期的那样,createFragment 方法不再调用。这是预期的行为还是错误,我该怎么办

我的代码是

    class EEditionPagerAdapter(
    fragmentManager: FragmentManager, lifecycle: Lifecycle, private var date: String
    ) : FragmentStateAdapter(fragmentManager, lifecycle) {

    private var menuList = emptyList<EEditionMenu>()

    override fun getItemCount(): Int = menuList.size

    override fun createFragment(position: Int): Fragment {
        val menu = menuList[position]
        return EEditionListingFragment.newInstance(menu, date)
    }

    fun submitList(list: List<EEditionMenu>) {
        menuList = list
        notifyItemRangeChanged(0, menuList.size)
    }

    fun changeDate(date: String, position: Int){
        this.date = date
        notifyItemChanged(position)
    }
}

【问题讨论】:

    标签: android android-viewpager2


    【解决方案1】:

    FragmentStateAdapter 使用项目 ID 来确定是否已创建片段并重用已创建的片段。默认情况下,项目 ID 是项目的位置。您可以覆盖 getItemIdcontainsItem 以根据位置和日期提供您自己的唯一 ID,然后当日期更改时它会要求新的片段。

    【讨论】:

      【解决方案2】:

      当您为 FragmentStateAdapter 调用 notifyItemChanged 时,它会调用 ensureFragment(position) 来恢复已创建的片段

       private void ensureFragment(int position) {
          long itemId = getItemId(position);
          if (!mFragments.containsKey(itemId)) {
              // TODO(133419201): check if a Fragment provided here is a new Fragment
              Fragment newFragment = createFragment(position);
              newFragment.setInitialSavedState(mSavedStates.get(itemId));
              mFragments.put(itemId, newFragment);
          }
      }
      

      尝试覆盖 onBindViewHolder 并将 Date 设置为片段

         override fun onBindViewHolder(
          holder: FragmentViewHolder,
          position: Int,
          payloads: MutableList<Any>
      ) {
          super.onBindViewHolder(holder, position, payloads)
          val fragment: EEditionListingFragment? = fragmentManager.findFragmentByTag("f$position") as EEditionListingFragment?
          fragment.updateDate(date)
      }
      

      【讨论】:

      • 那么刷新当前页面片段应该怎么做
      • С完成了答案
      • 很好 - 奇怪的是,如果真的想弥合 viewpager 和 recyclerview 之间的差距,没有 get 方法......
      • @slott 桥使用你自己的物品 ID
      【解决方案3】:

      FragmentStateAdapter.class中放入mFragment的片段由

      void placeFragmentInViewHolder(@NonNull final FragmentViewHolder holder)
      

      方法,它是包私有的,我们无权访问,在这种方法中,片段被添加到 mFragment 管理器中,标签为"f" + holder.getItemId(),与"f" + position相同。

              scheduleViewAttach(fragment, container);
              mFragmentManager.beginTransaction()
                      .add(fragment, "f" + holder.getItemId())
                      .setMaxLifecycle(fragment, STARTED)
                      .commitNow();
              mFragmentMaxLifecycleEnforcer.updateFragmentMaxLifecycle(false);
      

      因此,我们可以在显示片段时覆盖onBindViewHolder 方法。

      @Override
      public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {
          super.onBindViewHolder(holder, position, payloads);
          if (position == 0) {
      
              String fragmentTag = "f" + holder.getItemId();
              Log.v(TAG,"fragmentTag is : " + fragmentTag);
              MyFragment fragment0 = (MyFragment) this.mFragmentManger.findFragmentByTag(fragmentTag);
      
              if (fragment0 != null) {
                  Log.v(TAG,"onBindViewHolder updating fragment ...");
                  // do what ever you want to update the MyFragment 
                  fragment0.update(payloads);
              } else {
                  Log.v(TAG,"onBindViewHolder called, but fragment0 is null!");
              }
          }
      } 
      

      在我的例子中,this.mFragmentManager 是通过构造函数兑现的。

      public MyFragmentStateAdapter(@NonNull Fragment fragment) {
              super(fragment); // this calls the fragment.getChildFragmentManager().
              this.mFragmentManger = fragment.getChildFragmentManager();
      }
      

      createFragment() 是:

      @NonNull
      @Override
      public Fragment createFragment(int position) {
          if(position == 0){
              if (this.fragment0 == null) {
                  this.fragment0 = MyFragment.getInstance();
              }
              return this.fragment0;
          } else {
              Log.v(TAG, "position " + position + " is called");
              return null;
          }
      }
      

      最后,在别的地方调用更新来触发更新:

      ViewPager2.getAdapter().notifyItemChanged(0, null); 
      // 0 is the fragment position of the fragment0 and null is payload.
      

      【讨论】:

        猜你喜欢
        • 2021-06-04
        • 2022-01-24
        • 2015-05-11
        • 2020-05-15
        • 2014-10-31
        • 2018-02-12
        • 2014-01-20
        • 2015-01-13
        • 2013-08-01
        相关资源
        最近更新 更多