简体   繁体   中英

Android: Sending a cardview from one fragment to another

I need some help for a summer project

This is my Events fragment

This is my MyList fragment

I'm using a RecyclerView+Cardview to display the Events. The idea is that the user can click the big plus on the right side of each card, and the card would be displayed in the MyList fragment. I would like to ask if it's possible to transfer a card directly from one fragment to another? Also, both fragments are contained within the same activity, which makes it a little trickier(I haven't found any available solutions).

If that is not possible, another way is to transfer the reference type object contained in the CardView to the MyList fragment. However, this is even less straightforward. This is because the button is inflated in the adapter, but there is no reference type object created here. I have seen many tutorials on using the Parcelable interface, however, I don't know how to implement it here when I'm unable to even create the object in the adapter. The reference object is created in another activity and stored in Firebase before it is read and displayed.

I'm going to attach my EventsAdapter.java and EventsItem.java and EventsFragment.java code below, but please let me know if I should include more code to describe the problem.

Thanks for reading my very long post!!


public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder> implements Filterable {
    private ArrayList<EventsItem> mEventsList;
    private ArrayList<EventsItem> mEventsListFull;
    private EventsAdapter.OnItemClickListener mListener;
    private Context mContext;
    private DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.UK);

    public interface OnItemClickListener {
        void onItemClick(int position);
    }


    //the ViewHolder holds the content of the card
    public static class EventsViewHolder extends RecyclerView.ViewHolder {

        public ImageView mImageView;
        public ImageView mAddButton;
        public TextView mTextView1;
        public TextView mTextView2;
        public TextView mTextView3;
        public TextView mTextView4;
        public TextView mTextView5;

        public EventsViewHolder(Context context, View itemView, final EventsAdapter.OnItemClickListener listener) {
            super(itemView);
            final Context context1 = context;
            mImageView = itemView.findViewById(R.id.imageView);
            mAddButton = itemView.findViewById(R.id.image_add);
            mTextView1 = itemView.findViewById(R.id.title);
            mTextView2 = itemView.findViewById(R.id.event_description);
            mTextView3 = itemView.findViewById(R.id.date);
            mTextView4 = itemView.findViewById(R.id.location);
            mTextView5 = itemView.findViewById(R.id.time);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        int position = getAdapterPosition();
                        if (position != RecyclerView.NO_POSITION) {
                            listener.onItemClick(position);
                        }
                    }
                }
            });
            mAddButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String str1 = mTextView1.getText().toString();
                    String str2 = mTextView2.getText().toString();
                    String str3 = mTextView3.getText().toString();
                    String str4 = mTextView4.getText().toString();
                    String str5 = mTextView5.getText().toString();

                    Bundle bundle = new Bundle();
                    bundle.putString("title", str1);
                    bundle.putString("event description", str2);
                    bundle.putString("date", str3);
                    bundle.putString("location", str4);
                    bundle.putString("time", str5);
                    MylistFragment mlf = new MylistFragment();
                    mlf.setArguments(bundle);
                }
            });
        }

    }

    //Constructor for EventsAdapter class. This ArrayList contains the
    //complete list of items that we want to add to the View.
    public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
        mEventsList = EventsList;
        mContext = context;
        mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
    }

    //inflate the items in a EventsViewHolder
    @NonNull
    @Override
    public EventsAdapter.EventsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.event_item, parent, false);
        EventsAdapter.EventsViewHolder evh = new EventsAdapter.EventsViewHolder(mContext, v, mListener);
        return evh;
    }

    @Override
    public void onBindViewHolder(@NonNull EventsAdapter.EventsViewHolder holder, int position) {
        EventsItem currentItem = mEventsList.get(position);
        holder.mImageView.setImageResource(currentItem.getProfilePicture());
        holder.mTextView1.setText(currentItem.getTitle());
        holder.mTextView2.setText(currentItem.getDescription());
        holder.mTextView3.setText(df.format(currentItem.getDateInfo()));
        holder.mTextView4.setText(currentItem.getLocationInfo());
        holder.mTextView5.setText(currentItem.getTimeInfo());
    }



    @Override
    public int getItemCount() {
        return mEventsList.size();
    }
public class EventsItem implements Occasion, Parcelable {
    //fields removed for brevity

