programing

방법의 결과로 데이터 스냅샷 값을 반환하는 방법은 무엇입니까?

iphone6s 2023. 7. 16. 12:53
반응형

방법의 결과로 데이터 스냅샷 값을 반환하는 방법은 무엇입니까?

저는 자바에 대한 경험이 많지 않습니다.이 질문이 바보 같은 질문인지는 모르겠지만 Firebase 실시간 데이터베이스에서 사용자 이름을 가져와 이 방법으로 이 이름을 반환해야 합니다.그래서 저는 이 값을 얻는 방법을 알아냈지만, 이 방법의 결과로 어떻게 반환해야 하는지 이해할 수 없습니다.이것을 하는 가장 좋은 방법은 무엇입니까?

private String getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
            .addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // How to return this value?
            dataSnapshot.getValue(String.class);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

이는 비동기식 웹 API의 고전적인 문제입니다.당신은 아직 적재되지 않은 물건은 지금 반품할 수 없습니다. 즉, 글벌변생성외사수없다습니용부할서여에하 밖에서 사용할 수는 없습니다.onDataChange()방법은 항상 그럴 것이기 때문입니다.null은 이런일일이유는는나 때문에 입니다.onDataChange()메서드를 비동기라고 합니다.연결 속도와 상태에 따라 해당 데이터를 사용할 수 있을 때까지 수백 밀리초에서 몇 초 정도 걸릴 수 있습니다.

그러나 Firebase Realtime Database는 데이터를 비동기식으로 로드할 뿐만 아니라 시간이 걸릴 수 있으므로 거의 모든 최신 웹 API도 로드합니다.따라서 데이터를 기다리는 대신(사용자가 응답하지 않는 애플리케이션 대화 상자로 이어질 수 있음) 기본 애플리케이션 코드는 데이터가 보조 스레드에 로드되는 동안 계속됩니다.그런 다음 데이터를 사용할 수 있으면 onDataChange() 메서드가 호출되고 데이터를 사용할 수 있습니다.다시 말해서, 그때쯤이면onDataChange()메서드를 데이터가 아직 로드되지 않았습니다.

예를 들어, 코드에 로그 문을 몇 개 배치하여 무슨 일이 일어나고 있는지 좀 더 명확하게 확인해 보겠습니다.

private String getUserName(String uid) {
    Log.d("TAG", "Before attaching the listener!");
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // How to return this value?
            dataSnapshot.getValue(String.class);
            Log.d("TAG", "Inside onDataChange() method!");
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
    Log.d("TAG", "After attaching the listener!");
}

이 코드를 실행하면 출력은 다음과 같습니다.

수신기를 연결하기 전에!

청취자를 부착한 후!

Inside on Data Change() 메서드!

이것은 아마도 당신이 예상했던 것이 아닐 것이지만, 그것은 당신의 데이터가 왜null반품시에

대부분의 개발자들의 초기 반응은 이것을 "수정"하는 것입니다.asynchronous behavior개인적으로 이에 반대하는 것을 추천합니다.웹은 비동기식이며, 최신 웹 API로 생산성을 높이는 방법을 더 빨리 배울 수 있다는 것을 더 빨리 받아들일수록 좋습니다.

저는 이 비동기식 패러다임에 대한 문제를 재구성하는 것이 가장 쉽다는 것을 알게 되었습니다."먼저 데이터를 가져온 다음 기록합니다."라고 말하는 대신 "데이터를 가져오기 시작합니다."라고 문제를 설정합니다.데이터가 로드되면 기록합니다.", 는 즉, 데이가필코내부있합니다어야에드요는 안에 있어야 합니다.onDataChange()메소드 또는 내부에서 호출됩니다.

databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // How to return this value?
        if(dataSnapshot != null) {
            System.out.println(dataSnapshot.getValue(String.class));
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
});

만약 당신이 그것을 밖에서 사용하고 싶다면, 다른 접근법이 있습니다.Firebase에서 데이터를 반환할 때까지 기다리려면 직접 콜백을 만들어야 합니다.를▁an합다를 만들어야 .interface다음과 같이:

public interface MyCallback {
    void onCallback(String value);
}

그런 다음 실제로 데이터베이스에서 데이터를 가져오는 메서드를 만들어야 합니다.이 방법은 다음과 같습니다.

public void readData(MyCallback myCallback) {
    databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            String value = dataSnapshot.getValue(String.class);
            myCallback.onCallback(value);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

마지막에는 그냥 전화만 하면 됩니다.readData() and pass of 의 MyCallback인터페이스는 다음과 같이 필요한 모든 곳에서 인수로 사용됩니다.

readData(new MyCallback() {
    @Override
    public void onCallback(String value) {
        Log.d("TAG", value);
    }
});

이것이 당신이 그 값을 밖에서 사용할 수 있는 유일한 방법입니다.onDataChange()방법.자세한 내용은 이 비디오를 참조하십시오.

편집: 2021년 2월 26일

자세한 내용은 다음 문서를 참조하십시오.

그리고 다음 비디오:

"19.6.0" 버전부터 Firebase Realtime Database SDK에는 Database Reference 또는 Query 개체에서 호출할 수 있는 get()이라는 새로운 메서드가 포함되어 있습니다.

로컬 캐시에서 이전 데이터를 사용할 수 있는 경우에도 서버에서 데이터를 반환하는 DatabaseReference#get() 및 Query#get()이 추가되었습니다.

이미 알고 있듯이 Firebase API는 비동기식입니다.그래서 우리는 그것에 대한 콜백을 만들어야 합니다.먼저 인터페이스를 만듭니다.

public interface FirebaseCallback {
    void onResponse(String name);
}

그리고 ty FirebaseCallback의 객체를 인수로 사용하는 메서드:

public void readFirebaseName(FirebaseCallback callback) {
    DatabaseReference uidRef = databaseReference.child(String.format("users/%s/name", uid))
    uidRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DataSnapshot> task) {
            if (task.isSuccessful()) {
                String name = task.getResult().getValue(String.class);
                callback.onResponse(name);
            } else {
                Log.d(TAG, task.getException().getMessage());
            }
        }
    });
}

