简体   繁体   English

Java中的异步执行流程

[英]Asynchronous flow of execution in Java

I'm writing a method where I want to query a database and perform another method after the query has finished.我正在编写一个方法,我想在其中查询数据库并在查询完成后执行另一种方法。 Since the call to the database is asynchronous, though, I can't seem to figure out how to stop the main flow of execution until the database call is complete, like so:但是,由于对数据库的调用是异步的,我似乎无法弄清楚如何在数据库调用完成之前停止主要执行流程,如下所示:

public void getUserFromEmail(String email) {
    Firebase usersRef = rootRef.child("users");

    //Asynchronous database call, want to stop everything else 
    usersRef.orderByKey().equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            System.out.println(firebaseError.getMessage());
        }
    });
    //Perform some more operations after database call is finished
}

I'm used to working with asynchronous callbacks in Nodejs, but I can't figure out if there's any equivalent way of controlling execution flow in Java.我习惯于在 Nodejs 中使用异步回调,但我不知道在 Java 中是否有任何等效的方法来控制执行流程。 Is there any easy way to achieve what I want to do?有什么简单的方法可以实现我想做的事情吗?

You can't stop the main flow, the main thread will continue on.你不能停止主流程,主线程会继续。 (Unless you otherwise stop it, but that will cause "Application Not Responding", so don't). (除非您以其他方式停止它,但这会导致“应用程序无响应”,所以不要)。

Just do the action in the callback.只需在回调中执行操作即可。

public void getUserFromEmail(String email) {
    Firebase usersRef = rootRef.child("users");

    //Asynchronous database call, want to stop everything else 
    usersRef.orderByKey().equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // Perform some more operations after database call is finished
            // OR... callSomeMethod();
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            System.out.println(firebaseError.getMessage());
        }
    });

}

public void callSomeMethod() {
    // Perform some more operations after database call is finished
}

If you come from a Node background, then maybe this looks similar.如果您来自 Node 背景,那么这可能看起来很相似。 Passing along the function to getUserFromEmail将函数传递给getUserFromEmail

public void otherMethod() {
    getUserFromEmail("steve@example.com", new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // Perform some more operations after database call is finished
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            System.out.println(firebaseError.getMessage());
        }
    });
}

public void getUserFromEmail(String email, ValueEventListener listener) {
    rootRef.child("users")
        .orderByKey()
        .equalTo(email)
        .addListenerForSingleValueEvent(listener);
}

You can control the flow if you really want to using locks.如果你真的想使用锁,你可以控制流程。 For instance using CountdownLatch :例如使用CountdownLatch

public DataSnapshot getUserFromEmail(String email) throws InterruptedException {
    AtomicReference<DataSnapshot> dataSnapshotRef = new AtomicReference<DataSnapshot>();
    CountDownLatch completeSignal = new CountDownLatch(1);

    Firebase usersRef = rootRef.child("users");

    //Asynchronous database call, want to stop everything else 
    usersRef.orderByKey().equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            dataSnapshotRef.set(dataSnapshot);
            // Causes execution of the waiting thread to continue
            // from the `await` call
            completeSignal.countDown();
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            completeSignal.countDown();
        }
    });

    // Execution on this thread pauses at the `await` call until
    // countDown has been called from another thread.
    completeSignal.await();

    // Do stuff after onDataChanged or onCancelled has been called
    DataSnapshot dataSnapshot = dataSnapshotRef.get();
}

However this approach will block the thread that executed getUserFromEmail until Firebase has returned some data.然而,这种方法会阻塞执行getUserFromEmail的线程,直到 Firebase 返回一些数据。 Particularly, if you call getUserFromEmail from your UI thread then this will block the UI thread and cause an ANR.特别是,如果您从 UI 线程调用getUserFromEmail ,那么这将阻塞 UI 线程并导致 ANR。

It is better to follow the callback approach like so:最好遵循这样的回调方法:

public DataSnapshot getUserFromEmail(String email, ValueEventListener listener) {
    Firebase usersRef = rootRef.child("users");

    //Asynchronous database call, want to stop everything else 
    usersRef.orderByKey().equalTo(email).addListenerForSingleValueEvent(listener);
}

public void getUserAndThenDoSomething() {
    getUserFromEmail("bob@example.com", new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // Do stuff after getting the email here
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
        }
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM