I have two arraylist and I want to display the data in both list in the same recyclerview. My code looks like this.
My adapter
class NotificationAdapter extends RecyclerView.Adapter<NotificationViewHolder> {
//..
List<Notification> notifList = new ArrayList<>();
List<AcceptedInvitation> acceptedInvitations = new ArrayList<>();
Context context;
LayoutInflater inflater;
public NotificationAdapter(Context context){
this.context = context;
inflater = LayoutInflater.from(context);
}
public void addNotification(Notification notification){
notifList.add(notification);
notifyDataSetChanged();
notifyItemInserted(notifList.size());
}
public void addAcceptedInvitation(AcceptedInvitation invitation){
acceptedInvitations.add(invitation);
notifyDataSetChanged();
notifyItemInserted(acceptedInvitations.size());
}
#Override
public NotificationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.rv_notifications, parent, false);
NotificationViewHolder holder = new NotificationViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final NotificationViewHolder holder, int position) {
String user1= null;
String user2= null;
if(position < notifList.size()){
user1= notifList.get(position).getUserName();
}else {
user2= acceptedInvitations.get(position).getUserName();
}
#Override
public int getItemCount() {
return notifList.size() + acceptedInvitations.size();
}
}
RecyclerView ViewHolder
public class NotificationViewHolder extends RecyclerView.ViewHolder {
//..
TextView userName;
public NotificationViewHolder(View itemView) {
super(itemView);
userName = (TextView) itemView.findViewById(R.id.display_name);
}
}
I have an error in onBindViewHolder() part. I'm using Firebase in retrieving the data by the way.
Main Activity(loadData() is called when the activity starts)
public void loadData(){
//..
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference().child("users").child(key).child("invitations");
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Notification notification = dataSnapshot.getValue(Notification.class);
adapter.addNotification(notification);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
DatabaseReference invitationRef = database.getReference().child("users").child(key).child("acceptedInvitations");
invitationRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
AcceptedInvitation acceptedInvitation = dataSnapshot.getValue(AcceptedInvitation.class);
Toast.makeText(getActivity(), dataSnapshot.getValue().toString(), Toast.LENGTH_LONG).show();
adapter.addAcceptedInvitation(acceptedInvitation);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I can already retrieve the data from invitations and acceptedInvitations json-array, but i have an error when I tried to populate the data from the acceptedInvitations, basically when I call "addAcceptedInvitation(acceptedInvitation)".
Error.
threadid=1: thread exiting with uncaught exception (group=0x41a81c80)
I assume you want to combine the Notification data and AcceptedInvitation data. Please note that when you call two Firebase Database call, the second one will be executed after the first one is finished. So it is okay to use this code below (because if not, this code is risky).
First, remove notifyItemInserted() inside addNotification and addAcceptedInvitation as it is no use if it's called directly after notifyDataSetChanged(). But if you prefer keeping notifyItemInserted() and removing notifyDataSetChanged(), it will be more complicated.
Then lets point out what went wrong. When you call notifyDataSetChanged(), your adapter will refresh all of its item. In your getItemCount(), you mention that your adapter have (notifList.size() + acceptedInvitations.size()). So if you have 3 notifList and 2 acceptedInvitations, your adapter will refresh from its first value to (3+2) fifth value.
Knowing that, the onBindViewHolder will be called with position value from 0 to 4 (0 is first, 4 is fifth). Look at the code:
#Override
public void onBindViewHolder(final NotificationViewHolder holder, int position) {
...
if(position < notifList.size()){
user1 = notifList.get(position).getUserName();
} else {
user2 = acceptedInvitations.get(position).getUserName();
}
}
Notice that when position is 0 or 1 or 2, it is fine because its executing notifList.get(position) and notifList on those index is exist. But when position is 3, its executing acceptedInvitations.get(position) that will triger error because acceptedInvitations only have value on index 0 and 1 not in 3
After understanding that, your code should look like this:
#Override
public void onBindViewHolder(final NotificationViewHolder holder, int position) {
...
if(position < notifList.size()){
user1 = notifList.get(position).getUserName();
} else {
user2 = acceptedInvitations.get(position - notifList.size()).getUserName();
}
}
Hope this help :)
Related
I want data from firebase to be printed out in recyclerview list.
The loop is correct but, it didn't replace my data.
This is from the track_record code.
private void readData(){
reference = FirebaseDatabase.getInstance().getReference("FireAlarm");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
Data data = snapshot.getValue(Data.class);
dataList.add(data);
}
recordAdapter = new RecordAdapter(track_record.this,dataList);
recyclerView.setAdapter(recordAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
this is from my adapter
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_data,parent,false);
return new RecordAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Data data = dataList.get(position);
holder.outputData.setText(data.getAlarm());
}
#Override
public int getItemCount() {
return dataList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView outputData;
public ViewHolder(View itemView){
super(itemView);
outputData = itemView.findViewById(R.id.dataFetch);
}
}
this is from xml the data should be replaced
<TextView
android:id="#+id/dataFetch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="data"
android:textSize="20dp"
android:textAlignment="center"
android:background="#F5B6B6"
android:textColor="#000000"/>
this is my database
this is current output
You must add child value event listener to FireAlarm, the listener will be triggered as soon as it is attached to a DatabaseReference object (in your code the object is reference) by calling onChildAdded() method and triggered each time data in the child added, removed, changed,...
Your readData should be rewritten as below:
reference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Data data = (Data) dataSnapshot.getValue(Data.class);
dataList.add(data);
//then notify data changed
recordAdapter.notifyDataSetChange();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Data data = (Data) dataSnapshot.getValue(Data.class);
//then find position of `data` in datalist to change some information of the item at position.
//then notify data changed
recordAdapter.notifyDataSetChange();
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
Data data = (Data) dataSnapshot.getValue(Data.class);
//then find data in datalist to remove, after removed, notify data set changed
recordAdapter.notifyDataSetChange();
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
You should use addChildEventListener instead of addValueEventListener, and write the code inside onChildAdded.
You can find the explanation from documentation:
When working with lists, your application should listen for child
events rather than the value events used for single objects.
I have a lists in which each row will consist of multiple chips.
On each row I can able to type anything and suggestion would come and if I select any of the suggestion then chip will be added in same row just like auto complete text view.
I tried many things like adding views dynamically in linear layout and others but not getting the solution.
I appreciate If anyone knows how to do it.
This is my code run succesfully ;
package com.example.masterappinc;
public class Judgedetailadapter extends RecyclerView.Adapter {
Judgedetailreturn judgedetailreturn;
List<Judgedetailreturn> judgelist;
Context context;
public Judgedetailadapter(List<Judgedetailreturn> judgelist, Context context) {
this.judgelist = judgelist;
this.context = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater =LayoutInflater.from(context);
View view= inflater.inflate(R.layout.cardviewjudgedetail,parent,false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
final Judgedetailreturn judgedetailreturn1=judgelist.get(position);
holder.name.setText(judgedetailreturn1.getName());
String ide = judgedetailreturn1.getId();
holder.id.setText(ide);
holder.company.setText(judgedetailreturn1.getCompany());
holder.mobno.setText(judgedetailreturn1.getMobno());
holder.domain.setText(judgedetailreturn1.getDomain());
holder.email.setText(judgedetailreturn1.getEmail());
Firebase mref = new Firebase("https://master-app-inc.firebaseio.com/judgeid/"+ide+"/StudentIDalloted");
mref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Chip chip=new Chip(holder.chipGroup.getContext());
chip.setText(dataSnapshot.getValue().toString());
holder.chipGroup.addView(chip);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
#Override
public int getItemCount() {
return judgelist.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
ChipGroup chipGroup;
TextView name,id,email,mobno,company,domain;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.namejudegedetail);
id = itemView.findViewById(R.id.judgeidjudegedetail);
email = itemView.findViewById(R.id.emailidjudegedetail);
mobno = itemView.findViewById(R.id.mobilenojudgedetail);
company = itemView.findViewById(R.id.companynamejudegedetail);
domain= itemView.findViewById(R.id.domainjudgedetail);
chipGroup = itemView.findViewById(R.id.chipgrp);
}
}
public void toast(String x){
Toast.makeText(context,x,Toast.LENGTH_SHORT).show();
}
}
Hope this run !
I have a firebase strucuture as
The recycler view is only displaying the last added or say latest added node to the database instead of displaying each and every node
the database reference i am using is
r2 = FirebaseDatabase.getInstance().getReference().child("Uploads").child("Wheat").child(S).child(D).child(T).child(FirebaseAuth.getInstance().getUid());
and the code for recycler view is as
public class MyPost extends AppCompatActivity {
private RecyclerView recyclerView;
private DatabaseReference r, r2, r3;
private String S, D, T;
FirebaseRecyclerAdapter<RecyclerCropView, ViewHolder2> Fbra1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_post);
r = FirebaseDatabase.getInstance().getReference().child("User_Data").child(MainDashboard.type).child(FirebaseAuth.getInstance().getUid());
recyclerView = (RecyclerView) findViewById(R.id.R_view2);
r.addListenerForSingleValueEvent(rr);
}
private ValueEventListener rr = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
S = dataSnapshot.child("State").getValue().toString();
D = dataSnapshot.child("City").getValue().toString();
T = dataSnapshot.child("Tehsil").getValue().toString();
// Toast.makeText(MyPost.this,S+D+T.toString(),Toast.LENGTH_LONG).show();
r2 = FirebaseDatabase.getInstance().getReference().child("Uploads").child("Wheat").child(S).child(D).child(T).child(FirebaseAuth.getInstance().getUid());
// Toast.makeText(MyPost.this,r2.toString(),Toast.LENGTH_LONG).show();
r2.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
r3=r2.child(dataSnapshot.getKey());
Toast.makeText(MyPost.this, r3.toString(), Toast.LENGTH_LONG).show();
FirebaseRecyclerOptions<RecyclerCropView> options = new FirebaseRecyclerOptions.Builder<RecyclerCropView>().setQuery(r3, RecyclerCropView.class).build();
Fbra1 = new FirebaseRecyclerAdapter<RecyclerCropView, ViewHolder2>(options) {
#Override
protected void onBindViewHolder(#NonNull ViewHolder2 holder, int position, #NonNull RecyclerCropView model) {
holder.setProductImage(model.getProduct_Image());
holder.setProduct(model.getProduct());
holder.setMax(model.getMaximumPrice());
holder.setQuantityUnit(model.getQuantityUnit());
holder.setQuantity(model.getQuantity());
}
#NonNull
#Override
public ViewHolder2 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_post, parent, false);
return new ViewHolder2(v);
}
};
Fbra1.notifyDataSetChanged();
recyclerView.hasFixedSize();
recyclerView.setLayoutManager(new LinearLayoutManager(MyPost.this));
Fbra1.startListening();
recyclerView.setAdapter(Fbra1);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
#Override
protected void onRestart() {
super.onRestart();
finish();
}
}
Recycler view is only showing very last item that was added to database.
Note:-
The item.xml file has width set to wrap content.
if i remove the childEventListener the recyclerView shows multiple items with
null on the place of TextView(These are those textView on which data retrived was supposed to be set)
Here is the problem: r2.addChildEventListener
Classes implementing this interface can be used to receive events about changes in the child locations of a given DatabaseReference ref. Attach the listener to a location using addChildEventListener(ChildEventListener) and the appropriate method will be triggered when changes occur.
Firebase Docs
What you should use is a r2.addListenerForSingleValueEvent
This returns the children of the specific node. But now since you are using FirebaseUI library, you will not need to listen as it is a listener itself.
So your code should listen to the root of the posts. This r3=r2.child(dataSnapshot.getKey()); is unnecessary because it only gets one entry
Change to this
FirebaseRecyclerOptions<RecyclerCropView> options = new FirebaseRecyclerOptions.Builder<RecyclerCropView>().setQuery(r2, RecyclerCropView.class).build();
Fbra1 = new FirebaseRecyclerAdapter<RecyclerCropView, ViewHolder2>(options) {
#Override
protected void onBindViewHolder(#NonNull ViewHolder2 holder, int position, #NonNull RecyclerCropView model) {
holder.setProductImage(model.getProduct_Image());
holder.setProduct(model.getProduct());
holder.setMax(model.getMaximumPrice());
holder.setQuantityUnit(model.getQuantityUnit());
holder.setQuantity(model.getQuantity());
}
#NonNull
#Override
public ViewHolder2 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_post, parent, false);
return new ViewHolder2(v);
}
};
Fbra1.notifyDataSetChanged();
recyclerView.hasFixedSize();
recyclerView.setLayoutManager(new LinearLayoutManager(MyPost.this));
Fbra1.startListening();
recyclerView.setAdapter(Fbra1);
I am trying to retrieve data from firebase database, when i try to retrieve data for the very first time after installing the app nothing is displayed in recycler view but when i press back and once again try to retrieve data,its displayed properly, suggest me changed which i should do in my code so that data is properly displayed in first attempt
Method Used to return ArrayList
public ArrayList<SaveAddInformation> retrieve(){
AdvertisementRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot eventSnapshot : dataSnapshot.getChildren()) {
SaveAddInformation mModel = eventSnapshot.getValue(SaveAddInformation.class);
Log.d("DATA" ,""+ mModel);
adinfolist.add(mModel);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return adinfolist;
}
Adpater Class
Context c;
ArrayList<SaveAddInformation> adinfolist;
public MyAdapter(Context c, ArrayList<SaveAddInformation> adinfolist) {
this.c = c;
this.adinfolist = adinfolist;
}
#Override
public MyViewholder onCreateViewHolder(ViewGroup parent, int viewType) {
View v= LayoutInflater.from(c).inflate(R.layout.design_row,parent,false);
MyViewholder myViewholder=new MyViewholder(v);
return myViewholder;
}
#Override
public void onBindViewHolder(MyViewholder holder, int position) {
SaveAddInformation save=adinfolist.get(position);
holder.titleTv.setText(save.getTitleS());
holder.rentamt.setText(save.getRent_amount());
holder.rentdays.setText(save.getRentDayS());
holder.desc.setText(save.getDescriptionS());
holder.setImage(getApplicationContext(), save.getImageuri());
// holder.titleTv.setText((CharSequence) adinfolist.get(position));
}
#Override
public int getItemCount() {
return adinfolist.size();
}
}
ViewHolder Class
public MyViewholder(View itemView) {
super(itemView);
titleTv=(TextView)itemView.findViewById(R.id.Titletextv);
rentamt=(TextView)itemView.findViewById(R.id.rent_amount);
rentdays=(TextView)itemView.findViewById(R.id.days_rent);
desc=(TextView)itemView.findViewById(R.id.descTV);
}
public void setImage(Context applicationContext, String imageuri) {
adimg=(ImageView)itemView.findViewById(R.id.ad_image);
// We Need TO pass Context
Picasso.with(applicationContext).load(imageuri).into(adimg);
}
If you are sure that the code has no errors, I would like to remind you that Firebase connections are async.
So the first time the function retrieve() returns the value of arrayList is actually empty.
What you can do is call adapter.notifyDataSetChanged() after the for loop in onDataChange() method.
I'm using Firebase with RecyclerView,I'd like to retrieve the child with a specific position to delete it. I know that I should use a query of orderBy, but I need to get a specific child by its position.
Is there a way to do this? I only found a way to get the number of children with getChildrenCount() method of the snapshot, but didn't find something by passing the position value.
Thank you.
protected void populateViewHolder(final ReportViewHolder viewHolder, final Report report, int position) {
viewHolder.txtTitle.setText(report.title);
viewHolder.txtMessage.setText(report.message);
viewHolder.txtDate.setText(report.date);
viewHolder.txtuserName.setText(report.userName);
viewHolder.btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String key = report.key;
Query myTopPostsQuery = mDatabaseReference.child("user-reports/"+userID).orderByKey().equalTo(report.key);
myTopPostsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
snapshot.getRef().removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mDatabaseReference.child("reports/"+ key).removeValue();
}
});
}
};
I want to use the position of populateViewHolder, to get the child position and then delete its node.
Now I added a field for report called key and using orderByKey().equalTo(report.key); to delete it.
I think you have to add delete and add methods to your adapter class.
public class AllAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Article> articleList = new ArrayList<>();
Context context;
public AllAdapter(Context context){
this.context = context;
}
public void addItem(Article article){
articleList.add(article);
notifyDataSetChanged();
}
public void deleteItem(int position){
articleList.remove(position);
notiftyDateSetChanged(position);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_post_item,null);
return new ArticleViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return articleList.size();
}
class ArticleViewHolder extends RecyclerView.ViewHolder{
public ArticleViewHolder(View itemView) {
super(itemView);
}
}
}