0

I create a RecyclerView list that shows a default layout. I then add a new item to the list and the layout updates to show the new item (a CardView). I then navigate back to a previous activity. When I return to the RecyclerView activity I am returned to the generic, default list and my new CardView item does not show.

I have the normal onCreate(Bundle savedInstanceState) code in the Activity. It seems like the adapter just creates a new RecyclerView list upon returning to it rather than returning to the previously created list. What am I missing here?

Activity:

public class ListContactsActivity extends AppCompatActivity {

private ListContactsAdapter mContactsAdapter;
private RecyclerView mRecyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_recyclerviewlist);

    final List<Contact> mContacts;
    mContacts = new ArrayList<>();

    mRecyclerView = (RecyclerView) findViewById(R.id.cardList);
    mRecyclerView.setHasFixedSize(true);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    mContactsAdapter = new ListContactsAdapter(this, mContacts);
    mContactsAdapter.setOnItemTapListener(new ListContactsAdapter.OnItemTapListener() {
        @Override
        public void onItemTap(Contact contact, int position) {
            mContactsAdapter.removeItem(contact, position);
        }
    });
    mRecyclerView.setAdapter(mContactsAdapter);
    ...

Adapter:

 public class ListContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private static class EmptyViewHolder extends RecyclerView.ViewHolder {
    public EmptyViewHolder(View itemView) {
        super(itemView);
    }
}

private class ContactViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView cardBlankText2;

    public ContactViewHolder(View itemView) {
        super(itemView);
        cardBlankText2 = (TextView) itemView.findViewById(R.id.cardBlankText2);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (mOnItemTapListener != null) {
            Contact contact = mContacts.get(getLayoutPosition());
            mOnItemTapListener.onItemTap(contact, getLayoutPosition());
        }
    }
}

private Context mContext;
private LayoutInflater mLayoutInflater;

private List<Contact> mContacts;
private List<ListItem> mItems;

private OnItemTapListener mOnItemTapListener;

public ListContactsAdapter(Context context, List<Contact> contacts) {
    mContext = context;
    mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mContacts = contacts;
    mItems = buildItemsList();
}

public void setOnItemTapListener(OnItemTapListener listener) {
    mOnItemTapListener = listener;
}

private List<ListItem> buildItemsList() {
    List<ListItem> items = new ArrayList<>();
    if (mContacts.size() > 0) {
        for (Contact contact : mContacts) {
            items.add(new ContactItem(contact));
        }
    } else {
        // when R. list is first created or when the number of cards
        // is deleted until there are zero, show the defaultcard_layout
        // and "Click the + above to get started".
        for (int i=0; i<1; i++) {
            items.add(new EmptyItem());
        }
    }
    return items;
}

public void addItem(Contact contact) {
    if (mContacts.size()==0) {
        // if list is empty 
        // remove empty cards first
        mItems.clear();
        notifyDataSetChanged();
    }

    // add item on the top of the list and scroll to the top position
    mContacts.add(contact);
    mItems.add(new ContactItem(contact));
    notifyItemInserted(0);
}

public void removeItem(Contact contact, int position) {
    mContacts.remove(contact);
    if (mContacts.size()==0) {
        // if no more contacts in list,
        // rebuild from scratch
        mItems.clear();
        mItems.addAll(buildItemsList());
        notifyDataSetChanged();
    } else {
        // else remove one item
        mItems.remove(position);
        notifyItemRemoved(position);
    }
}

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

@Override
public int getItemViewType(int position) {
    return mItems.get(position).getType();
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == ListItem.EMPTY_TYPE) {
        View itemView = mLayoutInflater.inflate(R.layout.defaultcard_layout, parent, false);
        return new EmptyViewHolder(itemView);
    } else {
        View itemView = mLayoutInflater.inflate(R.layout.singlecard_layout, parent, false);
        return new ContactViewHolder(itemView);
    }
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
    int type = getItemViewType(position);
    if (type == ListItem.CONTACT_TYPE) {
        ContactItem item = (ContactItem) mItems.get(position);
        final Contact contact = item.getContact();
        ContactViewHolder holder = (ContactViewHolder) viewHolder;
        holder.cardBlankText2.setText(contact.getName() + " " + contact.getSurname());
    }
}
}
AJW
  • 1,578
  • 3
  • 36
  • 77

1 Answers1

3

When an activity is popped off the stack by navigating back, it doesn't retain any of its views or state. The activity object and all its views and state are destroyed. If you need to somehow save what an activity was doing and need to restore that, you need to write the code to do that.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Understood thanks. I added onPause and onResume code from "Someone Somewhere"'s answer as shown here but nothing happened: http://stackoverflow.com/questions/28236390/recyclerview-store-restore-state-between-activities/35131170#35131170. I thought that retaining the layoutmanager state would work. Any thoughts? – AJW Feb 16 '16 at 03:53
  • If you don't want the destruction of the view to happen, then don't start another activity. Instead, switch between views within the current activity and handle the back button to show the prior view. Then if the user wants to navigate into the RecyclerView a second time, just switch the views back. It requires extra code and more complicated views, but you get what you want. – Doug Stevenson Feb 16 '16 at 03:57
  • I'm a newbie at coding and I'm afraid that would be way beyond my current capabilities. All I want to be able to do is create a RecyclerView list, then move around the app (do other activities) and then be able to return to the list to add to it, edit it, update it, remove items, etc. I want the list to be permanently available once created. What do you think? – AJW Feb 16 '16 at 04:04
  • 1
    Learn to write and write data to a sqlite database that's used to store the data in the ListView. There are a lot of tutorials on that, but it's not just a few simple lines of code. – Doug Stevenson Feb 16 '16 at 04:17
  • Ok, interesting. My plan was to learn about creating the RecyclerView and then to move onto SQLite to store the list data. So the database will allow me to store the data and then retrieve it later whenever I need to re-populate and show the RecyclerView list? – AJW Feb 16 '16 at 04:22
  • Thanks. It's amazing to me that almost every article/blog on RecyclerViews has its focus on creating a list, but none on saving the list. It does no good to create a beautifully crafted and valuable list (e.g., a big list of songs I want to download) and then have the list literally be destroyed if I navigate away from the list with the single press of the back button. Why wouldn't saving state code be a requirement for creating every RecyclerView list just like the other requirements: the adapter, the layoutmanager, onCreateViewHolder, onBindViewHolder and getItemCount? Am I off on this? – AJW Feb 17 '16 at 03:18
  • 1
    You might want to read up on Model View Presenter architecture. The work of Views is fairly cheap, and computers don't care if they're asked to do that work repeatedly. You don't want Views to care where their data comes from, so you separate those concerns and solve them independently so they can change without affecting each other. – Doug Stevenson Feb 17 '16 at 03:41
  • Also, I would appreciate it if you formally accept this answer as the correct one so I can get credit for it. :-) – Doug Stevenson Feb 17 '16 at 03:42
  • I understand your recommendation on views but "Model View Presenter architecture"? I'm a Java and Android newbie with zero formal training that is crowdsourcing whatever I can for help, not an advanced coding expert that is looking to refine my expertise. I appreciate your help and answer has been upvoted and accepted. – AJW Feb 17 '16 at 03:49
  • Well, when you get to the point of needing to ship an app to millions of people and build it with a team of dozen people working on it at the same time, the value of sticking to an app architecture will become more evident. I hope you have a great journey to that point! :-) – Doug Stevenson Feb 17 '16 at 03:52
  • Excellent! I will remember your words of advice as I work to get to that point. Working on a simple yet powerful app (something like Evernote) that takes managing work, play and life to the next level. – AJW Feb 17 '16 at 04:01