    //constructor removed for brevity
    }

    public EventsItem() {

    }

    public EventsItem(Parcel in) {
        profilePicture = in.readInt();
        timeInfo = in.readString();
        hourOfDay = in.readInt();
        minute = in.readInt();
        locationInfo = in.readString();
        title = in.readString();
        description = in.readString();
    }

    public static final Creator<EventsItem> CREATOR = new Creator<EventsItem>() {
        @Override
        public EventsItem createFromParcel(Parcel in) {
            return new EventsItem(in);
        }

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

    //getter methods have been removed for brevity
    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(profilePicture);
        dest.writeString(timeInfo);
        dest.writeString(locationInfo);
        dest.writeString(title);
        dest.writeString(description);
        dest.writeString(df.format(dateInfo));
        dest.writeInt(hourOfDay);
        dest.writeInt(minute);
    }
}
public class EventsFragment extends Fragment {
    ArrayList<EventsItem> EventsItemList;
    FirebaseDatabase mDatabase;
    DatabaseReference mDatabaseReference;
    ValueEventListener mValueEventListener;
    private RecyclerView mRecyclerView;
    private RecyclerView.LayoutManager mLayoutManager;
    private EventsAdapter mAdapter;
    private View rootView;
    public FloatingActionButton floatingActionButton;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_events, container, false);
        mDatabase = FirebaseDatabase.getInstance();
        mDatabaseReference = mDatabase.getReference().child("Events");

        createEventsList();
        buildRecyclerView();

        floatingActionButton = rootView.findViewById(R.id.fab);
        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), EventsAdder.class);
                startActivity(intent);
            }
        });
        mValueEventListener = new ValueEventListener() {

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                    EventsItemList.add(snapshot.getValue(EventsItem.class));
                }
                EventsAdapter eventsAdapter = new EventsAdapter(getActivity(), EventsItemList);
                mRecyclerView.setAdapter(eventsAdapter);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        mDatabaseReference.addValueEventListener(mValueEventListener);

        setHasOptionsMenu(true);
        Toolbar toolbar = rootView.findViewById(R.id.events_toolbar);
        AppCompatActivity activity = (AppCompatActivity) getActivity();
        activity.setSupportActionBar(toolbar);
        return rootView;
    }

    public void createEventsList() {
        EventsItemList = new ArrayList<>();
    }

    public void buildRecyclerView() {
        mRecyclerView = rootView.findViewById(R.id.recyclerview);
        mLayoutManager = new LinearLayoutManager(getContext());
        mAdapter = new EventsAdapter(getActivity(), EventsItemList);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    }

}

If you would like to see the same CardView within the MyListFragment, you could have the MyListFragment contain a RecyclerView, and reuse the same EventsAdapter and EventsViewHolder. The only difference is that rather than populating the adapter with all the children of the "Events" from your database, you would only populate it with the single Event that you want.

Also, since you have made your Event class implement parcelable, you do not need to manually create the bundle when clicking the plus button.

I am assuming you have a single Activity, and you simply want to replace the EventsFragment with the MyListFragment . Checkout the docs for replacing one fragment with another .

Step 1:

Extend your onItemClickListener to look like:

public interface OnItemClickListener {    
    void onItemClick(int position);
    void onPlusButtonClick(int position);
}

and adjust the code in your EventsViewHolder constructor to look like this when the plus button is clicked:

mAddButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (listener != null) {
            // no need to manually create the bundle here
            // you already have all the information you need
            int position = getAdapterPosition();
            if (position != RecyclerView.NO_POSITION) {
                listener.onPlusButtonClick(position);
            }
        }
    }
});

Step 2:

Implement our new method onPlusButtonClick . As per our discussion in the comments, it seems you do not implement this interface anywhere. You can implement it inside the constructor to your EventsAdapter :

public EventsAdapter(Context context, ArrayList<EventsItem> EventsList) {
    mEventsList = EventsList;
    mContext = context;
    mEventsListFull = new ArrayList<>(EventsList); // copy of EventsList for SearchView
    mListener = new OnItemClickListener() {
        @Override
        public void onItemClick() {
            // handle clicking the entire view holder
            // NOTE: inside your EventsViewHolder, it looks like you call this method on the entire itemView. This could 'swallow' the click on the plus button. You may need to adjust your code to handle this.
        }

        @Override
        public void onPlusButtonClick(int position) {
            MyListFragment myListFragment = new MyListFragment();
            Event event = mEventsList.get(position);
            Bundle bundle = new Bundle();
            bundle.putExtra("event", event); // this will work due to implementing parcelable
            myListFragment.setArguments(bundle);

            // use mContext since im assuming we areinside adapter
            // if in an Activity, no need to use context to get the fragment manager
            FragmentTransaction transaction = mContext.getSupportFragmentManager().beginTransaction();

            // Replace the EventsFragment with the MyListFragment
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, myListFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    }
}

Step 3:

Inside your MyListFragment s onCreateView() method:

@Override
public View onCreateView (
    LayoutInflater inflater, 
    ViewGroup container, 
    Bundle savedInstanceState
) {

    Bundle bundle = getArguments();
    Event event = bundle.getExtra("event"); // again, will work due to implementing parcelable

    // from here you should bind to a recycler view, and you can even reuse your adapter like so:
    List<EventsItem> singleEventList = new List<EventsItem>();
    singleEventList.add(event);
    EventsAdapter adapter = new EventsAdapter(getActivity(), singleEventList);

    // be sure to inflate and return your view here...
}

and you should be good to go!

I have left out bits of code here and there for simplicity.. but I hope this is understandable.

As a side note.. in your firebase database listener, it is bad practice to create a new EventsAdapter every single time your data is updated. Instead, you should update the data in the adapter with the new values. Do this by creating a public method inside the adapter such as replaceEvents(List<EventsItem> newEvents) , and inside, replace mEventsList with the new events, then call notifyDataSetChanged() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM