0

In my project, I am implementing a login system using Firebase Authentication. Since I am using email logins, I cannot store the name of any of my users in the authentication - instead, I am storing them in the realtime database as children of the userId. So my database structure looks like this:

fireapp 
   +users
     +userID
       Name: <name>

Where each user will have a record according to their ID.

When my user logs in, they will be taken to the home screen that has a navigation drawer. In the header of this drawer, I would like to display the user's name and email. So far I have set the email using FirebaseAuth, but setting the name has proven more difficult.

This is the code I am using currently:

String userId = mAuth.getUid();
TextView userEmail = (TextView) findViewById(R.id.lblHeaderName);

FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference ref = db.getReference("users/" + userId);
ref.addValueEventListener(new ValueEventListener()
{
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot)
    {
        //Retrieve the user's name and set the textview in the header accordingly
        String name = dataSnapshot.getValue(String.class);
        userName.setText(name);
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError)
    {
        //If the task is not successful, print an error message
        Toast.makeText(HomeScreen.this, "Error retrieving data from database: " + databaseError.getCode(), Toast.LENGTH_LONG).show();

    }
});

Here I am first getting the current user's ID and using that as the database path. Next I'm trying to get the name of the user and assign it to a string (since that is the only attribute I have stored for each user). finally setting it as the text of userName. When I run the code, the app crashes with this error:

2019-05-01 12:54:33.882 6447-6447/com.mobileappscw3.nrcforums E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.mobileappscw3.nrcforums, PID: 6447
    com.google.firebase.database.DatabaseException: Failed to convert value of type java.util.HashMap to String
        at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertString(com.google.firebase:firebase-database@@16.1.0:413)
        at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database@@16.1.0:199)
        at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database@@16.1.0:79)
        at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database@@16.1.0:212)
        at com.mobileappscw3.nrcforums.HomeScreen$1.onDataChange(HomeScreen.java:76)
        at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@16.1.0:75)
        at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@16.1.0:63)
        at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@16.1.0:55)
        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:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

Where HomeScreen.java:76 is this line in my code:

String name = dataSnapshot.getValue(String.class);

The tutorial that I was following used a String variable and parameter and it worked. However, every other example of this problem I have looked at uses User objects to retrieve data - however since I only have one attribute stored about the users (and this app is more proof-of-concept rather than a real working app), I would prefer not to use objects if possible. Can anyone help?

0

3 Answers 3

5

Change this:

String name = dataSnapshot.getValue(String.class);

into this:

String name = dataSnapshot.child("Name").getValue(String.class);
Sign up to request clarification or add additional context in comments.

Comments

3

It might help you out: Firebase "Failed to convert a value of type java.util.HashMap to int"

You might want to change String name = dataSnapshot.getValue(String.class);

to:

String name = dataSnapshot.child("users").child("userID").getValue(String.class);

Comments

3

Some of the other answers already show you how to read a specific property from a DataSnapshot inside the onDataChange method.

If you only need a single property, an alternative would be to attach your listener to just that property:

DatabaseReference ref = db.getReference("users/" + userId + "/Name");
ref.addValueEventListener(new ValueEventListener()
{
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot)
    {
        //Retrieve the user's name and set the textview in the header accordingly
        String name = dataSnapshot.getValue(String.class);
        userName.setText(name);
    }

The advantage of this is that the listener only reads/downloads the single property that is used inside the onDataChange, so it uses less bandwidth.

1 Comment

Ah, that's actually quite a good idea - I wasn't aware that you could put attributes in the path, but looking back that's common sense. As I said, this was more proof-of-concept rather than an actual deployment version, so I'm not overly fussed on performance currently. However, I will keep this in mind for actual projects - thanks very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.