2016-10-11 2 views
1

데이터베이스를 쿼리하고 쿼리가 끝난 후 다른 메서드를 수행 할 메서드를 작성하고 있습니다. 데이터베이스에 대한 호출이 비동기이기 때문에,하지만, 나는 데이터베이스 호출이 완료 될 때까지과 같이 실행의 주요 흐름을 중지하는 방법을 알아낼 수 없습니다Java에서의 비동기 실행 흐름

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 
} 

내가 작업에 사용 해요 Nodejs에서 비동기 콜백을 사용하지만 Java에서 실행 흐름을 제어하는 ​​동등한 방법이 있는지 알아낼 수 없습니다. 내가하고 싶은 것을 성취 할 수있는 쉬운 방법이 있습니까?

답변

1

주 흐름을 중단 할 수 없습니다. 주 스레드는 계속 진행됩니다. (그렇지 않으면 당신이 그것을 멈추지 만 "Application Not Responding"이 생길 것입니다. 그렇게하지 마십시오).

콜백의 동작 만 수행하면됩니다.

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 
} 

노드 배경에서 온 사람은 아마도 이와 비슷할 것입니다. 당신이 정말로 잠금을 사용하려는 경우 getUserFromEmail

public void otherMethod() { 
    getUserFromEmail("[email protected]", 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); 
} 
+0

내가 콜백이 완료되면 원래 meyhod에서 값을 반환하기를 원한다면 무엇? – Matt

+1

메소드가'void '입니다. 너는 돌아갈 수 없다. 사실, 당신도 그래야합니다. 비동기가'return' 문으로 잘 작동하지 않습니다 –

+1

콜백 내의'dataSnapshot'에서 얻은 데이터로 직접 UI를 업데이트 할 수 있습니다 –

0

에 기능을 함께 전달하면 당신은 흐름을 제어 할 수 있습니다. 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(); 
} 

그러나이 방법은 중포 기지 일부 데이터를 반환 할 때까지 getUserFromEmail 실행 스레드를 차단합니다. 특히 UI 스레드에서 getUserFromEmail으로 호출하면 UI 스레드가 차단되고 ANR이 발생합니다.

그것은 너무 같은 콜백 방식을 따라하는 것이 좋습니다 :

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("[email protected]", new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      // Do stuff after getting the email here 
     } 

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

마지막으로 ANR에 대한 리드를 확인했습니다. http://stackoverflow.com/a/33204705/209103 –

+0

에서 내 업데이트를 확인하십시오. UI 스레드에서 실행하면 yes, 그렇지 않은 경우 no로 실행하십시오. UI 스레드에서 해당 메서드를 사용하는 것에 대해 사람들에게 경고하는 답변에 추가되었습니다. –