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 MyListFragments 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().
Related
I have a fragment class that contains edit text,button and the recycler view. my recycler view use an xml layout of card view. my card view contains text view and a button(?) to show a pop up after being clicked.
I tried to add the pop up code in my fragment class as I usually do, but it's pointing out that my fragment doesn't have access to recycler's view card view layout. So I tried to add it in my adapter class but I'm getting stuck with getActivty() not getting recognize.
this is what I added in my view holder method inside on click
btnHelp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Popup_FreedomWall popup_freedomWall = new Popup_FreedomWall();
Bundle args = new Bundle();
System.out.println("=================TVFWID==========================");
System.out.println(tvFwId.getText().toString());
System.out.println("=====================TVFWID======================");
//data to get for report - uid(reported,get reported),freedom wall id
args.putString("user", mod_freedomWall.uid_report);
args.putString("reportedPost", tvFwId.getText().toString());
popup_freedomWall.setArguments(args);
popup_freedomWall.show();
popup_freedomWall.show(getActivity().getSupportFragmentManager(), "My Fragment");
}
});
```
<br/>
`Mod_FreedomWall.java` my Fragment
public class Mod_FreedomWall extends Fragment {
RecyclerView recyclerView;
Mod_FreedomWall_UserAdapter myAdapter;
FragmentManager fragmentManager;
ArrayList<Mod_FreedomWall_User> user;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.mod_freedomwall, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.freedomWallPost);
return v;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = (RecyclerView) view.findViewById(R.id.freedomWallPost);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, true);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
btnPost.setOnClickListener(new View.OnClickListener() {
final Date c = Calendar.getInstance().getTime();
final SimpleDateFormat df = new SimpleDateFormat("MM-dd-yy", Locale.getDefault());
final String formattedDate = df.format(c);
final Date currentTime = Calendar.getInstance().getTime();
final DateFormat dateFormat = new SimpleDateFormat("hh.mm aa");
final String dateString = dateFormat.format(new Date());
#Override
public void onClick(View v) {
String message = etPost.getText().toString();
createPost(message, user_name, dateString, formattedDate, level);
myAdapter.notifyDataSetChanged();
etPost.setText("");
}
});
user = new ArrayList<Mod_FreedomWall_User>();
retrievePost();
myAdapter = new Mod_FreedomWall_UserAdapter(this, user);
myAdapter.setListener(new Mod_FreedomWall_UserAdapter.MyListener() {
#Override
public void onItemClicked(String uid, String fwid) {
Popup_FreedomWall popup_freedomWall = new Popup_FreedomWall();
Bundle args = new Bundle();
//just to see if I'm getting data
System.out.println("=================TVFW==========================");
System.out.println(fwid);
System.out.println("=====================TVFW======================");
args.putString("user",uid);
args.putString("reportedPost", fwid);
popup_freedomWall.setArguments(args);
popup_freedomWall.show(getActivity().getSupportFragmentManager(), "pop_upFreedomWall");
}
});
recyclerView.setAdapter(myAdapter);
}
My Adapter
public class Mod_FreedomWall_UserAdapter extends RecyclerView.Adapter<Mod_FreedomWall_UserAdapter.ViewHolder> {
Mod_FreedomWall mod_freedomWall = new Mod_FreedomWall();
private ArrayList<Mod_FreedomWall_User> user;
String freeId,reporterId;
public Mod_FreedomWall_UserAdapter(Mod_FreedomWall context, ArrayList<Mod_FreedomWall_User> list){
user = list;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView ivUserProfile;
TextView tv_message,tv_username,tv_date,tvTime,tvFwId;
Button btnHelp;
public ViewHolder(#NonNull View itemView) {
super(itemView);
btnHelp = (Button) itemView.findViewById(R.id.btnHelp);
ivUserProfile = (ImageView) itemView.findViewById(R.id.ivUserProfile);
tv_message = (TextView) itemView.findViewById(R.id.tv_message);
tv_username = (TextView) itemView.findViewById(R.id.tv_username);
tv_date = (TextView) itemView.findViewById(R.id.tv_date);
tvTime = (TextView) itemView.findViewById(R.id.tvTime);
tvFwId = (TextView) itemView.findViewById(R.id.tvFwId);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btnHelp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("=================TVFWID==========================");
System.out.println(tvFwId.getText().toString());
System.out.println("=====================TVFWID======================");
freeId = tvFwId.getText().toString();
reporterId = mod_freedomWall.uid_report;
}
});
}
});
}
}
#NonNull
#Override
public Mod_FreedomWall_UserAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mod_freedomwall_post,viewGroup,false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull Mod_FreedomWall_UserAdapter.ViewHolder viewHolder, int position) {
viewHolder.itemView.setTag(user.get(position));
viewHolder.tvFwId.setVisibility(View.INVISIBLE);
viewHolder.tv_message.setText(user.get(position).getMessage());
viewHolder.tv_username.setText(user.get(position).getUsername());
viewHolder.tv_date.setText(user.get(position).getDate());
viewHolder.tvTime.setText(user.get(position).getTime());
viewHolder.tvFwId.setText(user.get(position).getFreedomWallId());
viewHolder.ivUserProfile.setImageResource(R.drawable.ic_username_white);
}
#Override
public int getItemCount() {
return user.size();
}
public interface MyListener {
void onItemClicked(String uid,String fwid);
}
MyListener mListener;
public void setListener(MyListener listener) {
mListener = listener;
}
}
Thank you in advance!
From what I understand you have two possible approaches to this problem.
Send a Context with in your Adapter's constructor and replace the part where you need the "getActivity()" with that context you passed through (obv via a variable in your Adapter).
Use an Interface approach.
I never like the Context style, so I'll give you an example for an Interface approach.
In your Adapter:
public abstract class YourAdapter extends ...<> {
public interface MyListener {
void onItemClicked(String someData); //can change this variable to whatever is needed, if any.
}
MyListener mListener;
...
Then let the onClickListener of the button call the Interface function you just created instead of trying to make a popup directly:
btnHelp.setOnClickListener(v -> onItemClicked("this is my data i pass through");
Then add a function to your Adapter to set the listener (or add it as argument in the constructor, whatever you want):
public void setListener(MyListener listener) {
mListener = listener;
}
And implement the listener in your Fragment:
adapter.setListener(new YourAdapter.MyListener() {
#Override
public void onItemClicked(String myData) {
//create your popup and simply call getActivity() since this is inside the Fragment
}
});
--- Your Fragment ---
public class Mod_FreedomWall extends Fragment {
RecyclerView recyclerView;
RecyclerView.Adapter myAdapter; //<-- 1 *remove*
RecyclerView.LayoutManager layoutManager; // obsolete, can be deleted. You make a local variable later on.
Mod_FreedomWall_UserAdapter adapter; // <-- 2 *rename to myAdapter*
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.mod_freedomwall, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.freedomWallPost);
return v;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = (RecyclerView) view.findViewById(R.id.freedomWallPost);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, true);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
// You call a function of `adapter` here, but adapter hasn't been
// properly initialised yet, it's null so far, so that won't go well.
// *rename adapter to myAdapter and move this part down*
adapter.setListener(new Mod_FreedomWall_UserAdapter.MyListener() {
#Override
public void onItemClicked(String uid, String fwid) {
Popup_FreedomWall popup_freedomWall = new Popup_FreedomWall();
Bundle args = new Bundle();
//data to get for report - uid(reported,get reported),freedom wall id
args.putString("user",uid);
args.putString("reportedPost", fwid);
popup_freedomWall.setArguments(args);
popup_freedomWall.show(getActivity().getSupportFragmentManager(), "My Fragment");
}
});
btnPost.setOnClickListener(new View.OnClickListener() {
final Date c = Calendar.getInstance().getTime();
final SimpleDateFormat df = new SimpleDateFormat("MM-dd-yy", Locale.getDefault());
final String formattedDate = df.format(c);
final Date currentTime = Calendar.getInstance().getTime();
final DateFormat dateFormat = new SimpleDateFormat("hh.mm aa");
final String dateString = dateFormat.format(new Date());
#Override
public void onClick(View v) {
String message = etPost.getText().toString();
createPost(message, user_name, dateString, formattedDate, level);
myAdapter.notifyDataSetChanged();
etPost.setText("");
}
});
user = new ArrayList<Mod_FreedomWall_User>();
retrievePost();
//Here you initialise your adapter
myAdapter = new Mod_FreedomWall_UserAdapter(this, user);
//you can move your `myAdapter.setListener` to this spot.
recyclerView.setAdapter(myAdapter);
}
Well, you declared two adapters but only really used one. Seems a bit mixed up.
To-do;
Scrap one of the adapters (number 1). Then the simplest way is to rename adapter at number 2 to myAdapter and also change the adapter at adapter.setListener to myAdapter.setListener(....
Then move that myAdapater.setListener(... to a place below myAdapter = new Mod_FreedomWall_UserAdapter(this, user); since that is where you actually initialise your adapter. Before that point you can't safely call the your adapter's functions.
I am having problems updating my RecyclerView with new data. If I press a confirmation button on a CardView in the first tab, the card should get added to the second tab but it won't update it there until I rotate the screen. I get the data for the card from reading a text file. Please advise me how to call the notifyDataSetChange method after I have added the new data to my text file. I have tried everything and all I get is NullPointerExceptions. The RecyclerViews are in fragments and I use FragementStatePagerAdapter.
I'll put some of my classes here. Ask if you need more information.
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
SectionsPagerAdapter.java
public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
private ViewPager viewPager;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
CompletedFragment.java
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed");
recyclerView.setAdapter(adapter);
return view;
}
}
}
EDIT:
Added the code for the second fragment, which is the one that should be updated after the onClick at RecyclerViewHolder-class.
You have to add a function in your adapter for adding data:
public void addData(String title, String desc, String point, String date) {
this.mListTitle.add(title);
this.mListDesc.add(desc);
this.mListPoints.add(point);
this.mListDates.add(date);
notifyDataSetChanged();
}
If you want to enable animations call notifyItemInserted() instead of notifyDataSetChanged();
It is important that you add a String to every list because in your onBindViewHolder() you get the item to display from every list with list.get(position). Otherwise you'll get a IndexOutOfBoundsException.
You can create an interface and use as a callback. Send it as a parameter of the RecyclerViewAdapter and then to your RecyclerViewHolder. When the item should be added you call the callback that will get you back to your fragment. There you can read the file again and call notifyDataSetChanged.
I know i explain pretty bad so i will try to change your code so that it does what i said:
this will be your RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
private Runnable callback;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) {
//add the callback here(Runnable) and save it into a local variable
this.callback=callback;
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
//call the callback
callback.run();
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
And this will be your fragment:
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
#Override
public void run() {
//here read the list again and call notifyDataSetChanged on your recycler
}
});
);
recyclerView.setAdapter(adapter);
return view;
}
}
}
Hope it helps and it works for you. If i did anything wrong, let me know, i can't run the code right now so...
edited, i forgot to add code in the callback
Aim
Allowing the Users to access their selected Group Chat. Once the user clicks on the Group Chat name, they will be entered into that Group Chat.
Database Tree
As shown in the Database Tree, the Currently Signed In user will be shown a list of Group Chat names that have been created.
I have an Admin Account to create these Group Chats for the users.
The Android, Asia, and Europe group chats that are seen within the Database ARE NOT fixed variables. They are names. A newly Group Chat name could be "Earth".
Therefore there is no way of calling it by a variable other than calling it by the Node itself.
Screenshot of Application
List of Group Chats 2. Entering a Group Chat
Flow of Activities
GroupFragment ---> Chat Activity
GroupFragment <--- Chat Activity
Flow of Application
User--->LoginActivity--->UserActivity--->GroupFrag--->GroupChatActivity
At the (GroupFrag--->GroupChatActivity) The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
The user must select a Group Chat name within the GroupFrag to enter the GroupChatActivity
Description
The users will be able to select a Group Chat name (from GroupFragment) and the app will bring the user into the Group Chat itself (into Chat Activity). The User will be able to go back to the GroupFragment and select another desired Group.
(Group Chat names are NOT FIXED -- They're not a node that can be called from)
Problem
I am unable to select the Group Chat names after it was prompt within the Fragment, which will then bring me to the Group Chat.
Group Fragment
#Override
public void onStart() {
super.onStart();
class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.MyHolder> {
ArrayList<String> list;
public GroupAdapter(ArrayList<String> list) {
this.list = list;
}
#Override
public GroupAdapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
public MyHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
jGroupsDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ArrayList<String> groupChatNames = new ArrayList<>();
for (DataSnapshot child : dataSnapshot.getChildren()) {
groupChatNames.add(child.getKey());
}
GroupAdapter adapter = new GroupAdapter(groupChatNames);
jGroupChatList.setAdapter(adapter);
//I'm not sure where to write a code for userID
//final String usersID = getRef(position).getKey();
// When the user clicks on one of the group chat names, he/she will be sent to the Chat Activity
jGroupChatList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Chat Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
jGroupChatName = getIntent().getExtras().get("groupChatName").toString();
jUserID = getIntent().getExtras().get("usersID").toString();
jUserName = getIntent().getExtras().get("usersName").toString();
jUserNeighbourhood = getIntent().getExtras().get("neighbourhood").toString();
jChatRoot = FirebaseDatabase.getInstance().getReference().child(jGroupChatName);
jChatToolbar = (Toolbar) findViewById(R.id.allUSersToolBar);
setSupportActionBar(jChatToolbar);
getSupportActionBar().setTitle(jGroupChatName); // Show the name of the selected group name
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Additional Comments
Online Tutorial
I have watched an Android Firebase Group Chat tutorial on youtube. The link is https://www.youtube.com/watch?v=wVCz1a3ogqk. But it does not provide some the features/ functions whic I am trying to implement.
Linked Question
Android - Firebase - Prompting Group Chat Names
Future Implementations
For future implementations, I would like to send and retrieve the messages and prompt it into the group chat for the users to view like a real group chat. But of course, I will leave that for another Question.
You can update your adapter and viewholder implementation as follows:
public class Adapter extends RecyclerView.Adapter<Adapter.MyHolder> {
Context context;
ArrayList<String> list;
public Adapter(Context context, ArrayList<String> list) {
this.context = context;
this.list = list;
}
#Override
public Adapter.MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_groups, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.setText(list.get(position));
}
#Override
public int getItemCount() {
return list.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
String groupName = list.get(getAdapterPosition());
Intent intentUserProfile = new Intent(context, MainActivity.class);
intentUserProfile.putExtra("groupChatName", groupName);
// If fixed, you should pass these values to adapter's constructor
// intentUserProfile.putExtra("neighbourhood", neighbourhood);
// intentUserProfile.putExtra("usersName", usersName);
// intentUserProfile.putExtra("usersID", usersID);
context.startActivity(intentUserProfile);
}
};
public MyHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(onClickListener);
nameTextView = (TextView) itemView.findViewById(R.id.groupChatNameTxt);
}
public void setText(String groupName) {
nameTextView.setText(groupName);
}
}
}
You also have to update this line in your GroupFragment:
GroupAdapter adapter = new GroupAdapter(getActivity(), groupChatNames);
This is another solution that you can implement inside your fragment so that you can put extras in intent (actually modified from your former question):
#Override
public void onStart() {
super.onStart();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference groupChatsRef = rootRef.child("Group Chats");
FirebaseRecyclerAdapter<String, GroupChatViewHolder> chatAdapter = new FirebaseRecyclerAdapter<String, GroupChatViewHolder>(
String.class,
R.layout.layout_groups,
GroupChatViewHolder.class,
groupChatsRef) {
protected void populateViewHolder(GroupChatViewHolder viewHolder, String model, int position) {
final String groupChatName = this.getRef(position).getKey();
viewHolder.setName(groupChatName);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName", groupChatName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
startActivity(intentUserProfile);
}
});
}
};
jGroupChatList.setAdapter(chatAdapter);
}
Note that it handles your string-string group chat entries in your DB as key-value pairs.
public class group_name_list_adapter extends RecyclerView.Adapter<group_name_list_adapter.ViewHolder> {
private List< group_name_list> listItems;
private Context context;
OnItemClickListener onItemClickListener;
public group_name_list_adapter(List<group_name_list> listItems, Context context) {
this.listItems = listItems;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_name_list, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
group_name_list listItem = listItems.get(position);
holder.txtTitle.setText(listItem.getTxtTitle());
holder.txtTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onGroupNameClick(position);
}
});
}
#Override
public int getItemCount() {
return listItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtTitle;
public ViewHolder(View itemView) {
super(itemView);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener{
void onGroupNameClick(int position);
}
}
public class group_name_list {
private String txtTitle;
public group_name_list(String txtTitle) {
this.txtTitle = txtTitle;
}
public String getTxtTitle() {
return txtTitle;
}
}
public class ChatActivity implements group_name_list_adapter.OnItemClickListener
private RecyclerView recyclerGroupName;
private group_name_list_adapter groupNameAdapter;
private List<group_name_list> group_name_List;
private List<String> groupNameKeyList; //This is optional – this is used if you wanted the group chats to have the same name instead of overwriting the groupchat when creating.
Inside your Firebase call:
group_name_List.removeAll(group_name_List t);
groupNameKeyList.removeAll(groupNameKeyList);
//Depending on your firebase reference. This could just be dataSnapshot.getChildren()
for (DataSnapshot child : dataSnapshot.child("Group Chats").getChildren()){
if (!child.getKey().equals(null)){
groupNameKeyList.add(child.getKey().toString()); //Again this is optional
}
group_name_list newGroupList = child.getValue();
);
groupNameList.add(newGroupList);
}
recyclerGroupName.setAdapter(groupNameAdapter);
gLayoutAttribute = new GridLayoutManager(getActivity(), 1);
recyclerGroupName = (RecyclerView) rootView.findViewById(R.id.recyclerGroupName);
recyclerGroupName.setHasFixedSize(true);
recyclerGroupName.setLayoutManager(new LinearLayoutManager(this.getContext()));
recyclerGroupName.setLayoutManager(gLayoutAttribute);
#Override
public void onAttributeClick(int position) {
Intent intentUserProfile = new Intent(getActivity(), ChatActivity.class);
intentUserProfile.putExtra("groupChatName",groupName);
intentUserProfile.putExtra("neighbourhood", neighbourhood);
intentUserProfile.putExtra("usersName", usersName);
intentUserProfile.putExtra("usersID", usersID);
intent.putExtra("name", groupList.get(position).toString());
//intent.putExtra("name", groupListKeyList.get(position).toString()); this is your optional key
startActivity(intentUserProfile);
}
Try according to this
Suppose you've created 5 user's in FirebaseDatabasewith different UID's
In this step you have to get all user's from Firebase and display it in RecyclerView
In Recyclerview's adapter class in onBindViewHolder' you have to do like add and remove` users from list which you generated at the time creating group.
In this step you've to search firebaseDatabase user's Uid which is currently logged in and if your UID is matched found in any Group then you need to get the Group-name .
Happy to help you
I initially followed the accepted answer in this previously posted question about how to save and restore the layout manager for a RecyclerView.
I have my RecyclerView in Activity B. [Note: Activity A will launch Activity B, transferring data via an intent.]
When a user clicks a viewholder in Activity B, Activity C is launched. Once Activity C is closed and destroyed, Activity B is visible, and I can see all of my data restored in the RecyclerView.
The Problem:
However, if I navigate away from my app (ie pressing the Home Key), it is pushed to the background. When my app is reinstated, onCreate() is called again. The LayoutManager's state is being saved, however none of my data is showing in the RecyclerView.
I can tell my LayoutManager state was saved after some debugging. It shows up as this when onCreate() is called again after reinstating the app from the background:
Saved Instance State = Bundle[{ActivityB - Linear Layout State=android.support.v7.widget.LinearLayoutManager$SavedState#6358f8f, android:viewHierarchyState=Bundle[mParcelledData.dataSize=1296]}]
I am not sure how to fix this after hours of trying.
My Code:
public class ActivityB extends AppCompatActivity {
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
private Parcelable linearLayoutState;
private RecyclerAdapter adapter;
private Button more;
private String id;
private List<VideoItem> list;
private List<VideoItem> newList;
private final String LINEARLAYOUT_STATE_KEY = "Activity B - Linear Layout State";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blayout);
// Retrieving data from Activity A
Intent intent = getIntent();
Bundle bundle = intent.getBundleExtra("bundle");
someClass.innerClass class = bundle.getParcelable("data");
id = class.getID();
list = class.getList();
newList = new ArrayList<>();
// Instantiating Recycler View
recyclerView = (RecyclerView)findViewById(R.id.activityb_recyclerview);
recyclerView.setNestedScrollingEnabled(false);
linearLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new RecyclerAdapter();
recyclerView.setAdapter(adapter);
moreButton = (Button)findViewById(R.id.activityb_more);
moreButton.setOnClickListener(new fetchMoreClickListener());
}
#Override
public void onResume(){
if (linearLayoutState != null) {
linearLayoutManager.onRestoreInstanceState(linearLayoutState);
} else {
// If no layout state is found, I need to populate my
// adapter.
// Here I am simply cloning my list again, to keep the original
// list intact. generateSubset() removes items from the cloned list
// to create a smaller subset that is added to the adapter.
for (ListItem item : list){
newList.add(new ListItemi(item));
}
adapter.addItems(generateSubset(0));
}
super.onResume();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
linearLayoutState = linearLayoutManager.onSaveInstanceState();
outState.putParcelable(LINEARLAYOUT_STATE_KEY, linearLayoutState);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
linearLayoutState = savedInstanceState.getParcelable(LINEARLAYOUT_STATE_KEY);
}
The other Activity LifeCycle Methods have not been overridden. I am not getting any error messages. Just my data stored in my viewholders is no longer showing in the RecyclerView.
Edit 1:
Here is my RecyclerAdapter code:
public class RecyclerAdapter extends RecyclerView.Adapter{
private static Date now;
private List list;
public static class ItemHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private Context context;
private String key;
private Bundle itemBundle;
private SimpleDraweeView photo;
private TextView title;
public ItemHolder(Context context, View view){
super(view);
this.context = context;
this.key = null;
this.itemBundle = null;
photo = (SimpleDraweeView)view.findViewById(R.id.itemholder_photo);
title = (TextView)view.findViewById(R.id.itemholder_title);
view.setOnClickListener(this);
}
public void bindData(Item item){
if (key == null){ key = item.getID(); }
if (itemBundle == null){
itemBundle = new Bundle();
itemBundle.setClassLoader(Item.class.getClassLoader());
itemBundle.putParcelable("data", item);
}
photo.setImageURI(Uri.parse(item.getPhotoURL()));
}
#Override
public void onClick(View view) {
Intent intent = new Intent(context, ActivityB.class);
intent.putExtra("bundle", itemBundle);
context.startActivity(intent);
}
}
public RecyclerAdapter(){
this.list = new ArrayList<>();
this.now = new Date();
}
public RecyclerAdapter(ArrayList<VideoItem> list){
this.list = list;
this.now = new Date();
this.notifyItemRangeInserted(0, list.size());
}
#Override
public RecyclerAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View recyclerItem = LayoutInflater.from(context)
.inflate(R.layout.itemholder_item, parent, false);
return new ItemHolder(context, recyclerItem);
}
#Override
public void onBindViewHolder(RecyclerAdapter.ItemHolder holder, int position) {
Item item = list.get(position);
holder.bindData(item);
}
private static Date getNow(){ return now; }
private static void updateNow(){ now = new Date(); }
#Override
public int getItemCount() {
return list.size();
}
public void addItem(Item item){
list.add(item);
this.notifyItemInserted(list.size() - 1);
}
public void addItems(ArrayList<Item> items){
int oldSize = list.size();
list.addAll(items);
this.notifyItemRangeInserted(oldSize, items.size());
}
}
Try changing your onResume() method to look something like the following:
#Override
public void onResume(){
super.onResume();
if (linearLayoutState != null) {
linearLayoutManager.onRestoreInstanceState(linearLayoutState);
}
// Here comes the code to populate your data.
// I'm not sure how you do this, so I just copy/paste your code
for (ListItem item : list){
newList.add(new ListItemi(item));
}
// Now instatiate and add the adapter to the RecyclerView
adapter = new RecyclerAdapter(newList);
recyclerView.setAdapter(adapter);
}
}
I have a question about passing clicked cardview data to activity, and here the full story :
I have an Activity called "Details", which contains 2 TextViews in it's layout, Title & Description .
I have setup a fragment ( tab_1 ) which contain the recyclerview codes and the the items data, each item of those contain : title & description .
What i want :
When the user click the item, it will open the Details Activity, and change Details layout title, with clicked item title, and the same for description .
I've manged to create the other activity as an example, and made intent to start it, plus adding "addOnTouchlistener" thanks to Stackoverflow, i've found the way to make it .
So, how to make this alive? I've tried many ways of the available answers on Stackoverflow, but all of them not working, or not related to my request .
Here are my files :
itemsdata.java :
public class itemsdata {
int CatPic;
String title;
String Descr;
int Exapnd;
int expand_no;
tab_1.java ( fragment )
public class tab_1 extends Fragment implements SearchView.OnQueryTextListener {
private RecyclerView mRecyclerView;
public RecyclingViewAdapter adapter;
private Activity context;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.tab_1, container, false);
mRecyclerView = (RecyclerView)layout.findViewById(R.id.recycler_view);
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener
(getContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Intent i = new Intent(view.getContext(), DetailsActivity.class);
view.getContext().startActivity(i);
}
}));
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new RecyclingViewAdapter(getActivity(),Listed());
mRecyclerView.setAdapter(adapter);
return layout;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
}
#Override
public boolean onQueryTextChange(String query) {
final List<itemsdata> filteredModelList = filter(Listed(), query);
adapter.animateTo(filteredModelList);
mRecyclerView.scrollToPosition(0);
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
return true;
}
private List<itemsdata> filter(List<itemsdata> models, String query) {
query = query.toLowerCase();
final List<itemsdata> filteredModelList = new ArrayList<>();
for (itemsdata model : models) {
final String text = model.title.toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
public List<itemsdata> Listed()
{
//Titles Strings
String sys_title1 = getString(R.string.system_item_title_1);
String sys_title2 = getString(R.string.system_item_title_2);
String sys_title3 = getString(R.string.system_item_title_3);
//Description Strings
String sys_descr1 = getString(R.string.system_item_desc_1);
String sys_descr2 = getString(R.string.system_item_desc_2);
String sys_descr3 = getString(R.string.system_item_desc_3);
//Adding New Cards
List<itemsdata> data = new ArrayList<>();
//Categories Icons New Items ** Make It The Same
int[] icons = {
R.drawable.facebook_icon ,
R.drawable.twitter_icon ,
R.drawable.twitter_icon
};
//Expand Button New Items
int[] expandbutton = {
R.drawable.expanded ,
R.drawable.expanded ,
R.drawable.expanded
};
//UnExpand Button New Items
int[] unexpandbutton = {
R.drawable.ca_expand ,
R.drawable.ca_expand ,
R.drawable.ca_expand
};
//Titles New Items
String[] titles = {
sys_title1 ,
sys_title2 ,
sys_title3
};
//Description New Items
String[] Description = {
sys_descr1 ,
sys_descr2 ,
sys_descr3
};
for(int i = 0;i<titles.length && i < icons.length && i < Description.length && i < unexpandbutton.length && i < expandbutton.length ; i++)
{
itemsdata current = new itemsdata();
current.CatPic = icons[i];
current.title = titles[i];
current.Descr = Description[i];
current.expand_no = unexpandbutton[i];
current.Exapnd = expandbutton[i];
data.add(current);
}
return data;
}
}
Details Activity :
public class DetailsActivity extends AppCompatActivity{
TextView title;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
title = (TextView)findViewById(R.id.details_title);
}
EDIT : I've made it, i have added a button which open the fragment, and passed the data, in the Adapter, but i want it via tab_1.java, not the Adapter, i mean i want to click on the item to open the fragment, not on a button, here a snap from my Adapter code ( i've added it in OnBindViewHolder )
I've setup a OnClick and implemented the Vew.setOnClick ..etc, but when i click the item, nothing happen.
#Override
public void onBindViewHolder(final MyRecycleViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(),DetailsActivity.class);
v.getContext().startActivity(i);
}
});
//Referencing Data
final itemsdata currentobject = mdata.get(position);
//Referencing Items
holder.ProbTitle.setText(currentobject.title);
holder.ProbDescr.setText(currentobject.Descr);
holder.CategoryPic.setImageResource(currentobject.CatPic);
holder.ExpandButton.setImageResource(currentobject.Exapnd);
holder.ExpandNoButton.setImageResource(currentobject.expand_no);
//What Happen When You Click Expand Button .
holder.ExpandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(), DetailsActivity.class);
i.putExtra("TitleKey",holder.ProbTitle.getText().toString());
v.getContext().startActivity(i);
}
}
);
public static class MyRecycleViewHolder extends RecyclerView.ViewHolder
{
SwipeLayout swipeLayout;
//Defining Items .
TextView ProbTitle;
ImageButton ExpandButton;
TextView ProbDescr;
ImageButton ExpandNoButton;
ImageView CategoryPic;
/*
TextView Card_Star;
TextView Card_UnStar;
*/
TextView Card_Share;
//Referencing Resources
public MyRecycleViewHolder(final View itemView) {
super(itemView);
ProbTitle = (TextView) itemView.findViewById(R.id.prob_title);
CategoryPic = (ImageView) itemView.findViewById(R.id.cat_pic);
ProbDescr = (TextView) itemView.findViewById(R.id.prob_descr);
ExpandButton = (ImageButton) itemView.findViewById(R.id.expand_button);
ExpandNoButton = (ImageButton) itemView.findViewById(R.id.expand_no_button);
/*
Card_Star = (TextView) itemView.findViewById(R.id.card_star);
Card_UnStar = (TextView) itemView.findViewById(R.id.card_unstar);
*/
Card_Share = (TextView) itemView.findViewById(R.id.card_share);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
}
create an Interface inside your adapter containing methods. And while implementing your Adapter, those methods will be implemented in your activity and you can perform whatever action you want.
public class Adapter extends RecyclerView.Adapter<MyRecycleViewHolder> {
public interface Callbacks {
public void onButtonClicked(String titleKey);
}
private Callbacks mCallbacks;
public Adapter() {
}
#Override
public MyRecycleViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_details, null);
return new MyRecycleViewHolder(v);
}
#Override
public void onBindViewHolder(final MyRecycleViewHolder holder, final int i) {
holder.ExpandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCallbacks != null) {
mCallbacks.onButtonClicked(holder.ProbTitle.getText().toString());
}
}
});
}
#Override
public int getItemCount() {
return;
}
public void setCallbacks(Callbacks callbacks) {
this.mCallbacks = callbacks;
}
}
you may try do this on your onItemClick()
Intent i = new Intent(view.getContext(), DetailsActivity.class);
i.putExtra("title", yourTitle);
i.putExtra("description", yourDescription);
view.getContext().startActivity(i);
and when oncreate in your DetailActivity,do this
String title = getIntent().getStringExtra("title");
String description = getIntent().getStringExtra("description");
so you can pass title and description to DetailActivity
IMO, you implement setOnClickListener inside Adapter of RecyclerView. You can refer to my following sample code, then apply its logic to your code. Hope it helps!
public class MyRVAdapter extends RecyclerView.Adapter<MyRVAdapter.ViewHolder> {
Context mContext;
List<String> mStringList;
public MyRVAdapter(Context mContext, List<String> mStringList) {
this.mContext = mContext;
this.mStringList = mStringList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView textView1 = (TextView) v.findViewById(R.id.textView1);
TextView textView2 = (TextView) v.findViewById(R.id.textView2);
Bundle bundle = new Bundle();
bundle.putString("key1", textView1.getText().toString());
bundle.putString("key2", textView2.getText().toString());
passToAnotherActivity(bundle);
}
});
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// do something...
}
#Override
public int getItemCount() {
if (mStringList != null) {
return mStringList.size();
}
return 0;
}
private void passToAnotherActivity(Bundle bundle) {
if (mContext == null)
return;
if (mContext instanceof MainActivity) {
MainActivity activity = (MainActivity) mContext;
activity.passToAnotherActivity(bundle); // this method must be implemented inside `MainActivity`
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public ViewHolder(View itemView) {
super(itemView);
// do something...
}
#Override
public void onClick(View v) {
}
}
}
First of all make your "itemsdata" object to implement Parcelable. You can check it here . In your onItemClick method you pass the object to your Details activity using intent.putExtra("key",listOfDataItems.get(position));
In your DetailsActivity you can get your custom object with getParcelable("key")
All above methods worked, but kinda long, so this one worked for me :
Cardview cardview;
cardView = (CardView)itemView.findViewById(R.id.cv);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent (view.getContext(), DetailsActivity.class);
i.putExtra("TitleKey",ProbTitle.getText().toString());
i.putExtra("DescrKey",ProbDescr.getText().toString());
view.getContext().startActivity(i);
}
});
And in Details.java :
TextView title;
TextView Descr;
title = (TextView)findViewById(R.id.details_title);
Descr = (TextView)findViewById(R.id.details_descr);
String titleresult = result.getExtras().getString("TitleKey");
String Descrresult = result.getExtras().getString("DescrKey");
title.setText(titleresult);
Descr.setText(Descrresult);