当前位置: 首页 > 知识库问答 >
问题:

回收器视图适配器获取旧数据(适配器),即使视图分页程序显示另一个片段

江飞章
2023-03-14

下面你可以找到fragment类,我在那个片段中有一个RecycerView,当用户长时间按下RecycerView中的一个项目时,我试图打开一个上下文菜单。

我能够显示上下文菜单,并为一个片段的单个实例获取选定项的位置,当我滑动到下一个片段时,我得到了相同的索引位置,当我进一步调试时,我发现我得到了前一个片段上的RecycerView的相同适配器。当我记录RecycerView的适配器大小时,可以看到这一点。

有人能帮助我理解为什么当我在ViewPager中切换到该片段的完全不同的html" target="_blank">实例时,我会得到以前的适配器数据,即使我可以在片段中看到正确的数据,并在onBindViewholder方法中获得正确的值。

public class HistoryFragment extends Fragment{
    private static final String LOG_TAG = HistoryFragment.class.getSimpleName();

    private RecyclerView mRecyclerView;
    private HistoryAdapter mHistoryAdapter;
    private List<Group> mGroups;

    private String mGroupType;

    /**
     * tried using a static int value to track which context menu was opened and on which fragment
     * refer post https://caughtinthemobileweb.wordpress.com/2013/10/22/android-viewpager-holds-reference-to-old-fragments/
     * BUG LOGGED AT https://code.google.com/p/android/issues/detail?id=19211
     * does not work :(
     */
    /*private static int selectedContextMenu;*/ // returns valid index as int is static, but adapter still has old data

    /**
     * The fragment argument for this fragment.
     */
    private static final String ARG_GROUP_TYPE = "group_type";

    public HistoryFragment() { }

    /**
     * Returns a new instance of this fragment
     */
    public static HistoryFragment newInstance(String groupType) {
        HistoryFragment fragment = new HistoryFragment();
        Bundle args = new Bundle();
        args.putString(ARG_GROUP_TYPE, groupType);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_history, container, false);
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerViewHistoryItem);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);
        mGroups = new ArrayList<>();
        mHistoryAdapter = new HistoryAdapter(getActivity(), mGroups);
        mRecyclerView.setAdapter(mHistoryAdapter);


        Bundle bundle = getArguments();
        mGroupType = bundle.getString(ARG_GROUP_TYPE);
        if(mGroupType != null && !mGroupType.equals("")){
            loadDataFromDb();
        } else {
            if(IS_DEBUG_ON) Log.d(LOG_TAG, "invalid fragment arguments");
            getActivity().finish();
        }
        return rootView;
    }

    @Override
    public boolean onContextItemSelected(MenuItem item){
        // int id = item.getItemId();
        Log.d(LOG_TAG, "position2: " + mHistoryAdapter.getSelectedItemPosition() + 
                " " + mGroups.get(mHistoryAdapter.getSelectedItemPosition()).getName()); // returns old data
        Log.d(LOG_TAG, "size2: " + mHistoryAdapter.getItemCount()); // returns old data
        // Log.d(LOG_TAG, "position3: " + selectedContextMenu); // returns correct index, but cant use as adapter still has old data
        Log.d(LOG_TAG, "position4: " + ((HistoryAdapter) mRecyclerView.getAdapter()).getSelectedItemPosition()); // returns old data
        return true;
    }

    private void loadDataFromDb(){
        new LoadGroups().execute();
    }

    class HistoryAdapter extends RecyclerView.Adapter<HistoryFragment.HistoryAdapter.ViewHolder> {
        private Context mContext;
        private List<Group> mList;
        private int mSelectedItemPosition;

        HistoryAdapter(Context mContext, List<Group> mList) {
            this.mContext = mContext;
            this.mList = mList;
        }

        class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
            View mView;
            TextView mTextViewName;
            TextView mTextViewDescription;
            ImageView mImageViewProfile;
            ImageView mImageCheck;

            public ViewHolder(View itemView) {
                super(itemView);
                this.mView = itemView;
                this.mTextViewName = (TextView) itemView.findViewById(R.id.textViewGroupName);
                this.mTextViewDescription = (TextView) itemView.findViewById(R.id.textViewGroupDescription);
                this.mImageViewProfile = (ImageView) itemView.findViewById(R.id.groupImage);
                this.mImageCheck = (ImageView) itemView.findViewById(R.id.imageCheck);
                this.mView.setOnCreateContextMenuListener(this); // registering listener
            }

            @Override
            public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                if(mGroupType.equals(GroupContract.GroupEntry.GROUP_TYPE_HISTORY_GROUP)){
                    menu.add(Menu.NONE, R.id.action_resubscribed_group, Menu.NONE, R.string.action_resubscribed_group);
                } else if(mGroupType.equals(GroupContract.GroupEntry.GROUP_TYPE_SUBSCRIBED_GROUP)){
                    if(!mList.get(getAdapterPosition()).isDefault()){
                        menu.add(Menu.NONE, R.id.action_unsubscribe_group, Menu.NONE, R.string.action_unsubscribe_group);
                    }
                    menu.add(Menu.NONE, R.id.action_mute, Menu.NONE, R.string.action_mute);
                    menu.add(Menu.NONE, R.id.action_view_group_info, Menu.NONE, R.string.action_view_group_info);

                }
            }
        }

        @Override
        public HistoryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_history, parent, false);
            return new HistoryAdapter.ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(final HistoryAdapter.ViewHolder holder, final int position) {
            if(mGroupType.equals(GroupContract.GroupEntry.GROUP_TYPE_SUBSCRIBED_GROUP)){
                holder.mImageCheck.setVisibility(View.VISIBLE);
            } else {
                holder.mImageCheck.setVisibility(View.GONE);
            }
            holder.mTextViewName.setText(mList.get(position).getName());
            holder.mTextViewDescription.setText(mList.get(position).getDescription());

            holder.mView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    // mSelectedItemPosition = position; // tried this, returns correct 
                    // selectedContextMenu = position; // also tried this, returns correct
                    mSelectedItemPosition = holder.getAdapterPosition(); // this also returns correct 
                    Log.d(LOG_TAG, "position1 - onBind: " + mSelectedItemPosition + " "+ mList.get(mSelectedItemPosition).getName()); // returns correct data
                    return false;
                }
            });

        }

        @Override
        public void onViewRecycled(ViewHolder holder) {
            holder.mView.setOnLongClickListener(null); // clearing listener to avoid collision between list items
            super.onViewRecycled(holder);
        }

        @Override
        public int getItemViewType(int position) {
            return 0;
        }

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

        int getSelectedItemPosition() {
            Log.d(LOG_TAG, "getter: " + mSelectedItemPosition); // this returns wrong data, shows that fragment is referring old adapter data
            return mSelectedItemPosition;
        }
    }

    // get data from db
    class LoadGroups extends AsyncTask<Void, Void, Void>{

        @Override
        protected Void doInBackground(Void... voids) {
            mGroups = GroupContract.getGroupEntriesFromDB(getActivity(), mGroupType);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);

            mHistoryAdapter = new HistoryAdapter(getActivity(), mGroups);
            mRecyclerView.setAdapter(mHistoryAdapter);
        }
    }
}

