For months I have created a chat for the Android system using Firebase as a database.
I followed this guide here
( link ) and at the beginning it was all right, the chat was good and it didn't have any kind of delays. I then started to add other particularities, such as the display or not of the message and the status of the participants (online and offline) and from that moment three problems began to manifest in particular:
1) when I change the chat activity to go to another and then return to the chat, the layout appears empty without messages and if you try to change the activity the application closes itself. I found out that I get this error:
E/RecyclerView: No adapter attached; skipping layout
These are the files that make up the part related to chat:
MessageChat.java
public class MessageChat {
private String sender;
private String receiver;
private String msg;
private String currenttime;
private boolean isseen;
public MessageChat(String sender, String receiver, String msg, String currenttime, boolean isseen){
this.sender = sender;
this.receiver = receiver;
this.msg = msg;
this.currenttime = currenttime;
this.isseen = isseen;
}
public MessageChat(){}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getReceiver() {return receiver;}
public void setReceiver(String receiver) { this.receiver = receiver;}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getCurrenttime() {
return currenttime;
}
public void setCurrenttime(String currenttime) {
this.currenttime = currenttime;
}
public boolean isIsseen() {return isseen;}
public void setIsseen(boolean isseen) {this.isseen = isseen;}
}
msgAdapter.java
public class msgAdapter extends RecyclerView.Adapter<msgAdapter.MsgViewHolder> {
public static final int INT_TYPE_LEFT = 0;
public static final int INT_TYPE_RIGHT = 1;
private static List<MessageChat> mChat;
private static Context context;
private FirebaseUser fuser;
public msgAdapter(List<MessageChat> msg, Context context) {
this.mChat = msg;
this.context = context;
}
#Override
public msgAdapter.MsgViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == INT_TYPE_RIGHT) {
View view = LayoutInflater.from(context).inflate(R.layout.right_message, null);
msgAdapter.MsgViewHolder msgViewHolder = new msgAdapter.MsgViewHolder(view);
return msgViewHolder;
}else{
View view = LayoutInflater.from(context).inflate(R.layout.left_message, null);
msgAdapter.MsgViewHolder msgViewHolder = new msgAdapter.MsgViewHolder(view);
return msgViewHolder;
}
}
#Override
public void onBindViewHolder(final msgAdapter.MsgViewHolder holder, final int position) {
MessageChat msg = mChat.get(position);
holder.show_msg.setText(msg.getMsg());
if ((position == mChat.size()-1) && msg.getSender().equals(fuser.getUid())){
if (msg.isIsseen()){
holder.tv_seen.setText(" Seen ");
holder.tv_seen.setVisibility(View.VISIBLE);
}else {
holder.tv_seen.setText(" Sent ");
holder.tv_seen.setVisibility(View.VISIBLE);
}
}else{
holder.tv_seen.setVisibility(View.GONE);
}
}
#Override
public int getItemCount() {
return mChat.size();
}
public static class MsgViewHolder extends RecyclerView.ViewHolder {
TextView username, show_msg, tv_seen;
public MsgViewHolder(final View itemView) {
super(itemView);
show_msg = (TextView) itemView.findViewById(R.id.show_msg);
tv_seen = (TextView) itemView.findViewById(R.id.tv_seen);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// item clicked
MessageChat msg = mChat.get(getAdapterPosition());
String ctime = msg.getCurrenttime();
TastyToast.makeText(context, ctime, TastyToast.LENGTH_LONG, TastyToast.INFO);
}
});
}
}
#Override
public int getItemViewType(int position) {
fuser = FirebaseAuth.getInstance().getCurrentUser();
if (mChat.get(position).getSender().equals(fuser.getUid())){
return INT_TYPE_RIGHT;
}else{
return INT_TYPE_LEFT;
}
}
}
On the internet I have found many answers that solve this problem in the following way, replacing this:
View view = LayoutInflater.from(context).inflate(R.layout.right_message, null);
to this:
View view = LayoutInflater.from(context).inflate(R.layout.right_message, parent, false);
But in my case I only got the busted chat with empty spaces between one comic and another.
Homefragment.java
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private View v;
private ImageButton btn_send;
private EditText et_send_mex;
private DatabaseReference reference;
private msgAdapter mAdapter;
private List<MessageChat> mChat;
private RecyclerView recyclerView;
private FirebaseUser user;
private String Uid, Oid;
private static final String sId = "xyz1";
private static final String pId = "xyz2";
ValueEventListener seenListener;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel.class);
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_home, container, false);
btn_send = v.findViewById(R.id.btn_send);
et_send_mex = v.findViewById(R.id.et_send_mex);
recyclerView = v.findViewById(R.id.rv_mex);
recyclerView.setHasFixedSize(true);
LinearLayoutManager llManager = new LinearLayoutManager(getContext());
llManager.setStackFromEnd(true);
recyclerView.setLayoutManager(llManager);
user = FirebaseAuth.getInstance().getCurrentUser();
Uid = user.getUid();
btn_send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// notify = true;
String m = et_send_mex.getText().toString();
if (!m.equals("") || !m.equals("\n")){
if (Uid.equals(pId)){
sendMessage(Uid,sId,m);
}else if (Uid.equals(sId)){
sendMessage(Uid,pId,m);
}
}
}
});
readMessage();
return v;
}
private void seenMessage(final String senderId){
reference = FirebaseDatabase.getInstance().getReference("chats");
seenListener = reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()){
MessageChat msgchat = snapshot.getValue(MessageChat.class);
if (msgchat.getReceiver().equals(user.getUid()) && msgchat.getSender().equals(senderId)){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("isseen", true);
snapshot.getRef().updateChildren(hashMap);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void sendMessage(String sender, String receiver, String message){
reference = FirebaseDatabase.getInstance().getReference();
HashMap<String, Object> hashMap = new HashMap<>();
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
month = month+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR_OF_DAY);
int sec = c.get(Calendar.MINUTE);
String dt = day+" - "+month+" - "+year+", "+hour+":"+sec;
hashMap.put("currenttime", dt);
hashMap.put("sender", sender);
hashMap.put("receiver", receiver);
hashMap.put("msg", message);
hashMap.put("isseen", false);
reference.child("chats").push().setValue(hashMap);
et_send_mex.setText("");
}
private void readMessage (){
mChat = new ArrayList<>();
mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
reference = FirebaseDatabase.getInstance().getReference("chats");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mChat.clear();
for (DataSnapshot snapshot: dataSnapshot.getChildren()){
MessageChat chat = snapshot.getValue(MessageChat.class);
mChat.add(chat);
if (!chat.getSender().equals(Uid)){
Oid = chat.getSender();
seenMessage(Oid);
}
}
mAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
// user status
private void status(String status){
user = FirebaseAuth.getInstance().getCurrentUser();
reference = FirebaseDatabase.getInstance().getReference("Users").child(user.getUid());
HashMap<String, Object> hashMap = new HashMap<>();
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
month = month+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int hour = c.get(Calendar.HOUR_OF_DAY);
int sec = c.get(Calendar.MINUTE);
String dt = day+" - "+month+" - "+year+", "+hour+":"+sec;
hashMap.put("lastaccess", dt);
hashMap.put("status", status);
reference.updateChildren(hashMap);
}
#Override
public void onResume() {
super.onResume();
status("online");
recyclerView.setAdapter(mAdapter);
}
#Override
public void onPause() {
super.onPause();
reference.removeEventListener(seenListener);
status("offline");
}
}
I was also advised to add in here:
#Override
public void onResume() {
super.onResume();
status("online");
}
The following code:
recyclerView.setAdapter(mAdapter);
But with poor results (maybe you can suggest me if it is right to add this part here or not, thank you very much)
2) When I send a message, it often takes a long time to reach the database, let's say that Firebase is not really a realtime database. Here I have not encountered any type of error, it is simply very slow.
3) Later I also added the change of state, simply when the application is closed or in background ( onPause () ), the state is set to offline in the database, otherwise it is online. But often it doesn't work properly, probably application crashes or delays affect this.
I remain available for any other part of the code or for clarification.
I thank you in advance for your help and I apologize for my bad English, I have been working on this application since last spring and I still have not been able to solve these problems.
first thing you want to do is, remove the part in your onCreate.
reference = FirebaseDatabase.getInstance().getReference("chats");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
readMessage();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Here you basically put a reference on the database (chats) and every time it changes, it will call your function readMessage, which will always override your messages and put another listener on the same spot. Make sure you understand, that addValueEventListener is triggered every time the tree/path (chats) in firebase is updated!
You could simply replace the code from above with:
readMessage();
that would already make sure it is listening to your db. I believe that firebase is not slow, but that the two listeners maybe overriding their result.
About the next part i am not 100%, but i believe you can remove
mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
from onDataChange (in readMessage) and put it directly under that part where you create the ArrayList. Like this:
mChat = new ArrayList<>();
mAdapter = new msgAdapter(mChat,getContext());
recyclerView.setAdapter(mAdapter);
reference = FirebaseDatabase.getInstance().getReference("chats");
I hope i understood your problem and my answer will give you a bit more clarity :)
Greetings!
Related
I'm trying to make a comment system for posts on my social media app. In my database each post has a section inside of "comments" table, like so:
"hypno--######" is the title of the social media post. It Contains the comment, user id of the user who posted the comment, and a unixtimestamp when the comment was posted. Each comment is titled after the time it was posted.
This is the Comment class
public class comment {
public String uID;
public String comment_t;
public long unixTimestamp;
public comment() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public comment(String uID, String comment_t, long unixTimestamp) {
this.uID = uID;
this.comment_t = comment_t;
this.unixTimestamp = unixTimestamp;
}
public String getuID() {
return uID;
}
public void setuID(String uID) {
this.uID = uID;
}
public String getComment() {return comment_t;}
public void setComment() {this.comment_t = comment_t; }
public long getUnixTimestamp() {
return unixTimestamp;
}
}
This is the Comment Adapter:
Public class Adapter_Comment extends FirebaseRecyclerAdapter<comment, Adapter_Comment.ViewHolder_com> {
private DatabaseReference mDatabase;
private static final String TAG = "RecyclerViewAdapter";
private Context mContext;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
private static AppCompatActivity unwrap(Context context) {
while (!(context instanceof Activity) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
}
return (AppCompatActivity) context;
}
public Adapter_Comment(#NonNull FirebaseRecyclerOptions<comment> options) {
super(options);
//this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder_com onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_comment, parent, false);
mDatabase = FirebaseDatabase.getInstance().getReference();
return new ViewHolder_com(view);
}
#Override
protected void onBindViewHolder(#NonNull ViewHolder_com holder, int position, #NonNull comment model) {
mDatabase = FirebaseDatabase.getInstance().getReference();
long dv = model.getUnixTimestamp()*-1000;
Date df = new java.util.Date(dv);
String vv = new SimpleDateFormat("MM dd, yyyy hh:mma", Locale.ENGLISH).format(df);
holder.time.setText(vv);
String com = model.getComment();
holder.comment_text.setText(com);
mDatabase.child("users").child(model.getuID()).child("profileUrl").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists())
{
final String picUrl = snapshot.getValue(String.class);
Glide.with(holder.postPfp.getContext()).load(picUrl).into(holder.postPfp);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});
holder.postPfp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//AppCompatActivity activity = (AppCompatActivity) v.getContext();
AppCompatActivity activity = unwrap(v.getContext());
Fragment OtherProfileFragment = new OtherProfileFragment();
Bundle bundle = new Bundle();
bundle.putString("key", model.getuID());
OtherProfileFragment.setArguments(bundle);
activity.getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, OtherProfileFragment).addToBackStack(null).commit();
}
});
}
public class ViewHolder_com extends RecyclerView.ViewHolder {
TextView comment_text;
CircleImageView postPfp;
TextView time;
RelativeLayout comment_layout;
public ViewHolder_com(#NonNull View itemView) {
super(itemView);
postPfp = itemView.findViewById(R.id.iv_comment_icon);
comment_text = itemView.findViewById(R.id.tv_comment_text);
time = itemView.findViewById(R.id.tv_comment_time);
comment_layout = itemView.findViewById(R.id.comment_layout);
}
}
}
This is Comment Fragment:
public class CommentFragment extends Fragment {
private DatabaseReference mDatabase;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
View view;
String value;
RecyclerView recyclerView;
Query query;
TextView comment_text;
long unixTime = System.currentTimeMillis() / 1000L;
public long globalUnix;
Button comment_post;
String comment_string;
Adapter_Comment adapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_comment, container, false);
value = getArguments().getString("key");
mDatabase = FirebaseDatabase.getInstance().getReference();
recyclerView = view.findViewById(R.id.recyclerv_comment);
comment_text = view.findViewById(R.id.tv_comment_type);
comment_post = view.findViewById(R.id.btn_comment_post);
globalUnix = (unixTime * -1);
comment_post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(comment_text.getText().toString() == NULL){
Toast.makeText(getActivity(), "No Comment Typed", Toast.LENGTH_LONG).show();
}
else{
comment com = new comment();
com.uID = user.getUid();
com.comment_t = comment_text.getText().toString();
com.unixTimestamp = globalUnix;
mDatabase.child("comments").child(value).child(globalUnix + "").setValue(com);
}
}
});
initRecyclerView();
return view;
}
private void initRecyclerView(){
//Log.d(TAG, "initRecyclerView: init recyclerView");
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
query = FirebaseDatabase.getInstance().getReference().child("comments").orderByValue();
FirebaseRecyclerOptions<comment> options = new FirebaseRecyclerOptions.Builder<comment>().setQuery(query, comment.class).build();
adapter = new Adapter_Comment(options);
recyclerView.setAdapter(adapter);
adapter.startListening();
adapter.notifyDataSetChanged();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Inside of the adapter I'm using the comment model, to get the uID, comment and timestamp to fill the holder, however when i set these values im getting null values. Is there something im missing when trying to connect the adapter/firebase and model/holder?
long dv = model.getUnixTimestamp()*-1000;
Date df = new java.util.Date(dv);
String vv = new SimpleDateFormat("MM dd, yyyy hh:mma", Locale.ENGLISH).format(df);
holder.time.setText(vv);
String com = model.getComment();
holder.comment_text.setText(com);
mDatabase.child("users").child(model.getuID()).child("profileUrl").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists())
{
final String picUrl = snapshot.getValue(String.class);
Glide.with(holder.postPfp.getContext()).load(picUrl).into(holder.postPfp);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});
There's really too much going on in here, but...
As far as I can see you're creating a FirebaseUI adapter on FirebaseDatabase.getInstance().getReference().child("comments"). FirebaseUI adapters show the direct child nodes of the node you pass in, so in your case it'll create one view for the hypno---...196 node. You're trying to read a Comment object from there, but don't exist until one level lower in your JSON.
So you can:
Either show the comments for one post, by basing the adapter off of that. So: FirebaseDatabase.getInstance().getReference().child("comments").child("hypno---...196") (which the real key in there).
Or you can show one piece of information about each post, for example its key.
If you want to show a flat list of comments for all posts through the FirebaseUI adapter, you'll have to store a flat list of comments across all posts in your database too.
List all information of both service providers (Babysitter and Kids event planner) from the Account class
public class Register_Requests extends Fragment {
FirebaseAuth mAuth;
DatabaseReference refAccount,searchdatabase;
FirebaseUser user;
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
RecyclerView recyclerView;
Adapter adapter;
TextView Fullname_Admin;
Button btnlogOutAdmin,search_bar;
String F_name, L_name;
ArrayList<Account> list = new ArrayList();
private String mParam1;
private String mParam2;
public Register_Requests() { }
public static Register_Requests newInstance(String param1, String param2) {
Register_Requests fragment = new Register_Requests();
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) {
View view= inflater.inflate(R.layout.fragment_register__requests, container, false);
ImageView imgfake;
TextView nametext,SPtext,count;
imgfake=view.findViewById(R.id.imgfake);
nametext=view.findViewById(R.id.nametext);
SPtext=view.findViewById(R.id.SPtext);
count= (TextView) view.findViewById(R.id.counttext);
btnlogOutAdmin = view.findViewById(R.id.signout_admin);
Fullname_Admin= (TextView) view.findViewById(R.id.name_admin);
recyclerView =(RecyclerView)view.findViewById(R.id.recview_SP);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
user= FirebaseAuth.getInstance().getCurrentUser();
refAccount = FirebaseDatabase.getInstance().getReference().child("Account");
String Id_admin = FirebaseAuth.getInstance().getCurrentUser().getUid();
// Welcome admin
FirebaseDatabase.getInstance().getReference("Admin").child(Id_admin)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Admin admin_display = snapshot.getValue(Admin.class);
if(admin_display != null){
F_name = admin_display.getA_FullName();
L_name = admin_display.getA_LastName();
Fullname_Admin.setText("Welcome "+F_name+" "+L_name+" !");}}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getActivity(),"Something Wrong Happened",Toast.LENGTH_SHORT).show();}});
// Logout admin
btnlogOutAdmin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseAuth.getInstance().signOut();
perfrences.clearData(getActivity());
getActivity().finish();
startActivity(new Intent(getActivity(),Login.class));}});
// List Babysitter and Kids Event Planner from Account
refAccount.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
list.clear();
if (snapshot.exists())
{
for (DataSnapshot snapshot1: snapshot.getChildren())
{
Account a=snapshot1.getValue(Account.class);
list.add(a);
}
adapter.notifyDataSetChanged();
count.setText(adapter.getItemCount()+" Registers"); }
else
{ nametext.setText("No Available Service Providers");
nametext.setVisibility(View.VISIBLE);} }
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
// Adapter for recycle view
FirebaseRecyclerOptions<Account> options =
new FirebaseRecyclerOptions.Builder<Account>()
.setQuery(refAccount, Account.class)
.build();
adapter = new Adapter(options);
recyclerView.setAdapter(adapter);
adapter.startListening();
return view;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}}
Adapter class where I'll get access from Account class to both service provider
public class Adapter extends FirebaseRecyclerAdapter<Account, Adapter.viewHolder> {
DatabaseReference Ref,Ref2,check;
boolean flag =true, flag2=true;
String userIDs,total_count,IDsitter,IDplanner;
public Adapter(#NonNull FirebaseRecyclerOptions<Account> options) { super(options); }
#Override
protected void onBindViewHolder(#NonNull viewHolder holder, int position, #NonNull Account model) {
Ref= FirebaseDatabase.getInstance().getReference("Babysitter");
Ref2= FirebaseDatabase.getInstance().getReference("Kids Event Planner");
userIDs = model.user_id;
// Print all the Babysitter
Ref.child(userIDs).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
if(snapshot.hasChild("b_FirstName")){
String Fname = snapshot.child("b_FirstName").getValue().toString();
String Lname = snapshot.child("b_LastName").getValue().toString();
String photo = snapshot.child("b_Photo").getValue().toString();
String gender = snapshot.child("b_Gender").getValue().toString();
String nationality = snapshot.child("b_Nationality").getValue().toString();
String phone = snapshot.child("b_Phone").getValue().toString();
String B_date = snapshot.child("b_BirthDate").getValue().toString();
int Y_e = parseInt(snapshot.child("years_of_Experience").getValue().toString());
String exp= Integer.toString(Y_e);
String state= snapshot.child("registration_Status").getValue().toString();
String educate= snapshot.child("b_EducationLevel").getValue().toString();
holder.nametext.setText(Fname +" "+ Lname );
holder.SPtext.setText(model.getAccount_role());
Picasso.with(holder.imgfake.getContext()).load(photo).placeholder(R.drawable.ic_action_name).into(holder.imgfake);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
AppCompatActivity activity=(AppCompatActivity)view.getContext();
activity.getSupportFragmentManager().beginTransaction().replace(R.id.container, new eachInfo_SP(model.user_id,Fname,Lname,photo,
gender,nationality,phone,B_date,model.getAccount_email(),model.getAccount_role(), exp,state,educate)).addToBackStack(null).commit();}});}
else { flag=false;System.out.println("No values");} if (!(model.account_role.equals("Admin"))&& !(model.account_role.equals("Parent")) ){
// Log.e(String.valueOf(snapshot.getKey().equals(userIDs)), snapshot.getChildrenCount() + " Registers");
total_count = snapshot.getChildrenCount() + " Registers";
System.out.println(total_count);
}}}
#Override
public void onCancelled(#NonNull DatabaseError error) {}});
// Print all the KEP
Ref2.child(userIDs).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
KidsEventPlanner k= snapshot.getValue(KidsEventPlanner.class);
if(snapshot.hasChild("e_FirstName")){
String Fname = snapshot.child("e_FirstName").getValue().toString();
String Lname = snapshot.child("e_LastName").getValue().toString();
String photo = snapshot.child("e_Photo").getValue().toString();
String gender = snapshot.child("e_Gender").getValue().toString();
String nationality = snapshot.child("e_Nationality").getValue().toString();
String phone = snapshot.child("e_Phone").getValue().toString();
String B_date = snapshot.child("e_BirthDate").getValue().toString();
int Y_e = parseInt(snapshot.child("years_of_experience").getValue().toString());
String exp= Integer.toString(Y_e);
String state= snapshot.child("registration_status").getValue().toString();
String educate= snapshot.child("e_EducationLevel").getValue().toString();
holder.nametext.setText(Fname +" "+ Lname );
holder.SPtext.setText(model.getAccount_role());
Picasso.with(holder.imgfake.getContext()).load(photo).placeholder(R.drawable.ic_action_name).into(holder.imgfake);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
AppCompatActivity activity=(AppCompatActivity)view.getContext();
activity.getSupportFragmentManager().beginTransaction().replace(R.id.container, new eachInfo_SP(model.user_id,Fname,Lname,photo,
gender,nationality,phone,B_date,model.getAccount_email(),model.getAccount_role(), exp, state,educate)).addToBackStack(null).commit();}});}
else{flag2 = false; System.out.println("False");}} }
#Override
public void onCancelled(#NonNull DatabaseError error) {}});
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.singlerowdata,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;}
public class viewHolder extends RecyclerView.ViewHolder
{
ImageView imgfake;
TextView nametext,SPtext,count;
public viewHolder(#NonNull View itemView) {
super(itemView);
imgfake=itemView.findViewById(R.id.imgfake);
nametext=itemView.findViewById(R.id.nametext);
SPtext=itemView.findViewById(R.id.SPtext);
count= (TextView) itemView.findViewById(R.id.counttext);}}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
}
This is the Account class where I'll save the user's ID. Basically, I have in this class 4 users and just wanted related information of service providers
public class Account {
String account_email,account_password ,account_role, user_id;
public Account() {}
public Account(String account_email, String account_password, String account_role, String user_id) {
this.account_email = account_email;
this.account_password = account_password;
this.account_role = account_role;
this.user_id = user_id;
}
public String getAccount_email() {return account_email;}
public void setAccount_email(String account_email) {this.account_email = account_email;}
public String getAccount_password() {return account_password;}
public void setAccount_password(String account_password) {this.account_password = account_password; }
public String getAccount_role() {return account_role;}
public void setAccount_role(String account_role) {this.account_role = account_role; }
public String getUser_id() { return user_id; }
public void setUser_id(String user_id) { this.user_id = user_id;}
}
As you can see in the account_role these are 3 users and the 4th is the parent
there are 16 nodes in the Account path
those are other paths of (Service providers) which is in total 8 nodes
The problem is I just invoked only the service provider's information which should display 8 items in recycle view but here is displaying the rest of the items in the account class which in total 16 items, which means 8 item's data is shown but the rest is empty and I want to display item list as the size of service providers. So How I can prevent this problem?
It's showing empty rows from the Account class.
To get only the child nodes from under /Account with a specific value for account_role, you can use a query to order and filter data:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Account");
Query query = ref.orderByChild("account_role").equalTo("Babysitter");
query. addListenerForSingleValueEvent(...
But you can only do this for a single value (like Babysitter above), or for a contiguous range of values (like: from Admin to Babysitter). There is no way to request (with a single query) a number of distinct values like you want.
Some options:
Perform a query (like I showed above) for each value, and then merge the results in your client-side code. The performance of this will be fine, but it will be a bit more code.
Give each child node a single property that exactly matches your condition, so for example: "Babysitter_or_KidsEventPlanner": true. Then you can filter on that property. This works best if you have a limited number of such combinations.
Perform a query on a range of values, for example: ref.orderByChild("account_role").startAt("Babysitter").endAt("Kids Event Planner"). Just keep in mind that this returns all nodes where the account_role value is between Babysitter and Kids Event Planner, so it'd also include nodes with Car mechanic. Sometimes this is a good option though, especially if you can order/rename the values in a way to allow your query needs.
This question already has answers here:
FirebaseListAdapter not pushing individual items for chat app - Firebase-Ui 3.1
(2 answers)
Closed 4 years ago.
I'm trying to implement a FirebaseRecyclerAdapter For the first time, but it just never gets called! I've checked the Firebase Guide Here but no good.
Have also checked similar threads that reported "Deleting Has FixedSize()" fixed it for them but that's not the case Here
Here's part of my database
and Here's my code for the adapter and model:
FirebaseRecyclerAdapter<Complaint, ComplaintHolder> TestAdapter;
DatabaseReference mRef;
FirebaseUser mUser;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUser = FirebaseAuth.getInstance().getCurrentUser();
mRef = FirebaseDatabase.getInstance().getReference("AccountsComplaintBasdNode").child(mUser.getUid());
Query query = mRef;
FirebaseRecyclerOptions<Complaint> mOptions = new FirebaseRecyclerOptions.Builder<Complaint>()
.setQuery(query, Complaint.class)
.build();
if (TestAdapter == null) {
TestAdapter = new FirebaseRecyclerAdapter<Complaint, ComplaintHolder>(mOptions) {
#NonNull
#Override
public ComplaintHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, viewGroup, false);
Toast.makeText(getActivity(), "Please get called", Toast.LENGTH_SHORT).show();
return new ComplaintHolder(v);
}
#Override
protected void onBindViewHolder(#NonNull ComplaintHolder holder, int position, #NonNull Complaint model) {
holder.TitleTv.setText(model.getComplaintTitle());
SimpleDateFormat smf = new SimpleDateFormat("yyyy/MM/dd");
String dateString = smf.format(model.getDate());
holder.DateTv.setText(dateString);
}
///Model Object here
public Complaint() {
}
private String ComplaintTitle;
private String details;
private Date mDate;
private String PhotoUrl;
public Complaint(String complaintTitle, String details, Date date, String photoUrl) {
ComplaintTitle = complaintTitle;
this.details = details;
mDate = date;
PhotoUrl = photoUrl;
}
public void setComplaintTitle(String complaintTitle) {
ComplaintTitle = complaintTitle;
}
public void setDetails(String details) {
this.details = details;
}
public void setDate(Date date) {
this.mDate = date;
}
public void setPhotoUrl(String photoUrl) {
PhotoUrl = photoUrl;
}
public String getComplaintTitle() {
return ComplaintTitle;
}
public String getDetails() {
return details;
}
public Date getDate() {
return mDate;
}
public String getPhotoUrl() {
return PhotoUrl;
}
The FirebaseRecyclerAdapter uses an event listener to monitor changes to the Firebase query. To begin listening for data, call the startListening() method. Make sure you have finished any authentication necessary to read the data before calling startListening() or your query will fail.
So seems only you need is to call TestAdapter.startListening(); in onStart() method and don't forget to call TestAdapter.stopListening(); in onStop() as well but before calling stopListening() always check agains null
like:if(TestAdapter != null)
For more information and example: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md
My database structure
I am trying to create an activity where I can display all the logs. Just timestamp and the log message. I have tried with firebaseUI and adapter but I can't get the data to show. Best I have done was to post same last log in all positions. This is what I have so far but no success. I am new to firebase and all I need is to display the logs in a list. It can be lisView or recyclerView. If anyone can help me with code or example. Thank you.
Database structure is | "logs" node / userId / logId / fields |
public class LogActivity extends AppCompatActivity {
private static final String TAG = "LogActivity";
private static final int ACTIVITY_NUM = 3;
//widgets
private Context mContext = LogActivity.this;
private RecyclerView mLogRecycleView;
private TextView timeStamp, log;
//firebase
private DatabaseReference mLogDatabase;
private FirebaseAuth mAuth;
//adapter
private FirebaseRecyclerAdapter adapter;
//vars
private String mCurrentUserID, logID;
List<AppLogs> logsList = new ArrayList<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
Log.d(TAG, "onCreate: Started");
mCurrentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mLogRecycleView = findViewById(R.id.recyclerList);
mLogDatabase = FirebaseDatabase.getInstance().getReference().child("logs").child(mCurrentUserID);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mLogRecycleView.setHasFixedSize(true);
mLogRecycleView.setLayoutManager(linearLayoutManager);
firebaseListAdapter();
mLogRecycleView.setAdapter(adapter);
setupBottomNavigationView();
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
private void firebaseListAdapter() {
Log.d(TAG, "firebaseListAdapter: started");
Query logQuery = mLogDatabase.orderByChild("time");
FirebaseRecyclerOptions<AppLogs> options =
new FirebaseRecyclerOptions.Builder<AppLogs>()
.setQuery(logQuery, AppLogs.class).build();
adapter = new FirebaseRecyclerAdapter<AppLogs, LogViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final LogViewHolder holder, int position, #NonNull AppLogs model) {
Log.d(TAG, "onBindViewHolder: started");
//get the ID of the messages
//final String logID = getRef(position).getKey();
//Log.d(TAG, "onBindViewHolder: logID : " + logID);
Query logQuery = mLogDatabase;
logQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot singData : dataSnapshot.getChildren()) {
//AppLogs logs = dataSnapshot.getValue(AppLogs.class);
Log.d(TAG, "onChildAdded: log:==== " + singData.child("log").getValue());
//Log.d(TAG, "onChildAdded: log_ID:==== " + logs.getLog_id());
String log = singData.child("log").getValue().toString();
// String timeStamp = Long.toString(logs.getTime());
//
holder.setLog(log);
// holder.setTimeStamp(timeStamp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public LogViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder: create users view holder: ");
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_log_list_view, parent, false);
return new LogViewHolder(view);
}
};
}
public static class LogViewHolder extends RecyclerView.ViewHolder {
View mView;
public LogViewHolder(View itemView) {
super(itemView);
this.mView = itemView;
}
public void setLog(String log) {
TextView tvLog = mView.findViewById(R.id.tvLog);
tvLog.setText(log);
}
public void setTimeStamp(String timeStamp) {
TextView tvTimeStamp = mView.findViewById(R.id.tvTimeStamp);
tvTimeStamp.setText(timeStamp);
}
}
/*
*BottomNavigationView Setup
*/
private void setupBottomNavigationView() {
Log.d(TAG, "setupBottomNavigationView: setting up BottomNavigationView");
BottomNavigationViewEx bottomNavigationViewEx = (BottomNavigationViewEx) findViewById(R.id.bottomNavViewBar);
BottomNavigationViewHelper.setupBottomNavigationView(bottomNavigationViewEx);
BottomNavigationViewHelper.enableNavigation(mContext, this, bottomNavigationViewEx);
Menu menu = bottomNavigationViewEx.getMenu();
MenuItem menuItem = menu.getItem(ACTIVITY_NUM);
menuItem.setChecked(true);
}
}
and my log model class
package com.logistics.alucard.socialnetwork.Models;
public class AppLogs {
private String log, log_id;
private long time;
public AppLogs(String log, String log_id, long time) {
this.log = log;
this.log_id = log_id;
this.time = time;
}
public AppLogs() {
}
public String getLog() {
return log;
}
public void setLog(String log) {
this.log = log;
}
public String getLog_id() {
return log_id;
}
public void setLog_id(String log_id) {
this.log_id = log_id;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}
I manage to figure it out! Thank you for your help. Still a bit confusing how to
build queries but I'll try to get better :)
This is my solution to the firebase retrieve data:
protected void onBindViewHolder(#NonNull final LogViewHolder holder, int position, #NonNull AppLogs model) {
Log.d(TAG, "onBindViewHolder: started");
//get the ID of the messages
final String logID = getRef(position).getKey();
//Log.d(TAG, "onBindViewHolder: logID : " + logID);
Query logQuery = mLogDatabase;
logQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//AppLogs appLogs = dataSnapshot.getValue(AppLogs.class);
//Log.d(TAG, "onDataChange: logs:---------" + dataSnapshot.child(logID).child("log").getValue());
String log = dataSnapshot.child(logID).child("log").getValue().toString();
String timeStamp = dataSnapshot.child(logID).child("time").getValue().toString();
Log.d(TAG, "onDataChange: logs:--------------" + log);
holder.setLog(log);
holder.setTimeStamp(timeStamp);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Main activity.java
public class activity_3 extends AppCompatActivity {
TextView question,option_1,option_2,option_3,description,winnner;
NumberProgressBar option_progress1, option_progress2,option_progress3;
int val_1;
int val_2;
int val_3;
DatabaseReference Polldata_3;
String optionOne;
String optionTwo;
String optionThree;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
final String que = getIntent().getExtras().getString("que");
final String des = getIntent().getExtras().getString("des");
optionOne = getIntent().getExtras().getString("option1");
optionTwo = getIntent().getExtras().getString("option2");
optionThree = getIntent().getExtras().getString("option3");
final String id_user = getIntent().getExtras().getString("id");
val_1 = getIntent().getExtras().getInt("val1");
val_2 = getIntent().getExtras().getInt("val2");
val_2 = getIntent().getExtras().getInt("val3");
option_progress1 = (NumberProgressBar) findViewById(R.id.option1_progressbar);
option_progress2 = (NumberProgressBar) findViewById(R.id.option2_progressbar);
option_progress3 = (NumberProgressBar) findViewById(R.id.option3_progressbar);
Polldata_3 = FirebaseDatabase.getInstance().getReference("POll").child("poll_3");
final DatabaseReference answsersave = Polldata_3.child(id_user);
question = (TextView) findViewById(R.id.question_showpoll);
option_1 = (TextView) findViewById(R.id.option_1);
option_2 = (TextView) findViewById(R.id.option_2);
option_3 = (TextView) findViewById(R.id.option_3);
description = (TextView) findViewById(R.id.description_user_3);
winnner = (TextView) findViewById(R.id.winner);
option_1.setText(optionOne);
option_2.setText(optionTwo);
option_3.setText(optionThree);
question.setText(que);
description.setText(des);
option_progress1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
option_progress1.setProgress(val_1+1);
option_progress1.setEnabled(false);
option_progress2.setEnabled(false);
option_progress3.setEnabled(false);
val_1++;
answsersave.child("option_1_value").setValue(val_1);
//winnerdeclare();
}
});
option_progress2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
option_progress2.setProgress(val_2+1);
option_progress1.setEnabled(false);
option_progress2.setEnabled(false);
option_progress3.setEnabled(false);
val_2++;
answsersave.child("option_2_value").setValue(val_2);
// winnerdeclare();
}
});
option_progress3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
option_progress3.setProgress(val_3+1);
option_progress1.setEnabled(false);
option_progress2.setEnabled(false);
option_progress3.setEnabled(false);
val_3++;
// winnerdeclare();
answsersave.child("option_3_value").setValue(val_3);
}
});
}
}
ADAPTER CLASS
public class listview_3 extends AppCompatActivity {
ListView listviewpoll3;
private DatabaseReference Poll_data_3;
List<addpoll_3> addpoll_3List;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview_3);
listviewpoll3 = (ListView) findViewById(R.id.poll_listview_3);
Poll_data_3 = FirebaseDatabase.getInstance().getReference("POll").child("poll_3");
addpoll_3List = new ArrayList<>();
listviewpoll3.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapter, View v, int position, long id) {
Intent intent = new Intent(listview_3.this, activity_3.class);
addpoll_3 poll = addpoll_3List.get(position);
final String optionone = poll.getOption_1();
final String optiontwo = poll.getOption_2();
final String optionthree = poll.getOption_3();
final String id_user = poll.getId();
final int value_1 = poll.getOption_1_value();
final int value_2 = poll.getOption_2_value();
final int value_3 = poll.getOption_3_value();
final String question = poll.getQuestion();
final String desp = poll.getDescription();
intent.putExtra("option1",optionone);
intent.putExtra("option2",optiontwo);
intent.putExtra("option3",optionthree);
intent.putExtra("id",id_user);
intent.putExtra("val1",value_1);
intent.putExtra("val2",value_2);
intent.putExtra("val3",value_3);
intent.putExtra("que",question);
intent.putExtra("descp",desp);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
Poll_data_3.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
addpoll_3List.clear();
for(DataSnapshot pollSnapshot: dataSnapshot.getChildren())
{
addpoll_3 poll = pollSnapshot.getValue(addpoll_3.class);
addpoll_3List.add(poll);
}
poll_list_3 adapter = new poll_list_3(listview_3.this,addpoll_3List);
listviewpoll3.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
list class
public class poll_list_3 extends ArrayAdapter<addpoll_3> {
private Activity context;
private List<addpoll_3> addpoll_3List;
public poll_list_3(Activity context, List<addpoll_3> addpoll_3List) {
super(context, R.layout.list_layout, addpoll_3List);
this.context = context;
this.addpoll_3List = addpoll_3List;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View viewitem = inflater.inflate(R.layout.list_layout,null);
TextView textViewName = (TextView) viewitem.findViewById(R.id.tv);
TextView textViewDesp = (TextView) viewitem.findViewById(R.id.tv1);
final addpoll_3 poll1 = addpoll_3List.get(position);
textViewName.setText(poll1.getQuestion());
textViewDesp.setText(poll1.getDescription());
return viewitem;
}
}
I am making a polling app where user can create a poll which is then stored in the firebase database and retrieved into listview of the app
when the user clicks on the list view he is directed to the the activity where there are number of progressbars
i have added a ON-click listener o the progress bar, So when user clicks on the progressbar the val of that option gets incremented in the database. so when a different user vote on the same poll the value from the database is fetched and value of the current user is added displaying the winner,but problem is the value of the progressbar1 gets the value from the database but the other two keep progress bar values start from 0 every time user clicks on the other two progress bar (ie 2 and 3).
please help
addpoll_3.java
public class addpoll_3 {
String id;
String question;
String description;
String option_1;
String option_2;
String option_3;
int option_1_value;
int option_2_value;
int option_3_value;
public addpoll_3(){}
public addpoll_3(String id, String question, String description, String option_1, String option_2, String option_3, int option_1_value, int option_2_value, int option_3_value) {
this.id = id;
this.question = question;
this.description = description;
this.option_1 = option_1;
this.option_2 = option_2;
this.option_3 = option_3;
this.option_1_value = option_1_value;
this.option_2_value = option_2_value;
this.option_3_value = option_3_value;
}
public String getId() {
return id;
}
public String getQuestion() {
return question;
}
public String getDescription() {
return description;
}
public String getOption_1() {
return option_1;
}
public String getOption_2() {
return option_2;
}
public String getOption_3() {
return option_3;
}
public int getOption_1_value() {
return option_1_value;
}
public int getOption_2_value() {
return option_2_value;
}
public int getOption_3_value() {
return option_3_value;
}
}
code:
Activity_3.java
val_1 = getIntent().getExtras().getInt("val1");
val_2 = getIntent().getExtras().getInt("val2");
val_3 = getIntent().getExtras().getInt("val3");
These were changes to be made
//Read from the database
myRef.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
String value = dataSnapshot.getValue(String.class);
Log.d(TAG, "Value is: " + value);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});