이제 데이터를 읽으려면 인수로 전달하는 위의 메서드를 FirebaseCallback 유형의 개체라고 부르기만 하면 됩니다.

readFirebaseName(new FirebaseCallback() {
    @Override
    public void onResponse(String name) {
        Log.d("TAG", name);
    }
});

자세한 내용은 다음 문서를 참조하십시오.

그리고 다음 비디오:

저는 당신이 요구하는 것을 이해한다고 믿습니다.가져오기 방법에서 "반환"(그 자체로)하고 싶다고 하지만 가져오기가 완료된 후 검색된 값을 실제로 사용할 수 있기를 원한다고 말하면 충분할 수 있습니다.그렇다면 다음과 같이 해야 합니다.

  1. 클래스의 맨 위에 변수 만들기
  2. 가장 정확하게 수행한 값 검색
  3. 클래스의 공용 변수를 검색된 값과 동일하게 설정합니다.

가져오기가 성공하면 변수를 사용하여 많은 작업을 수행할 수 있습니다.4a 및 4b는 몇 가지 간단한 예입니다.

4a. 편집:사용 예로, 다음을 사용하는 클래스에서 실행할 필요가 있는 다른 모든 항목을 트리거할 수 있습니다.yourNameVariable(그리고 당신은 확신할 수 있습니다.yourNameVariable이 아님

4b. 편집:사용 예로 ClickListener의 버튼에 의해 트리거되는 함수에서 변수를 사용할 수 있습니다.


이거 먹어봐요.

// 1. Create a variable at the top of your class
private String yourNameVariable;

// 2. Retrieve your value (which you have done mostly correctly)
private void getUserName(String uid) {
    databaseReference.child(String.format("users/%s/name", uid))
            .addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // 3. Set the public variable in your class equal to value retrieved
            yourNameVariable = dataSnapshot.getValue(String.class);
            // 4a. EDIT: now that your fetch succeeded, you can trigger whatever else you need to run in your class that uses `yourNameVariable`, and you can be sure `yourNameVariable` is not null.
            sayHiToMe();
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

// (part of step 4a)
public void sayHiToMe() {
  Log.d(TAG, "hi there, " + yourNameVariable);
}

// 4b. use the variable in a function triggered by the onClickListener of a button.
public void helloButtonWasPressed() {
  if (yourNameVariable != null) {
    Log.d(TAG, "hi there, " + yourNameVariable);
  }
}

그런 다음 사용할 수 있습니다.yourNameVariable당신이 수업 내내 원하는 곳 어디든.


참고: 반드시 확인하시기 바랍니다.yourNameVariable는 null이므로 시 .onDataChange비동기식이므로 다른 곳에서 사용하려고 할 때 완료되지 않았을 수 있습니다.

아이디어가 . 가시성이 사라진 상태에서 TextView 안에 넣으십시오.textview.setVisiblity(Gone)아니면 뭔가, 그리고 나서 비슷한 것을 하라.

textview.setText(dataSnapshot.getValue(String.class))

그러면 나중에 그것과 함께.textview.getText().toString()

그냥 미친 듯이 간단한 아이디어.

사용하다LiveData반환 유형으로 지정하고 원하는 작업을 실행하기 위한 값의 변화를 관찰합니다.

private MutableLiveData<String> userNameMutableLiveData = new MutableLiveData<>();

public MutableLiveData<String> getUserName(String uid) {

    databaseReference.child(String.format("users/%s/name", uid))
            .addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // How to return this value?
            String userName = dataSnapshot.getValue(String.class);
            userNameMutableLiveData.setValue(userName);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });

    return userNameMutableLiveData;
}

당신의 럼당신에서.Activity/Fragment를 지키다LiveData 안쪽 에쪽안.onChanged원하는 작업을 수행합니다.

getUserName().observe(this, new Observer<String>() {
    @Override
    public void onChanged(String userName) {
        //here, do whatever you want on `userName`
    }
});

이는 해결책이 아니라 코드 구성을 위한 메서드 외부의 데이터에 액세스하는 방법입니다.

// Get Your Value
private void getValue() {

    fbDbRefRoot.child("fbValue").addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            String yourValue = (String) dataSnapshot.getValue();
            useValue(yourValue);

        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });

}

// Use Your Value
private void useValue(String yourValue) {

    Log.d(TAG, "countryNameCode: " + yourValue);

}

결과를 달성하는 또 다른 방법(그러나 반드시 해결책은 아님)

공개 변수 선언

public static String aPublicVariable;

비동기 메서드 내부에서 이 변수 설정

aPublicVariable = (String) dataSnapshot.getValue();
     

어디서나 변수 사용

Log.d(TAG, "Not Elegant: " + aPublicVariable);

두 번째 방법에서는 비동기 호출이 길지 않으면 거의 항상 작동합니다.

언급URL : https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method

반응형