I've been trying to delete data from firebase with an OnClick RecyclerView method, but nothing works. I can't even make my OnClick method works. I have watched videos and tutorials, I've tried so much stuff and nothing helps...
Here is my adapter class:
public class myadapter extends RecyclerView.Adapter<myadapter.myviewholder>{
ArrayList<datamodel> dataholder;
public myadapter(ArrayList<datamodel> dataholder) {
this.dataholder = dataholder;
}
#NonNull
#Override
public myviewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new myviewholder(view);
}
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
}
#Override
public int getItemCount() {
return dataholder.size();
}
class myviewholder extends RecyclerView.ViewHolder{
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
}
}
And my fragment (the one that have the recyclerView):
public class articulos extends Fragment {
private FirebaseUser firebaseUser;
private String uid;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private DatabaseReference myRef;
private Context mContext;
private myadapter myadapter;
RecyclerView recyclerView;
ArrayList<datamodel> dataholder;
public articulos() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment articulos.
*/
// TODO: Rename and change types and number of parameters
public static articulos newInstance(String param1, String param2) {
articulos fragment = new articulos();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_articulos, container, false);
recyclerView = view.findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
myRef = FirebaseDatabase.getInstance().getReference();
dataholder= new ArrayList<>();
getDataFromFirebase();
//datamodel ob1 = new datamodel("Esta nueva", "5000MXN", "wwsad.adasd", "asdasdsa");
// dataholder.add(ob1);
//recyclerView.setAdapter(new myadapter(dataholder));
return view;
}
private void getDataFromFirebase() {
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
uid = firebaseUser.getUid();
Query query = myRef.child("Usuarios").child(uid).child("articulos");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
ClearAll();
for(DataSnapshot snapshot1 : snapshot.getChildren()){
datamodel datamodel = new datamodel();
datamodel.setImageurl(snapshot1.child("imageurl").getValue(String.class));
datamodel.setDescr(snapshot1.child("descripcion").getValue(String.class));
datamodel.setHeader(snapshot1.child("nombre").getValue(String.class));
datamodel.setPrec(snapshot1.child("precio").getValue(String.class));
dataholder.add(datamodel);
}
myadapter = new myadapter(dataholder);
recyclerView.setAdapter(new myadapter(dataholder));
myadapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private void ClearAll(){
if(dataholder != null){
dataholder.clear();
if(myadapter != null){
myadapter.notifyDataSetChanged();
}
}
dataholder = new ArrayList<>();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button mbtnNuevoArticulo = view.findViewById(R.id.btnNuevoArticulo);
mbtnNuevoArticulo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.agregarart);
}
});
}
If anyone can tell me what to do and how to do it, please.. I need it so bad
Try set onclicklistener on viewholder class
class myviewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
CircleImageView CircleImg;
TextView header, descr, price;
public myviewholder(#NonNull View itemView) {
super(itemView);
CircleImg = itemView.findViewById(R.id.circle1);
header = itemView.findViewById(R.id.txtheader1);
descr = itemView.findViewById(R.id.txtdescr1);
price = itemView.findViewById(R.id.txtprecio1);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//do something when clicked
}
}
You can apply onclick listener by using following code :
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
add this code in your onBindViewHolder of Adapter. Just make sure to change the id of holder.
full code :
#Override
public void onBindViewHolder(#NonNull myviewholder holder, int position) {
Glide.with(holder.itemView.getContext()).load(dataholder.get(position).getImageurl()).into(holder.CircleImg);
holder.header.setText(dataholder.get(position).getHeader());
holder.descr.setText(dataholder.get(position).getDescr());
holder.price.setText(dataholder.get(position).getPrec());
holder.header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something.
}
});
}
Create object of view inside your view holder and also initialize button.setOnClickListener(this) inside viewHolder itself and setting on click inside onBinfViewHolder(...)(only in JAVA). In kotlin you just need to set on click method inside onBindViewHolder(...).
Example:
class YourAdapter():RecyclerView.Adapter<YourAdapter.YourViewHolder>() {
class YourViewHolder(view: View):RecyclerView.ViewHolder(view){
val yourButton:Button = view.findViewById(R.id.landingViewBtn)
}
override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
holder.yourButton.setOnClickListener {
//do Something
val intent = Intent(context,nextActivity::class.java)
context.startActivity(intent)
}
}
}
Related
I'm doing my final project that due tomorrow and I only have one thing left to do. But I already lost a lot of time on it. I am creating a recyclerview from a JSON that I obtain through Volley from the Adafruit API and everything is fine, the only thing i need is that when I clicking on the items different Intents are opened. I would greatly appreciate if someone could help me. I have to say that I am working on a fragment and there things are a little different.
The code of my Adapter:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
ArrayList<FeedData> feedData;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData) {
this.feedData = feedData;
}
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v);
}
#Override
public void onBindViewHolder(#NonNull viewholder holder, int position) {
holder.setData(feedData.get(position));
}
#Override
public int getItemCount() {
return feedData.size();
}
public class viewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button btnMisFeeds;
FeedData dataHolder;
public viewholder(#NonNull View itemView) {
super(itemView);
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
public void setData(FeedData feedData) {
dataHolder = feedData;
btnMisFeeds.setText(dataHolder.getName());
}
#Override
public void onClick(View v) {
}
}
The code of my fragment:
public class FragmentInicio extends Fragment {
Button btnControlar, btnAddFeed;
View view;
String temperatura, distancia, infrarrojo, polvo;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private static final String USER_PREFERENCES = "userPreferences";
private static final String TOKEN_KEY = "token";
private RequestQueue nQueue;
ArrayList<AdafruitFeed> adF;
AdafruitFeedAdapter adapterFeed;
RecyclerView recyclerView;
SharedPreferences userPreferences;
SharedPreferences.Editor userEditor;
String token;
public FragmentInicio() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment FragmentInicio.
*/
// TODO: Rename and change types and number of parameters
public static FragmentInicio newInstance(String param1, String param2) {
FragmentInicio fragment = new FragmentInicio();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_inicio, container, false);
btnControlar = view.findViewById(R.id.btnControlar);
btnAddFeed = view.findViewById(R.id.btnAddFeed);
btnControlar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), ControlActivity.class));
}
});
btnAddFeed.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(v.getContext(), AgregarFeedActivity.class));
}
});
nQueue = SingletonRequest.getInstance(view.getContext()).getRequestQueue();
adF = new ArrayList<>();
userPreferences = view.getContext().getSharedPreferences(USER_PREFERENCES, Context.MODE_PRIVATE);
userEditor = userPreferences.edit();
token = userPreferences.getString(TOKEN_KEY, null);
getFeeds();
return view;
}
public void getFeeds() {
String url = "https://cleanbotapi.live/api/v1/feeds";
final JsonObjectRequest getFeeds = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerFeed);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearManager = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(linearManager);
final Gson gson = new Gson();
final AdafruitFeed adafruitFeed = gson.fromJson(response.toString(), AdafruitFeed.class);
adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData());
temperatura = adafruitFeed.getListFeedData().get(0).getName();
distancia = adafruitFeed.getListFeedData().get(1).getName();
infrarrojo = adafruitFeed.getListFeedData().get(2).getName();
polvo = adafruitFeed.getListFeedData().get(3).getName();
recyclerView.setAdapter(adapterFeed);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("errorPeticion", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Authorization", "Bearer " + token);
return headers;
}
};
nQueue.add(getFeeds);
}
}
I trying to create an OnClickListener for everyone of my Adafruit feeds but i cant.
First of all the naming convention of a class should be in "PascalCase".
You need to define an interface that contains a method for your listener and pass it to the constructor of the adapter. And then also pass this listener to your ViewHolder by constructor.
Example:
public class AdafruitFeedAdapter extends RecyclerView.Adapter<AdafruitFeedAdapter.viewholder> {
public interface OnClickListener {
void onClick(FeedData data, int position);
}
ArrayList<FeedData> feedData;
OnClickListener clickListener;
public AdafruitFeedAdapter(ArrayList<FeedData> feedData,OnClickListener clickListener) {
this.feedData = feedData;
this.clickListener = clickListener;
}
...
#NonNull
#Override
public viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feed, parent, false);
return new viewholder(v,clickListener);
}
}
And in your viewholder modify it like below:
...
OnClickListener clickListener;
public viewholder(#NonNull View itemView,OnClickListener clickListener) {
super(itemView);
this.clickListener = clickListener;
btnMisFeeds = itemView.findViewById(R.id.btnMisFeeds);
btnMisFeeds.setOnClickListener(this);
}
...
#Override
public void onClick(View v) {
clickListener.onClick(dataHolder,getBindingAdapterPosition());
}
...
And your fragment:
public class FragmentInicio extends Fragment implements AdafruitFeedAdapter.OnClickListener {
...
#override
public void onClick(FeedData data, int position){
// TODO: implement your intent action
}
...
}
And your adapter: adapterFeed = new AdafruitFeedAdapter(adafruitFeed.getListFeedData(),FragmentInicio.this);
I am programming a music player app and having a problem with a RecyclerView inside a fragment(which connects to tab layout in my main activity) from some reason the RecyclerView is not clickable and when I am pressing an item the app just close.
Can you please help me with that?
I added the fragment class and the adapter class.
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MusicviewHolder> {
private List<Music> songs;
public Resources res;
Context context;
public MusicAdapter(Context context, List<Music> songs) {
String s = String.valueOf(R.drawable.lionkingposter);
songs.add(new Music("jgggug", "Circle of life", "Alton John ", "Lion King",s));
// }
this.songs = songs;//constructor
this.context=context;
}
interface MusicListener {
void onMusicClicked(int position, View view);
// void onDeleteClicked(int position);
}
MusicListener listener;
public void setListener(MusicListener listener) {
this.listener = listener;
}
#Override
public MusicviewHolder onCreateViewHolder(ViewGroup parent, int viewType) {//function design the cell
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell, parent, false);
MusicviewHolder musicviewholder = new MusicviewHolder(view);
return musicviewholder;
}
#Override
public void onBindViewHolder(MusicviewHolder holder, int position) {//this function takes the object and put it in the cell
Music music = songs.get(position);
if (music.getPhoto() != null) {
try {
holder.songImg.setImageResource(Integer.parseInt(music.getPhoto()));
} catch (Exception e) {
//holder.songImg.setImageURI(Uri.parse(music.getPhoto()));
byte[] decodedString = Base64.decode(music.getPhoto(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
holder.songImg.setImageBitmap(decodedByte);
}
} else {
holder.songImg.setImageResource(0);
}
holder.songName.setText(music.getTitle());
holder.movieName.setText(music.getAlbum());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Intent intent=new Intent(context,MediaPlayer.class);
//intent.putExtra("song",position);
//context.startActivity(intent);
Toast.makeText(context,"hello",Toast.LENGTH_SHORT);
}
});
}
#Override
public int getItemCount() {
return songs.size();
}
public class MusicviewHolder extends RecyclerView.ViewHolder {
TextView songName;
TextView movieName;
ImageView songImg;
public MusicviewHolder(#NonNull View itemView) {
super(itemView);
songName = itemView.findViewById(R.id.song_title);
movieName = itemView.findViewById(R.id.movie_title);
songImg = itemView.findViewById(R.id.song_img);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onMusicClicked(getAdapterPosition(), v);
}
}
);
}
}
}
public class SongFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private RecyclerView recyclerview;
private RecyclerView.Adapter myadapter;
private RecyclerView.LayoutManager layoutManager;
View view;
private ArrayList<Music> songs=new ArrayList<>();
private Resources res;
public Context context;
Bundle bundle;
// private ShowSongActivity show;
public SongFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment SongsFragment.
*/
// TODO: Rename and change types and number of parameters
public static SongFragment newInstance(String param1, String param2) {
SongFragment fragment = new SongFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
ArrayList<Music> listTemp = MusicManager.getInstance(getContext()).getMusics();
if (listTemp != null)
songs.addAll((Collection<? extends Music>) listTemp.clone());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_songs, container, false);
recyclerview = (RecyclerView) view.findViewById(R.id.songs_recycler);
MusicAdapter musicAdapter = new MusicAdapter(context,songs);
recyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerview.setAdapter(musicAdapter);
recyclerview.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
return view;
}
}
Try to set onClickListener on the holder into the onBindViewHolder method and when invoke the listener it need to be passed into the setListener(MusicListener listener) method. Something like this:
holder.itemView.setOnClickListener(v -> this.listener.onMusicClicked(position, v);});
In my opinion, it's better to change the interface MusicListener like that:
interface MusicListener {
void onMusicClicked(int position, Music item);
}
And return the clicked item directly like this:
holder.itemView.setOnClickListener(v -> this.listener.onMusicClicked(position, songs.get(position);});
Furthermore, it is better to pass the MusicListener when you create the RecyclerView Adapter because you can easily forget to set it and this will cause the Nullpointer Exception.
I am not sure why you are doing this: String s = String.valueOf(R.drawable.lionkingposter); If you want to keep the Drawable resource in the class make property int (Integer) and keep only the R.drawable.lionkingposter when you set the drawable resource to an ImageView use setBackgroundResource method as described here
I hope this helped ;)
I faced the same problem, Don't know the actual cause of this but I found a working solution.
You need to create a Listener class which implements RecyclerView.OnItemTouchListener
public class MatchClickListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ClickListener clickListener;
public MatchClickListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
#Override
public void onTouchEvent(#NotNull RecyclerView rv, MotionEvent e) {
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
public interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);}
}
Then call it from your fragment or mainactivity where recyler view is created
recyclerView.addOnItemTouchListener(new MatchClickListener
(getActivity(),recyclerView, new MatchClickListener.ClickListener() {
#Override
public void onClick(View view, int position) {
Intent in =new Intent(getActivity(), TournamentPage.class);
startActivity(in);
}
#Override
public void onLongClick(View view, int position) {
}
}));
First, implement the interface in fragment something like that.
public class SongFragment extends Fragment implements MusicAdapter.MusicListener
Second, override the method.
#Override
public void onMusicClicked(int position, View view) {
}
Third, Pass the view to the method. but below the adapter object
musicAdapter.setListener(this::onItemClick);
Here is the complete solution.
public class SongFragment extends Fragment implements MusicAdapter.MusicListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private RecyclerView recyclerview;
private RecyclerView.Adapter myadapter;
private RecyclerView.LayoutManager layoutManager;
View view;
private ArrayList<Music> songs=new ArrayList<>();
private Resources res;
public Context context;
Bundle bundle;
// private ShowSongActivity show;
public SongFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment SongsFragment.
*/
// TODO: Rename and change types and number of parameters
public static SongFragment newInstance(String param1, String param2) {
SongFragment fragment = new SongFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
ArrayList<Music> listTemp = MusicManager.getInstance(getContext()).getMusics();
if (listTemp != null)
songs.addAll((Collection<? extends Music>) listTemp.clone());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_songs, container, false);
recyclerview = (RecyclerView) view.findViewById(R.id.songs_recycler);
MusicAdapter musicAdapter = new MusicAdapter(context,songs);
recyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerview.setAdapter(musicAdapter);
recyclerview.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
musicAdapter.setListener(this::onItemClick);
return view;
}
#Override
public void onMusicClicked(int position, View view) {
// here implement which you want
}
}
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().
I'm trying to figure out how to get data from a clicked item in a RecyclerView to a listview in a Fragment. I can't seem to figure out how to do this, as I can't get my bundle to work.
I've tried various solutions offered here on Stackoverflow, but none of them have worked. I have managed to get the info from the recyclerview, but I am stuck trying to figure out how I can pass it to the fragment. Can someone please help me?
The Adapter class:
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> {
private Context context;
ArrayList<FoodActivity> list;
public FoodAdapter(ArrayList<FoodActivity> list){
this.list = list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item_food, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.foods.setText(list.get(position).getName());
holder.carbo.setText(list.get(position).getCarbohydrates());
holder.protein.setText(list.get(position).getProtein());
holder.fats.setText(list.get(position).getFats());
//Get items from recyclerview when user clicks them. Then send them to FoodFragment
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String foods = list.get(position).getName();
String carbo = list.get(position).getCarbohydrates();
String protein = list.get(position).getProtein();
String fats = list.get(position).getFats();
Toast.makeText(v.getContext(), "test: " + foods, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView foods, carbo, fats, protein;
public ViewHolder(View itemView) {
super(itemView);
carbo = itemView.findViewById(R.id.carbo);
protein = itemView.findViewById(R.id.protein);
fats = itemView.findViewById(R.id.fats);
foods = itemView.findViewById(R.id.food);
}
}
}
The Fragment where the data comes from:
public class TrackingFragment extends Fragment {
DatabaseReference databaseReference;
ArrayList<FoodActivity> list;
RecyclerView recyclerView;
SearchView searchView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tracking, container, false);
databaseReference = FirebaseDatabase.getInstance().getReference().child("foods");
recyclerView = view.findViewById(R.id.rv);
searchView = view.findViewById(R.id.searchFood);
return view;
}
#Override
public void onStart() {
super.onStart();
if(databaseReference != null){
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()){
list.add(ds.getValue(FoodActivity.class));
}
FoodAdapter adapter = new FoodAdapter(list);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getActivity(), databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
if(searchView != null){
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
search(newText);
return true;
}
});
}
}
private void search(String str){
ArrayList<FoodActivity> searchList = new ArrayList<>();
for(FoodActivity object : list){
if(object.getName().toLowerCase().contains(str.toLowerCase())){
searchList.add(object);
}
}
FoodAdapter foodAdapter = new FoodAdapter(searchList);
recyclerView.setAdapter(foodAdapter);
}
}
And the class where it needs to go:
public class FoodFragment extends Fragment {
ImageButton addFood;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food, container, false);
addFood = view.findViewById(R.id.addFood);
addFood.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fr = getFragmentManager().beginTransaction();
fr.replace(R.id.fragment_container, new TrackingFragment());
fr.addToBackStack(null).commit();
}
});
return view;
}
}
The most simple is to add variables you need to your activity, set their values with onClick() and then retrieve data in other fragment:
in activity:
String foods;
public String getFoods() {
return foods;
}
public void setFoods(String foods) {
this.foods = foods;
}
in adapter:
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((YourActivity)getActivity()).setFoods("Any value");
}
});
in destination fragment:
String foods = ((YourActivity)getActivity()).getFoods();
Add an interface to your adapter as follow
public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> {
interface OnClickListener {
void onClick(FoodActivity clickedItem);
}
private OnClickListener mCallback;
private ArrayList<FoodActivity> list;
public FoodAdapter(ArrayList<FoodActivity> list){
this.list = list;
}
public void setOnClickListener(OnClickListener callback) {
mCallback = callback;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item_food, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.foods.setText(list.get(position).getName());
holder.carbo.setText(list.get(position).getCarbohydrates());
holder.protein.setText(list.get(position).getProtein());
holder.fats.setText(list.get(position).getFats());
//Get items from recyclerview when user clicks them. Then send them to FoodFragment
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCallback != null)
mCallback.onClick(list.get(position));
}
});
}
#Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView foods, carbo, fats, protein;
public ViewHolder(View itemView) {
super(itemView);
carbo = itemView.findViewById(R.id.carbo);
protein = itemView.findViewById(R.id.protein);
fats = itemView.findViewById(R.id.fats);
foods = itemView.findViewById(R.id.food);
}
}
}
Android sometimes is a little complicated, when it involves the full stack:
01 RecyclerView Adapter
/** 01. Some Adapter */
public class SomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private WeakReference<Context> mContext;
/** Constructor */
public SomeAdapter(#NonNull Context context) {
this.mContext = new WeakReference<>(context);
}
#NonNull
protected Context getContext() {
return this.mContext.get();
}
/** Call to Activity from within the adapter. */
private void someMethod() {
SomeActivity activity = (SomeActivity) getContext();
synchronized(activity) {activity.showLoginDialog();}
}
}
02 AppCompatActivity
/** 02. Some Activity */
public class SomeActivity extends AppCompatActivity {
#Nullable
private BaseFragment currentFragment = null;
/** Constructor */
public SomeActivity() {}
public void setCurrentFragment(Fragment fragment) {
this.currentFragment = fragment;
}
/** Call to the current Fragment. */
public void someMethod() {
if (currentFragment != null) {
currentFragment.someMethod();
}
}
}
03 Fragment
/** Some Fragment */
public class SomeFragment extends Fragment {
/** Constructor */
public SomeFragment() {}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
((BaseActivity) context).setCurrentFragment(this);
}
#Override
public void onDetach() {
super.onDetach();
((BaseActivity) getActivity()).setCurrentFragment(this);
}
}
To get your data from FoodAdapter to TrackingFragment, you can add TrackingFragment (or an interface it implements, ideally) as a parameter to the FoodAdapter constructor, then use that instance to forward your ViewHolder clicks to TrackingFragment for handling.
To get your data from TrackingFragment to FoodFragment, use the setTargetFragment/onActivityResult pattern for fragment <-> fragment communication. This answer has an example: https://stackoverflow.com/a/13733914/3238938
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