7

I have a RecyclerView that utilizes a Recycler Adapter to output a list layout, like this:

https://i.stack.imgur.com/nqek6.png

I need to attach the model below to each of the list items, such that if the user clicks on any element in the list item (like the circle or one of the two TextViews), it passes the model object to the next Activity.

Here is the User model:

public class User {

    private String id;
    private String username;
    private String displayName;
    private Object deletedAt;
    private Statistic stat;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username= username;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }

    public Object getDeletedAt() {
        return deletedAt;
    }

    public void setDeletedAt(Object deletedAt) {
        this.deletedAt = deletedAt;
    }

    public Statistic getStat() {
        return stat;
    }

    public void setStat(Statistic stat) {
        this.stat = stat;
    }

}

Here is the layout for each list item (user_layout.xml):

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/user_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/white">

            <ImageView
                android:id="@+id/avatar"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:background="@drawable/avatar" />


            <TextView
                android:id="@+id/display_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignTop="@+id/avatar"
                android:layout_toRightOf="@+id/avatar"
                />

            <TextView
                android:id="@+id/username"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/display_name"
                />

        </RelativeLayout>

    </LinearLayout>

</LinearLayout>

Here is the UserRecyclerAdapter that's used to inflate the layout above:

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

    private Context context;
    private List<User> mDataset;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView avatar;
        public TextView displayName;
        public TextView username;

        public ViewHolder(LinearLayout view) {
            super(view);

            avatar = (ImageView) view.findViewById(R.id.avatar);
            displayName = (TextView) view.findViewById(R.id.display_name);
            username = (TextView) view.findViewById(R.id.username);
        }
    }

    public UserRecyclerAdapter(Context context, List<User> myDataset) {
        this.context = context;
        this.mDataset = myDataset;
    }

    @Override
    public UserRecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_layout, parent, false);
        ViewHolder vh = new ViewHolder((LinearLayout) view);

        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        User userItem = mDataset.get(position);

        holder.displayName.setText(userItem.getDisplayName());
        holder.username.setText(userItem.getUsername());
    }

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

}

So my question is, how can I attach the User model object to each list item so that when an element (like the circle or two TextViews) are clicked, it passes the model object to the next Activity?

Thanks.

user5314557
  • 131
  • 1
  • 4

3 Answers3

11

implements Serializable in your User class like User implements Serializable.

pass serializable class via Bundle like

User userItem = mDataset.get(position);

Intent yourIntent = new Intent(this, YourNextActivity.class);
Bundle b = new Bundle();
b.putSerializable("user", userItem);
yourIntent.putExtras(b); //pass bundle to your intent
startActivity(yourIntent);

and get

Intent i = getIntent();
Bundle bundle = i.getExtras();
User user = (User) bundle.getSerializable("user");
Nitin Kabra
  • 3,146
  • 10
  • 43
  • 62
Mehul Kabaria
  • 6,404
  • 4
  • 25
  • 50
4

Make User implement the Parceable interface.

If you use Android Studio, there's a great plugin to help you with that called "Android Parcelable code generator". With the plugin you can just automatically generate all the necessary code, but the basic idea is as follows:

You need an empty constructor:

public User() {}

Then implement the interface methods:

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(id);
    dest.writeString(userName);
    dest.writeString(displayName);
    ...
    // Any object to be added to dest must implement Parceable in its turn
    // Please note that Lists and Serializable objects are already supported out of the box
}

public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {

    @Override
    public EventFrame createFromParcel(Parcel source) {
        return new User(source);
    }

    @Override
    public EventFrame[] newArray(int size) {
        return new User[size];
    }
};

private EventFrame(Parcel source) {
    id = source.readString();
    accessToken = source.readString();
    displayName = source.readString();
    ...
}

Afterwards, when creating an intent for the next activity, just do:

Intent yourIntent = new Intent(this, DestinyClass.class);
yourIntent.putExtra("user_identifier", user);
Edson Menegatti
  • 4,006
  • 2
  • 25
  • 40
  • 1
    How do I attach the model object to the list item layout though, such that when an element in the layout is clicked, it uses that specific model object instance. – user5314557 Sep 15 '15 at 20:03
  • That's a different question and I advise you to take a look at a few of the RecyclerView examples, SO is full of them. Anyway, the comment section is not the place to discuss that answer, just create another question for that. Check this link https://developer.android.com/training/material/lists-cards.html – Edson Menegatti Sep 15 '15 at 20:10
  • I think you're confused. I'm not asking how to make a RecyclerView. I've got that. I'm asking how to attach the object to the layout such that when the layout element is clicked, the object is sent to the next Activity. – user5314557 Sep 15 '15 at 20:14
  • I'm sorry, I was indeed confused. You can just include the user object to your ViewHolder, its contents doesn't need to be only UI elements. Then you can do what @tibo did and set a click listener on the UI elements you need. – Edson Menegatti Sep 16 '15 at 11:58
  • Also just wandering same thing can be achieved using Bundle class then why to use this library? – Hussain Shabbir Feb 13 '18 at 03:49
3

Use this library

@Parcel
public class User {
    public User() {}
    // You can keep all the members private with @Parcel(Serialization.BEAN)
    public String id;
    public String username;
    public String displayName;
    public Object deletedAt;
    public Statistic stat; // Needs to be @Parcel annotated as well
}

ActivityA.java
void openActivityB() {
    Intent intent = new Intent(this, ActivityB.class);
    intent.putExtra("user", Parcels.wrap(user));
    startActivity(intent);
}

ActivityB.java
void receive() {
    User user = Parcels.unwrap(getIntent().getParcelableExtra("user"));
} 

update:

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    User userItem = mDataset.get(position);

    holder.displayName.setText(userItem.getDisplayName());
    holder.username.setText(userItem.getUsername());

    setOnClickListener(...
        onClick() {
            Context context = holder.displayName.getContext();
            Intent intent = new Intent(context, ActivityB.class);
            intent.putExtra("user", Parcels.wrap(userItem));
            context.startActivity(intent);
    });
}
mbmc
  • 5,024
  • 5
  • 25
  • 53
  • How do I attach the object to the list item layout though? In other words, how would I get `user` so I can do `Parcels.wrap(user)`? – user5314557 Sep 15 '15 at 20:02
  • BAD, if you launch the activity from onBindViewHolder, you will launch a lot of activities, and without clicking... attach an onClickListener to the view of the viewholder and launch from there. – stephane k. Sep 15 '15 at 20:36
  • Wouldn't that start the activity upon clicking the entire layout? – user5314557 Sep 15 '15 at 21:15
  • it's pseudo code. Attach the listener to whatever view you want. – mbmc Sep 15 '15 at 21:19