使Java线程等待值

时间:2018-02-24 07:13:21

标签: java android multithreading firebase-realtime-database

我需要从他们的UID中检索Firebase数据库中的用户名。这是我执行此操作的代码,但我无法弄清楚如何使其正常工作。该主题来自:

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

立即:

return returnName[0].toString();

不等待它首先从侦听器填充数据,因此返回值为null并且应用程序崩溃。以下是此模块的完整代码:

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();
}

我花了几个小时阅读并尝试使用它来实现这个功能,但是我无法在启动返回值之前先让代码实际执行正确。

任何人都可以帮助我吗?

@TaherKorshidi 这是调用此函数的代码:

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);
    }
}

回答,@ TaherKorshidi的答案是在同一个监听器中获取其他值。没有别的方法可以解决这个问题,直到你把我指向这个方向,我才能确定怎么做。工作解决方案:

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);
                    }
                }

2 个答案:

答案 0 :(得分:1)

您可以将asyncTask用于此目的,如下所示

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);
    }
}

您可以从onCreate()调用此类,如下所示

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);
    }
}

然后你可以使用这种方法将你的friendName分配给一个字符串值并在那里工作

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

此方法是从onPostExecute()调用的。

答案 1 :(得分:0)

一种方法是使用CountDownLatch类:

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();
}

虽然它解决了你的问题,但它不是一个好的解决方案。