Search code examples
androidlistviewandroid-fragmentsandroid-arrayadapter

Passing of data to a new fragment, fired by the on click event of a component inside the listview


I have a list view fragment which is filled with data from an array adapter. Each item of the list view contain a profile image (ImageView), and description (TextView). I want to do it such that when you press an image in the list view, another fragment should replace the list view fragment and the late fragment should be filled with the data contained in the list item where the image that was pressed is located. What I did so far is implementing an on click listener for the image in the CustomAdaptor class which successfully manages to get the index of the clicked item in the list view and get the information from it. But it fails to fill the new fragment with data that was retrieved from the image click.

This is my Custom Adapter:

public class PostListAdaptor extends ArrayAdapter<Post>{

private Context context;
private ArrayList<Post> posts;

public PostListAdaptor(Context context, ArrayList<Post> objects)
{
    super(context, R.layout.item_post, objects);

    this.context = context;
    this.posts = objects;
}


@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View row = inflater.inflate(R.layout.item_post, parent, false);

    ImageView profileimage = (ImageView) row.findViewById(R.id.profileimage);
    TextView usernametext = (TextView) row.findViewById(R.id.usernametext);
    TextView datetext = (TextView) row.findViewById(R.id.datetext);
    TextView likestext = (TextView) row.findViewById(R.id.likestext);
    ImageView postimage = (ImageView) row.findViewById(R.id.postimage);
    TextView posttitletext = (TextView) row.findViewById(R.id.posttitletext);
  Picasso.with(context).load(posts.get(position).getImage()).into(postimage);
    Picasso.with(context).load(posts.get(position).getUserimage()).into(profileimage);
    datetext.setText(posts.get(position).getDate());
    usernametext.setText(posts.get(position).getUser());
    likestext.setText(Integer.toString(posts.get(position).getLikes()));
    posttitletext.setText(posts.get(position).getTitle());


    postimage.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View view) {

            ArrayAdapter<Post> postArrayAdapter;
            ArrayList<Post> onepostlist= new ArrayList<Post>();
            MainActivity.displayAllPosts=false;

            View parentRow = (View) view.getParent();
            ListView listView1 = (ListView) parentRow.getParent();

            final int position = listView1.getPositionForView(parentRow);

            FragmentTransaction ft = ((FragmentActivity)context).getSupportFragmentManager().beginTransaction();
            FragmentPost post = new FragmentPost();
            ft.replace(R.id.fragmentContainer, post);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.addToBackStack("post");
            ft.commit();

        }
    });

    return row;
}

Solution

  • First of all, whenever we want to pass data of custom class, preferably make that class as Parcelable (Other option, you can use Serializable). So, we can easily attach that parcelable class data with Intent or Bundle and get easily in next activity or fragment.

    So, make your Post class parcelable like below:

    public class Post implements Parcelable {
    String date;
    String user;
    String image;
    String userImage;
    String likes;
    String title;
    
    public Post() {
    }
    
    public String getDate() {
        return date;
    }
    
    public void setDate(String date) {
        this.date = date;
    }
    
    public String getUser() {
        return user;
    }
    
    public void setUser(String user) {
        this.user = user;
    }
    
    public String getImage() {
        return image;
    }
    
    public void setImage(String image) {
        this.image = image;
    }
    
    public String getUserImage() {
        return userImage;
    }
    
    public void setUserImage(String userImage) {
        this.userImage = userImage;
    }
    
    public String getLikes() {
        return likes;
    }
    
    public void setLikes(String likes) {
        this.likes = likes;
    }
    
    public String getTitle() {
        return title;
    }
    
    public void setTitle(String title) {
        this.title = title;
    }
    
    public Post(Parcel parcel) {
        date = parcel.readString();
        user = parcel.readString();
        image = parcel.readString();
        userImage = parcel.readString();
        likes = parcel.readString();
        title = parcel.readString();
    }
    
    @Override
    public int describeContents() {
        return 0;
    }
    
    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(date);
        parcel.writeString(user);
        parcel.writeString(image);
        parcel.writeString(userImage);
        parcel.writeString(likes);
        parcel.writeString(title);
    }
    
    public static final Parcelable.Creator<Post> CREATOR = new
            Parcelable.Creator<Post>() {
                public Post createFromParcel(Parcel in) {
                    return new Post(in);
                }
    
                public Post[] newArray(int size) {
                    return new Post[size];
                }
            };
    }
    

    Now using Bundle, we can send data to fragment during Add/replace operation of fragment.

    For that change below code of your onClick in Adapter below the line final int position = listView1...:-

        //Attach data using Bundle
        Bundle postBundle = new Bundle();
        postBundle.putParcelable("SELECTED_POST", posts.get(position));
    
        FragmentTransaction ft = ((FragmentActivity)context).getSupportFragmentManager().beginTransaction();
        FragmentPost post = new FragmentPost();
        post.setArguments(postBundle);              //Add this line to attach data
        ft.replace(R.id.fragmentContainer, post);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.addToBackStack("post");
        ft.commit();
    

    Then we can catch that data in onCreate() of fragment like below and use that as per need:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle dataBundle = getArguments();
        Post selectedPost = dataBundle.getParcelable("SELECTED_POST");
    }