下面可以找到ViewPager适配器类

public class HomeTabsPagerAdapter extends FragmentPagerAdapter {
    private Context mContext;

    HomeTabsPagerAdapter(Context context, FragmentManager fm) {
        super(fm);
        mContext = context;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return HistoryFragment.newInstance("TYPE_1");
            case 1:
                return HistoryFragment.newInstance("TYPE_2");
            case 2:
                return HistoryFragment.newInstance("TYPE_3");
        }
        return null;
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return mContext.getString(R.string.text_type_1);
            case 1:
                return mContext.getString(R.string.text_type_2);
            case 2:
                return mContext.getString(R.string.text_type_3);
        }
        return null;
    }

    // Doesn't work even when I use this or not
    /*@Override
    public int getItemPosition(Object object) {
        // try http://stackoverflow.com/a/8024557
        // return super.getItemPosition(object);
        return POSITION_NONE;
    }*/
}

共有1个答案

阎啸
2023-03-14

我怀疑,使用RecycerView.LayoutManager可能是一个问题,因为您有一个静态类,并且前两个创建的片段将具有相同的内容(与第二个片段相同)。下一个片段也是如此。此外,getItemPosition(Object Object)->返回POSITION_NONE只能与FragmentStatePagerAdapter一起使用。FragmentAdapter您从来没有改变片段,一旦创建。所以,我建议不要:

layoutManager layoutManager=new LinearLayoutManager(getActivity(),LinearLayoutManager.vertical,false);SetLayoutManager(layoutManager);

使用

 类似资料:
  • 我正在寻找在Android中使用列表适配器和Recyview适配器的区别。关于性能的任何不同,使用它们的利弊。

  • 我试图使用picasso库将url加载到imageView,但无法获得来正确使用picasso库。

  • 我有一个父回收器视图,其中包含一个水平回收器视图作为其项目。在其中,我将显示分类视频。当我开始滚动水平回收器视图时,应用程序崩溃。 错误是: 我的代码是category类 垂直适配器 水平适配器

  • 这是我的活动: 卡片xml 活动xml 这是我的自定义适配器 我已经看了很多关于如何让它工作的指南,但它仍然不起作用。有人知道发生了什么事吗?我的版本是25.0。1,并导入所有模块。但它并没有在布局中添加一张卡片。

  • 我根据类似问题的答案修改了代码,但没有一个有效。我正在使用TabFragments和RecyclerViews。控制台显示错误“E/RecyclerView:No adapter attached;kipping layout”四次。 (当修改它也给了我错误java.lang.NullPointerException:试图调用虚方法'voidandroid.support.v7.widget.Re

  • 我已经为android adapter view上的read onclick项编写了一个代码, 我正在传递它正在使用的信息 在我的第二个类页面上显示如下输出: {描述=关于选定的描述,标题=选定的标题} 我只想知道如何分别显示描述和标题。 如: 所选标题(显示在一个文本视图上)关于所选内容的说明(显示在另一个文本视图上) 第一类 ------------ public void onItemCli