I have a ViewPager with 3 tabs, each tab loads a fragment, new instance of the same fragment class but with an extra parameter.
Below you can find the fragment class, I have a RecyclerView in that fragment, I am trying to open a context menu when the user long presses on an item in the RecyclerView.
I am able to display the context menu and get the position of the selected item for a single instance of a fragment, when I swipe to the next fragment I am getting the same index position, when I debugged further I find that I am getting the same adapter for the RecyclerView on the previous fragment. This can be seen when I log the adapter size for that RecyclerView.
Can anyone help me understand why I am getting the previous adapter data when I have swiped to a completely different instance of that fragment in the ViewPager, even when I can see the correct data in the Fragment and get the correct values in the onBindViewHolder
method.
Below you can find the simplified code for the fragment class
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);
}
}
}
Below you can find the ViewPager Adapter class
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;
}*/
}