I am unable to change the text of multiple TextView to the values retrieved from Firebase Realtime Database.
My database looks like: Database
My current code is:
public class SearchResult extends AppCompatActivity {
TextView searchResultHSPName,searchResultHSPStatus, searchResultHSPType,searchResultHSPRating;
Button messageButton;
private static final String TAG = "SearchResult";
DatabaseReference rootReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_result);
searchResultHSPName = (TextView) findViewById(R.id.hspNameSearchResultTextView);
searchResultHSPType = (TextView) findViewById(R.id.hspTypeSearchResultTextView);
searchResultHSPRating = (TextView) findViewById(R.id.hspRatingSearchResultTextView);
searchResultHSPStatus = (TextView) findViewById(R.id.hspStatusSearchResultTextView);
//take the searched name from searchFunction and query db for the user details
Intent intent = getIntent();
final String searchedHSPName = intent.getExtras().getString("SearchFunctionMessage");
rootReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference userReference = rootReference.child("HSPUsers");
userReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
HSPUsers user = snapshot.getValue(HSPUsers.class);
String userName = user.HSPName;
if(userName == searchedHSPName){
searchResultHSPName.setText(userName);
searchResultHSPStatus.setText(user.HSPStatus);
searchResultHSPRating.setText(user.HSPRating);
searchResultHSPType.setText(user.HSPType);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
And my HSPUsers class is:
public class HSPUsers {
//HSP user contains 4 fields of data UserName, Status,Type,Rating
public String HSPName,HSPStatus, HSPType,HSPRating;
//constructor for datasnapshot
public HSPUsers(){
}
public HSPUsers(String username, String status, String type, String rating){
this.HSPName=username;
this.HSPStatus=status;
this.HSPType=type;
this.HSPRating=rating;
}
//get and set methods
public String getHSPUserName() {
return HSPName;
}
public void setHSPUserName(String HSPUserName) {
this.HSPName = HSPUserName;
}
public String getHSPUserStatus() {
return HSPStatus;
}
public void setHSPUserStatus(String HSPUserStatus) {
this.HSPStatus = HSPUserStatus;
}
public String getHSPUserType() {
return HSPType;
}
public void setHSPUserType(String HSPUserType) {
this.HSPType = HSPUserType;
}
public String getHSPUserRating() {
return HSPRating;
}
}
public String getHSPUserRating() {
return HSPRating;
}
}
Ideally, i would like to change the textViews to the user's Name/Status/Rating/Type. However, there has been no change to the textviews and i am left with UnchangedTextViews
Would appreciate any advice on how to change the TextViews to the HSPName/rating/Status/type?
Thank you in advance for any advice.
Related
I'm trying to build a ticket booking app for an event and I managed to do the registration and log-in part. After the login, the user profile shows up which contains some TextViews about the name, age, email, etc. and I want to read the data from the real-time database and put it in TextView.I don't know what is the problem but the TextViews won't show the data.
User profile class
public class ProfilUser extends AppCompatActivity {
private FirebaseUser user;
private DatabaseReference referinta;
private String userID;
private Button delogare;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profil_user);
delogare = (Button) findViewById(R.id.delogare);
delogare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(ProfilUser.this,MainActivity.class));
}
});
user = FirebaseAuth.getInstance().getCurrentUser();;
userID = user.getUid();
referinta = FirebaseDatabase.getInstance("https://rezervarebileteveniment-default-rtdb.europe-west1.firebasedatabase.app").getReference("Users").child(userID);
TextView bunVenitTextView = (TextView) findViewById(R.id.bunVenit);
TextView numeTextView = (TextView) findViewById(R.id.getNume);
TextView prenumeTextView = (TextView) findViewById(R.id.getPrenume);
TextView varstaTextView = (TextView) findViewById(R.id.getVarsta);
TextView emailTextView = (TextView) findViewById(R.id.getAdresaEmail);
referinta.child(userID).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
User profilUser = snapshot.getValue(User.class);
if(profilUser != null){
String nume = profilUser.nume;
String prenume = profilUser.prenume;
String email = profilUser.email;
String varsta = profilUser.varsta;
bunVenitTextView.setText("Buna ziua, "+nume + " "+prenume +"!");
numeTextView.setText(nume);
prenumeTextView.setText(prenume);
emailTextView.setText(email);
varstaTextView.setText(varsta);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(ProfilUser.this,"Ceva nu a mers bine!", Toast.LENGTH_LONG).show();
}
});
}
}
User class
package oct.alx.rezervarebileteveniment;
public class User {
public String nume, prenume , varsta, email;
public User(){
}
public User(String nume, String prenume, String varsta, String email){
this.nume = nume;
this.prenume = prenume;
this.varsta = varsta;
this.email = email;
}
public String getNume(){
return nume;
}
public void setNume(String nume){
this.nume = nume;
}
public String getPrenume() {
return prenume;
}
public void setPrenume(String prenume) {
this.prenume = prenume;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getVarsta() {
return varsta;
}
public void setVarsta(String varsta) {
this.varsta = varsta;
}
}
The problem in your code lies in the fact that you're calling .child(userID) twice, once when you create the reference:
referinta = FirebaseDatabase.getInstance("https://rezervarebileteveniment-default-rtdb.europe-west1.firebasedatabase.app")
.getReference("Users")
.child(userID); //👈
And second time when you attach the listener:
referinta.child(userID).addListenerForSingleValueEvent(/*... /*);
// 👆
This means that you're trying to read the data from a location that doesn't exist. To solve this, you either remove that method call from the first line of code or from the second one.
P.S. To use encapsulation, try to make all fields in your class private:
private String nume, prenume , varsta, email;
public class cp extends AppCompatActivity {
ListView ListPdf;
DatabaseReference databaseReference;
List<upload> uploadPdf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cp);
ListPdf = (ListView) findViewById(R.id.List);
uploadPdf = new ArrayList<>();
ViewAllPdf();
}
private void ViewAllPdf() {
databaseReference = FirebaseDatabase.getInstance().getReference("year_1");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot PostSnapShot: dataSnapshot.getChildren()){
upload Pdf = PostSnapShot.getValue(upload.class);
uploadPdf.add(Pdf);
}
String[] uploads = new String[uploadPdf.size()];
for(int i=0;i<uploads.length;i++){
uploads[i] = uploadPdf.get(i).getName();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(),android.R.layout.simple_list_item_1,uploads);
ListPdf.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
upload class
public class upload {
public String name;
public upload() {
this.name = name;
}
public String getName() {
return name;
}
}
In uploads[ ] it is storing null instead of file name,i cannot figure out what's the problem. I tried logcat for debuging but it shows Pdf object has three files but in uploads[ ] it stores NULL. Please look into it
Firebase database screenshot
The problem with your code is your POJO class Upload. See an example from Firebase Documentation
public class User {
public String username;
public String email;
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public User(String username, String email) {
this.username = username;
this.email = email;
}
}
Also the fields name in your Realtime Database doesn't match with your POJO class.
Fetching Data:
private void fetchResults() {
mDatabaseReference.child("Users").child(id).child("Quiz").child("Results").child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot resultSnapshot: dataSnapshot.getChildren()) {
String user = resultSnapshot.getKey();
String score = resultSnapshot.getValue(String.class);
Results results = new Results(user, score);
resultsList.add(results);
}
mAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
Saving Data:
String name = RecieversName;
HashMap<String, String> userMap = new HashMap<>();
userMap.put(name, String.valueOf(mScore));
mRef.child("Users").child(RecieversId).child("Quiz").child("Results").child(UID).setValue(userMap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Intent intent = new Intent(TakingQuiz.this, TakingQuizDone.class);
intent.putExtra("RecieversId",RecieversId);
intent.putExtra("Score", mScore.toString());
startActivity(intent);
finish();
}
}
});
Adapter:
public class AdapterQuiz extends RecyclerView.Adapter<AdapterQuiz.ResultViewHolder>{
private FirebaseAuth mAuth;
private List<Results> mResultsList;
public AdapterQuiz(List<Results>mResultsList)
{
this.mResultsList = mResultsList;
}
public class ResultViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView score;
public ResultViewHolder(View view)
{
super(view);
name = (TextView)view.findViewById(R.id.name);
score = (TextView)view.findViewById(R.id.score);
}
}
#Override
public ResultViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View V = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_activity_results,parent,false);
mAuth = FirebaseAuth.getInstance();
return new ResultViewHolder(V);
}
#Override
public void onBindViewHolder(ResultViewHolder holder, int position) {
Results results = mResultsList.get(position);
holder.name.setText(results.getName());
holder.score.setText(results.getScore());
}
#Override
public int getItemCount() {
return mResultsList.size();
}
}
Results Class
public class Results {
private String Name;
private String Score;
public Results() {
}
public Results(String Name, String Score) {
this.Name = Name;
this.Score = Score;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getScore() {
return Score;
}
public void setScore(String score) {
Score = score;
}
}
I have worked quite sometime on RecyclerView and Firebase but usually I would display a constant 'name' and a variable 'value' but here both name and variable is not decided by me... when the user finishes the quiz and his score will be displayed in the recyclerview but its just showing blank without any error... I'm not sure if this is the right way of fetching this kind of data... can anyone help me out please
Database - https://ibb.co/eMWkFJ
Results results;
String name, score;
private void fetchResults() {
mDatabaseReference.child("Users").child(id).child("Quiz").child("Results").child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) {
name = childDataSnapshot.getKey().toString();
score = childDataSnapshot.child(name).getValue());
results = new Results(user, score);
resultsList.add(results);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
I hope this will do your job.
To solve this, you first need to set the adapter before notifying it for changes. So please use the following line of code:
mRecyclerView.setAdapter(mAdapter);
Instead of this:
mAdapter.notifyDataSetChanged();
This last line of code should be used only when some changes take place in your database and in order to notify the adapter, this must be set in the fist place.
I am just having a problem when populating my list view. I think I know what's the problem since I tested it multiple times and it seems like the path for retrieving my data is actually the user store and not the bets but I don't seem to get where does the path come from. I was looking back at the methods and it seems that the path would be the DatabaseReference although my reference in the class is just standard
mDatabase = FirebaseDatabase.getInstance().getReference();
Here is my Adapter
public class CustomAdapter extends BaseAdapter{
Context c;
ArrayList<Bets> bets;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); //Getting currently logged user
DatabaseReference mDatabase;
String hours;
String samount;
public CustomAdapter(Context c, ArrayList<Bets> bets) {
this.c = c;
this.bets = bets;
}
#Override
public int getCount() {
return bets.size();
}
#Override
public Object getItem(int pos) {
return bets.get(pos);
}
#Override
public long getItemId(int itemid) {
return itemid;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
if(view == null)
{
view = LayoutInflater.from(c).inflate(R.layout.item_layout,viewGroup,false);
}
TextView condition = (TextView) view.findViewById(R.id.conditionList);
TextView place = (TextView) view.findViewById(R.id.placeList);
TextView amount = (TextView) view.findViewById(R.id.amountList);
final Bets bet = (Bets) this.getItem(position);
condition.setText(bet.getCondition());
place.setText(bet.getPlace());
String setamount = String.valueOf(bet.getAmount());
amount.setText(setamount);
hours = String.valueOf(bet.getHours());
samount = String.valueOf(bet.getAmount());
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
openDetailList(bet.getCreator(),bet.getCondition(),bet.getPlace(),hours,samount,bet.getJoined(),bet.getCreatorUid(),bet.getJoinedUid());
}
});
return view;
}
public void openDetailList(String...details)
{
Intent i = new Intent(c, ListDetail.class);
i.putExtra("CREATOR_KEY",details[0]);
i.putExtra("CONDITION_KEY",details[1]);
i.putExtra("PLACE_KEY",details[2]);
i.putExtra("HOURS_KEY",details[3]);
i.putExtra("AMOUNT_KEY",details[4]);
i.putExtra("JOINED_KEY",details[5]);
i.putExtra("CREATORUID_KEY",details[6]);
i.putExtra("JOINEDUID_KEY",details[7]);
c.startActivity(i);
}
}
and here is my FirebaseHelper
public class FirebaseHelper {
DatabaseReference db;
Boolean saved = null;
ArrayList<Bets> bets = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
public Boolean save(Bets bets)
{
if(bets == null)
{
saved = false;
}
else {
try {
db.child("bets").push().setValue(bets);
saved = true;
} catch (DatabaseException e) {
e.printStackTrace();
saved = false;
}
}
return saved;
}
private void fetchData(DataSnapshot dataSnapshot)
{
bets.clear();
for(DataSnapshot snapshot: dataSnapshot.getChildren())
{
Bets bet = snapshot.getValue(Bets.class);
bets.add(bet);
}
}
public ArrayList<Bets> retrieve()
{
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onComplete: Failed=" + databaseError);
}
});
return bets;
}
}
Saving/Inserting data works perfectly fine since I even have a sample data to show you after I added a bet but it doesn't populate the data.
{
"bets" :
{
"-LAzYM9SA-8Sg0YgGqnv" :
{
"amount" : 10,
"condition" : "It will be sunny",
"creator" : "Ginart",
"creatorUid" : "MxQPvCjUIkahVSZk1y2stdCxeY32",
"hours" : 2,
"joined" : "Free",
"joinedUid" : "",
"place" : "New York"
}
For some reason I think it reads the users data which is here
"users" : {
"EbYtfLUPs7Vu2rvnExaOaqJ4J883" : {
"balance" : 5,
"bets" : 1
},
Since every time I add a new user, the list view adds an Item to my list but with no data at all just my template and Android Studio shows me this
W/ClassMapper: No setter/field for balance found on class Models.Bets
W/ClassMapper: No setter/field for bets found on class Models.Bets
So it must be something wrong with the paths in my opinion. My Bets Model has no balance and bets variables.
Here is my OnCreate method where I'm using the retrieve() method in firebase
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logged_in);
Money = (EditText) findViewById(R.id.Balance);
User = (EditText) findViewById(R.id.Player);
betList = (ListView) findViewById(R.id.BetList);
addbet = (FloatingActionButton) findViewById(R.id.AddBet);
addcreds = (TextView) findViewById(R.id.addCredits);
Money.setInputType(0);
User.setInputType(0);
betting = FirebaseDatabase.getInstance().getReference();
mDatabase = FirebaseDatabase.getInstance().getReference();
helper = new FirebaseHelper(betting);
mDatabase.child("users").child(current.getUid().toString()).child("balance").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.
balance = dataSnapshot.getValue(Long.class);
String b = String.valueOf(balance);
Money.setText(b);
}
#Override
public void onCancelled(DatabaseError error) {
Money.setText("Error");
}
});
mDatabase.child("users").child(current.getUid().toString()).child("bets").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.
bets = dataSnapshot.getValue(Long.class);
}
#Override
public void onCancelled(DatabaseError error) {
}
});
User.setText(current.getDisplayName().toString());
//ADAPTER
adapter = new CustomAdapter(this,helper.retrieve());
betList.setAdapter(adapter);
addbet.setOnClickListener(this);
addcreds.setOnClickListener(this);
}
Also, whenever I'm trying to change my reference to
betting = FirebaseDatabase.getInstance().getReference().child("bets");
I get this error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: app.betme.betme, PID: 22814
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.Long to type Models.Bets
at com.google.android.gms.internal.zg.zzb(Unknown Source)
at com.google.android.gms.internal.zg.zza(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
at Utils.FirebaseHelper.fetchData(FirebaseHelper.java:67)
at Utils.FirebaseHelper.access$000(FirebaseHelper.java:21)
at Utils.FirebaseHelper$1.onChildAdded(FirebaseHelper.java:81)
at com.google.android.gms.internal.px.zza(Unknown Source)
at com.google.android.gms.internal.vj.zzHX(Unknown Source)
at com.google.android.gms.internal.vp.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
It's not error, It's just a waring from Firebase that you should have methods to set data for balance and bets
I'm working on getting a simple messaging system working using Firebase. But this one thing is causing me to want to pull out my own hair. I have a map that I'm using to store <String,Message> pairs, where Message is a class I wrote. I can't get my messages out of the map though. I've isolated the problem to be with map.get(key) not returning the Message, even though map.containsKey(key) returns true. What could be causing this and how do I fix it?
Here's the Message class:
public class Message {
private long timeStamp;
private String message;
private String to;
private String from;
public Message(String message, String to, String from)
{
timeStamp = new Date().getTime();
this.message = message;
this.to = to;
this.from = from;
}
public Message(){
}
public String getMessageText() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTo() {
return this.to;
}
public void setTo(String to) {
this.to = to;
}
public String getFrom() {
return this.from;
}
public void setFrom(String from) {
this.from = from;
}
public long getTimeStamp() {
return this.timeStamp;
}
public void setTimeStamp(long timeStamp) {
this.timeStamp = timeStamp;
}
}
This is the code I used that showed me map.containsKey(key) returns true:
public class LoadMessages extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_messages);
// Load previous messages
final LinearLayout messagesLayout = (LinearLayout) findViewById(R.id.messagesLayout);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = database.getReference(getIntent().getStringExtra("user") + "/Messages");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Map<String, Message> map = new TreeMap<String, Message>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Message m = snapshot.getValue(Message.class);
map.put(String.valueOf(m.getTimeStamp()), m);
TextView TV = new TextView(LoadMessages.this);
Boolean ck = map.containsKey(String.valueOf(m.getTimeStamp()));
if (ck) {
TV.setText("Contains key");
} else {
TV.setText("Doesn't contain key.");
}
messagesLayout.addView(TV);
}
// code to iterate through map entries and display messages
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// code Add new message onClick of fab
}
}
And this version of the code shows nothing in the TextView:
public class LoadMessages extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_messages);
// Load previous messages
final LinearLayout messagesLayout = (LinearLayout) findViewById(R.id.messagesLayout);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = database.getReference(getIntent().getStringExtra("user") + "/Messages");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Map<String, Message> map = new TreeMap<String, Message>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Message m = snapshot.getValue(Message.class);
map.put(String.valueOf(m.getTimeStamp()), m);
TextView TV = new TextView(LoadMessages.this);
Message test = map.get(String.valueOf(m.getTimeStamp()));
TV.setText(test.getMessageText());
messagesLayout.addView(TV);
}
// code to iterate through map entries and display messages
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// code Add new message onClick of fab
}
}
Edit: Here's my database structure:
I think the problem is that snapshot.getValue(Message.class) returns null.
TreeMap can store null as a value, so while it contains your key the value is actually null.
Okay, I figured it out! It turns out that the message String in Message was being changed to messageText in the database, so when I tried to extract it into a Message object it wouldn't recognize it. The fix was to change the message String in the Message class to messageText.