为什么在ViewPager2中FragmentStateAdapter无法工作?

9

Android Studio 3.6

我想在我的活动中使用ViewPager2内的2个片段。

这是我的活动:

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
public class QRBluetoothSwipeActivity extends AppCompatActivity {
    private ViewPager2 myViewPager2;
    private ViewPagerFragmentAdapter myAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Make sure this is before calling super.onCreate
        setTheme(R.style.AppTheme); // show splash screen
        super.onCreate(savedInstanceState);
        setContentView(R.layout.qr_bluetooth_swipe_activity);
        init();
    }

    private void init() {
        myAdapter = new ViewPagerFragmentAdapter(getSupportFragmentManager());
        myAdapter.addFragment(new BluetoothPageFragment());
        myAdapter.addFragment(new QrPageFragment());
        myViewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
        myViewPager2.setAdapter(myAdapter);
    }

}

这里是ViewPagerFragmentAdapter。

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.ArrayList;

public class ViewPagerFragmentAdapter  extends FragmentStateAdapter {

    private ArrayList<Fragment> arrayList = new ArrayList<>();

    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return arrayList.get(position);
    }

    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }
}

但是我遇到了编译错误:

ViewPagerFragmentAdapter is not abstract and does not override abstract method createFragment(int) in FragmentStateAdapter

我该如何解决这个问题并在 ViewPager2 中使用片段?谢谢。

这解决了https://dev59.com/onMOtIcB2Jgan1znY6rN#72538430。 - Volodymyr Zakharov
1个回答

17

ViewPager2 中的 FragmentStateAdapterViewPager 稍有不同,具体如下:

  • 不再实现 getCount(),而是实现 getItemCount()

  • 不再实现 getItem(int position),而是实现 createFragment(int position)

  • 构造函数签名也不同,需要添加 Lifecycle 参数,并在 super 中包含它

因此,请使用以下代码替换您的 ViewPagerFragmentAdapter

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.ArrayList;


public class ViewPagerFragmentAdapter extends FragmentStateAdapter {

    private ArrayList<Fragment> arrayList = new ArrayList<>();

    public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }


    public void addFragment(Fragment fragment) {
        arrayList.add(fragment);
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        // return your fragment that corresponds to this 'position'
        return arrayList.get(position);
    }

}

同样要确保导入/扩展正确的ViewPager2适配器

import androidx.viewpager2.adapter.FragmentStateAdapter;

2021年更新

这解决了问题的根本问题;然而,通常情况下创建FragmentStateAdapter的方式并不正确,因为:

  1. 为了拥有高性能的ViewPager,它应该只保留少量已实例化的屏幕外页面片段。

  2. 将所有页面片段保存在列表中对于浪费设备资源来说并不好。

  3. createFragment(),顾名思义,旨在为特定页面创建新的片段并返回它;而不是从已经实例化的片段列表中返回一个片段。

  4. 最重要的是,根据文档createFragment():

提供与指定位置相关联的新片段。

适配器将负责碎片的生命周期:

  • 碎片将用于显示项目。
  • 当其远离视口时,碎片将被销毁,并保存其状态。当项目再次接近视口时,将请求一个新的碎片,并使用先前保存的状态对其进行初始化。

因此,我建议将此设计更改为考虑到这一点:

假设您的页面片段是PageFragment;那么您可以通过在PageFragment中拥有static PageFragment newInstance(int position) {}方法来实现单个实例模式,然后createFragment()应该如下所示:

@NonNull
@Override
public Fragment createFragment(int position) {
    // return a brand new fragment that corresponds to this 'position'
    return PageFragment.newInstance(position); // Create a new instance of the page fragment
}

1
我找到了解决方案 https://dev59.com/eVQJ5IYBdhLWcg3wERqZ#58527394 - Alexei
1
使用以下构造函数:public ViewPagerFragmentAdapter(FragmentActivity fa) { super(fa); } - Alexei
1
@a_subscriber 感谢您的提示,它同样有效。 - Zain
16
这是一个非常错误的实现。正如其名称所示,FragmentStateAdapter的createFragment应该负责实例化Fragment。Fragment的创建不应该发生在FragmentStateAdapter之外。即使你需要创建大量的Fragments,FragmentStateAdapter也将负责处理内存使用效率。如果你在FragmentStateAdapter之外创建Fragment,这很可能导致内存效率低下。 - Cheok Yan Cheng
1
@CheokYanCheng 谢谢您提供的信息。非常感谢。 - Zain
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接