nothingness
nothingness

Reputation: 694

return an object Android

I want to return an object with some things in them.

Here is the declaration;

Object user_det = get_user_det();

Here is the function code:

        private Object get_user_det() {
        Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
        f_user.addListenerForSingleValueEvent(new ValueEventListener(){
            @Override
            public void onDataChange(DataSnapshot snap_user) {
                // TODO Auto-generated method stub
                Iterable<DataSnapshot> rs = snap_user.getChildren();
                Iterator<DataSnapshot> irs = rs.iterator();
                long allNum2 = snap_user.getChildrenCount();
                int maxNum2 = (int)allNum2;
                int count_user = 1;
                while(irs.hasNext())
                {
                    if(count_user <= maxNum2)
                    {
                        Firebase user_data = new Firebase("https://myapp.firebaseio.com/"); 
                        AuthData authData = user_data.getAuth();
                        Map<String, Object> nPost = (Map<String, Object>) irs.next().getValue();

                        String db_email = nPost.get("email_addr").toString();

                        if (authData != null) {
                            String usr_email = authData.getProviderData().get("email").toString();
                            if(usr_email.equals(db_email))
                            {
                      //NB: I WANT TO ADD THE FOLLOWING INTO THE OBJECT
                                String disp_name = nPost.get("disp_name").toString();
                                String real_name = nPost.get("real_name").toString();
                            }

                        } else {
                            System.out.println("Failed");
                        }
                    }
                    count_user++;
                }                       
            }
            @Override
            public void onCancelled(FirebaseError arg0) {
                // TODO Auto-generated method stub

            }
    }); 
    return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}

I want to return the string disp_name and real_name but they are inside the addListenerForSingleValueEvent, so how do I get them out and return it to the function.

I have wrote "NB" in the code where I need help with.

Thanks for your time.

Upvotes: 1

Views: 3779

Answers (3)

Chad Bingham
Chad Bingham

Reputation: 33876

How it works:

Firebase uses reflection to build a JSON tree object to save to the database. When you retrieve this JSON tree, you can cast it back to your original object. Just like serializing and deserializing. This means you do not need to handle the keys and values when trying to "rebuild" your object like you are. It can all be done like so:

YourObject object = (YourObject) dataSnapshot.getValue(YourObject.class);

Notice the YourObject.class in the getValue(). This tells firebase to reflect through this class and find the appropriate accessors with the dataSnapshot.


How to do it

Be sure that your object has:

  1. Accessors Appropriate getters and setters for ALL fields - (or annotated with @JsonIgnore if you wish to not save a particular field)
  2. Empty constructor. Your object must provide a constructor that does not modify itself at all.

What your object should look like:

public class YourObject {

     private String displayName;
     private String realName;   

     public YourObject() { /*Empty constructor needed for Firebase */ }

     // Accessors

     public void setRealName(String realName){
        this.realName = realName;
     }

     public String getRealName(){
        return this.realName;
     }

     public String getDisplayName(){
        return this.displayName;
     }

     public void setDisplayName(String displayName){
        this.displayName = displayName;
     } 
 }

Then, in any of the firebase callbacks, you can just cast your DataSnapshot in to your object:

public void onDataChange(DataSnapshot snap_user) {
      YourObject object = new Object;
      if(snap_user.getValue() != null) {
        try {
           object = (YourObject) snap_user.getValue(YourObject.class); <-- Improtant!!!
        } catch(ClassCastException ex) {
           ex.printStackTrace();
        }
      }
   return object;
}

Also

It seems you are retrieving many objects. When doing this, I find it best to use the onChildEventListener then for each of the YourObjects in that node, onChildAdded(DataSnapshot ds, String previousChild); will be called.

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 599726

It's probably easiest to see what's going on, if you add some printlns to your code:

private Object get_user_det() {
    Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
    System.out.println("Adding listener");
    f_user.addListenerForSingleValueEvent(new ValueEventListener(){
        @Override
        public void onDataChange(DataSnapshot snap_user) {
            System.out.println("Data received");
        }
        @Override
        public void onCancelled(FirebaseError arg0) {
            // TODO Auto-generated method stub                  
        }
    });
    System.out.println("Returning");
    return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}

If you execute this code, you will see that it logs:

Adding listener
Returning
Data received

Most likely, this is not what you expected. But hopefully, it makes sense if you read my explanation below.

Asynchronous loading

When you register your listener:

 f_user.addListenerForSingleValueEvent(new ValueEventListener(){

You tell Firebase to start listening for events. It goes off and starts retrieving the data from the server.

Since retrieving the data may take some time, it does this retrieval asynchronously so that your thread isn't blocked. Once the data is completely retrieved, Firebase calls the onDataChange method in your listener.

Between the time you start listening and the time onDataChange is called, your code continues executing. So there is no way to return data that is loaded asynchronously, because by the time your function returns, the data isn't loaded yet.

Solutions

Disclaimer: I am not an expert at solving this problem in Java, so there may be problems with my solutions. If^H^HWhen you find any, please report them in the comments.

I know of three possible solutions to the problem:

  1. force the code to wait for the data to be returned
  2. return a Future that at some point will contain the data
  3. pass a callback into get_user_det and call that function once the data is available

You will probably be tempted to selected option 1, since it matches most closely with your mental modal of loading data. While this is not necessarily wrong, keep in mind that there is a good reason that the loading is done asynchronously. It might be worth taking the "learning how to deal with asynchronicity" penalty now.

Instead of writing up examples for all solutions, I'll instead refer to some relevant questions:

Upvotes: 1

Jonas Czech
Jonas Czech

Reputation: 12348

If you want to return an object from your method in java, do it like this:


The Object class: This contains the structure of your Object, and defines what data will be in it. Also includes methods to easily get the data.

private class myObject {
     private String name;
     private String realName;

     //The constructor, so you can set the data when creating the Object.
     public myObject (String disp_name, String real_name) {
         name = disp_name;
         realName = real_name;
     }

     //Getter methods, to get the data.
     public String getRealName() {return realName;}
     public String getDisplayName() {return name;}
}

Your code:

private Object get_user_det() {
    myObject o;  //Declare it, so it can be returned.
    ...
    String disp_name = nPost.get("disp_name").toString();
    String real_name = nPost.get("real_name").toString();

    o = new myObject(disp_name, real_name); //create it and set the data.
    ...
    return myobject; //return the new Object with the data.
}

To get the data from the Object:

myObject o = get_user_det(); //Call the metod which return our Object.
String realName = o.getRealName(); //Get the data from the Object.
String displayName = o.getDisplayName;

In your case, it would be much easier to use a String array.

Hope this helps.

Upvotes: 2

Related Questions