Bisclavret
Bisclavret

Reputation: 1351

Making Java thread wait for value

I need to retrieve a users name from my Firebase database from their UID. This is my code for doing this, but I cannot work out how to get this working. The thread goes from:

final String[] returnName = new String[1];

Immediately to:

return returnName[0].toString();

Without waiting for it to populate data from the listener first, so the return value is null and the app crashes. Here is my full code for this module:

private synchronized String getFriendName(String key) {
    final String[] returnName = new String[1];
    DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Profiles").child(key).child("Name");
    ref.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot datas : dataSnapshot.getChildren()) {
                String userResult = datas.getKey();
                if (userResult != null) {
                    returnName[0] = dataSnapshot.getValue().toString();
                    String temp = dataSnapshot.getValue().toString();
                    Toast.makeText(getBaseContext(), "Step 1: " + temp, Toast.LENGTH_SHORT).show();
                    Toast.makeText(getBaseContext(), "Step 2: " + returnName[0], Toast.LENGTH_SHORT).show();
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    return returnName[0].toString();
}

I have spent hours reading and trying stuff to get this to work but I cannot make the code actually execute properly first before firing off the return value.

Can anyone help me?

@TaherKorshidi This is the code that calls this function:

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(currentLocation.latitude, currentLocation.longitude), radius);
geoQuery.removeAllListeners();

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
        friendID = key;
        String friend = getFriendName(friendID);
    }
}

Answer, @TaherKorshidi the answer was to get the other values in the same listener. There is no other way around this and I wasn't sure how to do it until you pointed me in this direction. Working solution:

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
                @Override
                public void onKeyEntered(String key, GeoLocation location) {
                    getFriendKey = key;
                    if (getFriendKey != ping_userID) {
                        for(ContactsList d : UserList){
                            if(d.getUID() != null && d.getUID().contains(getFriendKey)) {
                                friendName = d.getName();
                            }
                        }
                        Toast.makeText(getBaseContext(), "Name: " + String.valueOf(friendName), Toast.LENGTH_SHORT).show();
                        getFriendLocation(getFriendKey, friendName);
                    }
                }

Upvotes: 0

Views: 145

Answers (2)

Sagar A
Sagar A

Reputation: 89

You can use asyncTask for this purpose as below

public static class GetFriendName extends AsyncTask<String, Void, Void>{

    String returnName;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //Show progress bar
    }

    @Override
    protected Void doInBackground(String... strings) {
        DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Profiles").child(key).child("Name");
        ref.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                for (DataSnapshot datas : dataSnapshot.getChildren()) {
                    String userResult = datas.getKey();
                    if (userResult != null) {
                        returnName = dataSnapshot.getValue().toString();
                        String temp = dataSnapshot.getValue().toString();
                    }
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        //Dismiss progress bar
        showFriendName(returnName);
    }
}

you can call this class from onCreate() as below

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(currentLocation.latitude, currentLocation.longitude), radius);
geoQuery.removeAllListeners();

geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
        friendID = key;
        new GetFriendName().execute(friendID);
    }
}

then you can assign your friendName to a string value by using this method and do your work there

private static void showFriendName(String friendName){
    Toast.makeText(stackOverflowActivity, ""+friendName, Toast.LENGTH_SHORT).show();
    String friend = friendName;
    //Do your work here
}

this method is calling from onPostExecute().

Upvotes: 1

Farvardin
Farvardin

Reputation: 5424

one way is to use CountDownLatch class:

private synchronized String getFriendName(String key) {
    final String[] returnName = new String[1];
    DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Profiles").child(key).child("Name");
    final CountDownLatch latch = new CountDownLatch(1);
    ref.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot datas : dataSnapshot.getChildren()) {
                String userResult = datas.getKey();
                if (userResult != null) {
                    returnName[0] = dataSnapshot.getValue().toString();
                    String temp = dataSnapshot.getValue().toString();
                    Toast.makeText(getBaseContext(), "Step 1: " + temp, Toast.LENGTH_SHORT).show();
                    Toast.makeText(getBaseContext(), "Step 2: " + returnName[0], Toast.LENGTH_SHORT).show();
                    latch.countDown();
                }
            }
            latch.countDown();
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return returnName[0].toString();
}

although it solve your problem, but it is not a good solution.

Upvotes: 0

Related Questions