火力:如何捕获实时数据火力、实时、数据

2023-09-03 22:19:51 作者:橘黄色日落

我想在我从一个侦听单个事件调用获得方法返回的数据。但是,它看起来像我返回时被填充的实际回报语句之后的对象。据我所知,调用来获取数据快照是异步的,这就是为什么这种情况正在发生。我怎样才能避免这种情况?我试过信号量和原子布尔值,但它只是似乎锁定了我的申请。这里是code问题。

I am trying to return data in a method that I get from a listener for single event call. However, it looks like the object I'm returning is being populated after the actual return statement. I understand that the call to get the data snapshot is asynchronous and that is why this is happening. How can I avoid this? I've tried Semaphores and Atomic Booleans but it just seems to lock up my application. Here is the code in question.

static User getUser(String uid){
    /**** created final object here for returning ****/
    final User returnUser = new User();

    Firebase userRef = new Firebase("<firebase-url>/users/"+uid+"/");

    userRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Log.d("MT", "attempting to instantiate user");
            User tempUser = dataSnapshot.getValue(User.class);

            /**** preparing object for return ****/
            returnUser.setNickname(tempUser.getNickname());
            returnUser.setAge(tempUser.getAge());
            returnUser.setEmail(tempUser.getEmail());
            returnUser.setHeight(tempUser.getHeight());
            returnUser.setSex(tempUser.getSex());
            returnUser.setWeight(tempUser.getWeight());

            //This logs actual information
            Log.d("MT", returnUser.getNickname() + " =======INSTANTIATED=======."); 
            Log.d("MT", returnUser.getEmail());
            Log.d("MT", new Double(returnUser.getAge()).toString());
            Log.d("MT", new Double(returnUser.getHeight()).toString());
            Log.d("MT", returnUser.getSex());
            Log.d("MT", new Double(returnUser.getWeight()).toString());
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.d("MT", "Something went wrong.");
        }
    });
    Log.d("MT", returnUser.getNickname());    //This logs an empty string.
    return returnUser;
}

注:我已经试过原子布尔值设置为false然后设置为true的侦听器内,然后有一段时间(布尔==假的),才返回,但这个结果在我的应用程序的锁定。

Note: I've tried Atomic boolean set to false then set to true within the listener and then have a while(boolean == false) before I return but this results in a lockup of my application.

推荐答案

什么,你正在试图做的是使火力地堡同步。

What you're attempting to do is make Firebase synchronous.

这是可能的,但它是一个非常糟糕的主意。它会冒险做网络运营的主线上。一个模式,使得Android的非常暴躁。见他们的一般指导做网络上的东西一个单独的线程。

This may be possible, but it's a very bad idea. It'd risk doing network operations on the main thread. A pattern that makes Android very grumpy. See their general guidance on doing network stuff on a separate thread.

所以,已经确定了它的好,做网络的东西在不同的线程,我对你的好消息。火力地堡已经自动干这种事!指定回调,就像你在一个的AsyncTask

So, having established that it's good to do network stuff on a different thread, I have good news for you. Firebase already does this automatically! Specify a callback, just like you would in an AsyncTask.

更改您的getter接受回调作为参数。

Change your getter to accept a callback as a parameter.

public void getUser(String uid, AwesomeCallback callback){

    Firebase userRef = new Firebase("<firebase-url>/users/"+uid+"/");

    userRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Log.d("MT", "attempting to instantiate user");
            User returnUser = new User();
            User tempUser = dataSnapshot.getValue(User.class);

            /**** preparing object for return ****/
            returnUser.setNickname(tempUser.getNickname());
            returnUser.setAge(tempUser.getAge());
            returnUser.setEmail(tempUser.getEmail());
            returnUser.setHeight(tempUser.getHeight());
            returnUser.setSex(tempUser.getSex());
            returnUser.setWeight(tempUser.getWeight());

            //This logs actual information
            Log.d("MT", returnUser.getNickname() + " =======INSTANTIATED=======."); 
            Log.d("MT", returnUser.getEmail());
            Log.d("MT", new Double(returnUser.getAge()).toString());
            Log.d("MT", new Double(returnUser.getHeight()).toString());
            Log.d("MT", returnUser.getSex());
            Log.d("MT", new Double(returnUser.getWeight()).toString());

            callback.doCallback(returnUser);
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.d("MT", "Something went wrong.");
        }
    });
}

,然后从回调函数做你的工作

And then, do your work from the callback function

public class SomeAwesomeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        someObject.getUser("uid123", new AwesomeCallback() {
            @Override
            public void doCallback(User user) {
                // Do cool stuff with that user object here
            }
        });
    }
}

如果您还没有过去做了很多回调编程,这是一个有点古怪,这将需要一些时间来习惯它。不过,一旦你掌握了它,Android开发变得顺利。许多内置了Android SDK构建依赖于这种模式。

If you haven't done a lot of callback programming in the past, it's a bit weird, and it will take some time to get used to it. However, once you've mastered it, Android development goes much more smoothly. Lots of constructs built into the Android SDK depend on this pattern.

 
精彩推荐
图片推荐