android - ViewPager fragment 都引用相同的 RecyclerView 和/或适配器

标签 android android-fragments android-viewpager android-recyclerview

我有一个 fragment ,其中包含一个 RecyclerView 来显示给定日期的事件。我正在使用 ViewPager 将 fragment 分成多天;周六 Activity 的 fragment 和周日 Activity 的 fragment 。

但是,这两个 fragment 似乎都引用了相同的 RecyclerView 和/或适配器,因为它只是显示事件的最后一个选项卡(在本例中为星期日)。

在我的具体情况下,周六有两个事件,周日没有事件。两个 fragment 都有空的 RecyclerView。为了证实我的理论,它是由最后一个标签引起的,我切换了日期。这导致两个 RecyclerView 都有两个事件(星期六的事件)。

这是各个 fragment 的相关代码:

public class EventListFragment extends Fragment{
    private EventAdapter mEventAdapter;

    private static final String DATE_ARG = "eventDate";

    public static EventListFragment newInstance(LocalDate date){
        EventListFragment eventListFragment = new EventListFragment();
        Bundle args = new Bundle();
        args.putSerializable(DATE_ARG, date);
        eventListFragment.setArguments(args);
        return eventListFragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_event_list, container, false);

        // Setup recyclerview
        RecyclerView eventRecyclerView = (RecyclerView) view.findViewById(R.id.event_recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        eventRecyclerView.setLayoutManager(layoutManager);

        // Get date
        LocalDate eventDate = (LocalDate) getArguments().getSerializable(DATE_ARG);

        // Set adapter
        mEventAdapter = new EventAdapter(getActivity(), getEvents(eventDate));
        eventRecyclerView.setAdapter(mEventAdapter);

        return view;
    }
}

getEvents() 只是一个返回给定日期事件的私有(private)函数。我已经使用调试器和单元测试来验证它是否正常工作。调试器显示它为每个 fragment 提取了正确的列表,但正如我所解释的那样,它们显示不正确。

父 fragment 的相关代码如下:

public class EventFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_event, container, false);

        // Get and set up viewpager
        final ViewPager viewPager = (ViewPager) view.findViewById(R.id.event_view_pager);
        EventFragmentAdapter eventFragmentAdapter = new EventFragmentAdapter(getFragmentManager(), getEventDates());
        viewPager.setAdapter(eventFragmentAdapter);

        // Get and set up tablayout
        final TabLayout tabLayout = (TabLayout) view.findViewById(R.id.event_tabs);
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        tabLayout.post(new Runnable() {
            @Override
            public void run() {
                tabLayout.setupWithViewPager(viewPager);
            }
        });

        return view;
    }
}

与上一个类似,getEventDates() 只是提取事件发生的日期。目前出于测试目的,我正在对返回的日期列表进行硬编码,因为我们还没有设置数据库。我取消了这个方法,因为我希望应用程序能够在 2016 年再次运行,这可能有不同的日期:

private List<LocalDate> getEventDates(){
    List<LocalDate> eventDates = new ArrayList<>();

    eventDates.add(new LocalDate(2015, 10, 17));
    eventDates.add(new LocalDate(2015, 10, 18));

    return eventDates;
}

最后一点相关代码是针对我用于 ViewPager 的 FragmentStatePagerAdapter 的:

public class EventFragmentAdapter extends FragmentStatePagerAdapter {
    private List<LocalDate> mEventDates;

    public EventFragmentAdapter(FragmentManager fragmentManager, List<LocalDate> eventDates){
        super(fragmentManager);
        this.mEventDates = eventDates;
    }
    @Override
    public Fragment getItem(int i) {
        return EventListFragment.newInstance(mEventDates.get(i));
    }

    @Override
    public int getCount() {
        return mEventDates.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mEventDates.get(position).dayOfWeek().getAsText();
    }
}

知道为什么两个列表总是相同的,并且基于 ViewPager 中的最后一个选项卡吗?我假设它们以某种方式引用了相同的 RecyclerView 或相同的 RecyclerViewAdapter,但我没有这些的任何静态字段,所以我不确定它是如何发生的。

最佳答案

漫长的寻找和反高潮的解决方案(与最困难的错误一样)。也有点不公平,因为错误不在上面发布的代码中,我不得不寻找你的 git 项目来找出它。该错误在 EventAdapter 中:

public class EventAdapter extends RecyclerView.Adapter<EventAdapter.ViewHolder> {
    private static final List<Event> mEvents;
    private final Context mContext;

    public EventAdapter(Context context, List<Event> events){
        this.mContext = context;
        mEvents = events;
    }
    ...
}

mEvents 是静态的!...所以它在 mEvents 的所有实例之间共享。这完美地解释了该错误,因为最后对其进行更新将为所有 EventAdapter 设置值。

看起来您将 mEvents 设为静态,以便您可以在 ViewHolders 中访问它。相反,您可以将单个事件存储在 ViewHolder 中并删除危险的静态修饰符。另一方面,开源项目万岁!

关于android - ViewPager fragment 都引用相同的 RecyclerView 和/或适配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31773986/

相关文章:

java - 我需要使用没有一些参数的自定义类

android - 将 Snackbar 放在最高的 z 顺序以避免被 AutoCompleteTextView 下拉列表阻止

android - 无法将数据从 Activity 发送到 Android Studio 上的 fragment

android - 在 fragmentPagerAdapter 中禁用滑动? - 安卓

java - getItem() 在 Android 中的 ViewPager 中如何工作?

android - Android SDK 中突然缺少 ant/文件夹。谷歌删除了吗?

android - ListFragment onListItemClick 不再适用于 Android 4.1 Jelly Bean

android - 用 ViewPager 中的另一个 fragment 替换 fragment

android - 在 Android 的 ViewPager 中禁用和启用分页

java - Fragment 中的 ViewPager 返回 IllegalStateException