child
の値をFireBase
に返すメソッドを作成したい。私はこのようなことをやろうとしました:
public String getMessage(){
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message = (String) dataSnapshot.getValue();
Log.i("4r398", "work");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("error", firebaseError.getMessage());
}
});
return message;
}
問題は、メソッドがnull
を返すことです。これは、リスナーが完了するまでメソッドが待機せず、null
のデフォルト値message
が返されるためです。リスナーが発生するまでこのメソッドを待機させ、値を返すにはどうすればよいですか
インターフェースを作る
public interface OnGetDataListener {
//this is for callbacks
void onSuccess(DataSnapshot dataSnapshot);
void onStart();
void onFailure();
}
次の関数readData()を宣言します
public void readData(Firebase ref, final OnGetDataListener listener) {
listener.onStart();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener.onSuccess(dataSnapshot);
}
@Override
public void onCancelled(FirebaseError firebaseError) {
listener.onFailure();
}
});
}
次のようにreadData()関数を呼び出します。
readData(root.child("MessagesOnLaunch").child("Message"), new OnGetDataListener() {
@Override
public void onSuccess(DataSnapshot dataSnapshot) {
//got data from database....now you can use the retrieved data
}
@Override
public void onStart() {
//when starting
Log.d("ONSTART", "Started");
}
@Override
public void onFailure() {
Log.d("onFailure", "Failed");
}
});
readData()は、getMessage()メソッド内、またはonCreate()内でも呼び出すことができます。
CountDownLatchを使用できます。これはあなたがそれを使うことができる方法です。
public String getMessage(){
CountDownLatch done = new CountDownLatch(1);
final String message[] = {null};
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message[0] = (String) dataSnapshot.getValue();
System.out.println("worked");
done.countDown();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("failed"+firebaseError.getMessage());
}
});
try {
done.await(); //it will wait till the response is received from firebase.
} catch(InterruptedException e) {
e.printStackTrace();
}
return message[0];
}
値を返す関数としてFirebaseを使用しないでください。非同期の性質に反します。
Firebaseがそのタスクを実行できるようにするコード構造を計画し、クロージャー(ブロック)内で次のステップに進みます。
たとえば、コードで、最後の行が次の関数を呼び出してUIを更新するように、関数を変更して何も返さないようにします。
@ CMikeB1がJavaの世界で別の応答にコメントしているので、サーブレットとサービスの残りを処理しているときは、同期呼び出しを使用して操作を実行するので、sdk firebase adminに両方のオプションがあると便利です。開発者がケースの用途に応じてどちらを使用するかを選択できること。
Firebase管理者のSDKで採用されている現在のインターフェースであるApiFutureを使用して、同期データの読み取りを待機しないように実装しました。 リンク !
public DataSnapshot getMessage() {
final SettableApiFuture<DataSnapshot> future = SettableApiFuture.create();
databaseReference.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
future.set(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
future.setException(databaseError.toException());
}
});
try {
return future.get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
return null;
}
}
私と同じ問題に直面している人を助けるためにここにこれを残します。 @Tirupati Singhのコードは見栄えがいいのですが、なぜうまくいかなかったのかを彼の回答の下に書きました。 Atomicタイプの使用は機能しました-
public AtomicInteger getMessage(){
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicInteger message1 = new AtomicInteger(0);
//assuming you have already called firebase initialization code for admin sdk, Android etc
DatabaseReference root = FirebaseDatabase.getInstance().getReference("server");
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
message1.set((Integer) dataSnapshot.getValue());
done.set(true);
}
public void onCancelled(DatabaseError error) {
// TODO Auto-generated method stub
}
});
while (!done.get());
return message1;
}
関数はメッセージタイプIntegerのみを返すことができることに注意してください。文字列の原子型がないため、文字列で動作させることができませんでした。お役に立てれば!
このリンクをたどることができます https://youtu.be/LVaIArVY52
データの取得時にFirebaseデータベースが非常に遅いため、プロセスが完了するまでアプリケーションを待機させるには、次のようにします
新しいクラスを作成します。 Firebasedata.Javaおよびそれをアプリケーションで拡張し、このコードをOnCreateセクションに追加します
public class Firebasedata extends Application {
@Override
public void onCreate() {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
super.onCreate();
}
}
マニフェストでJavaクラスを宣言します
<application
Android:name=".Firebasedata" <------
Android:allowBackup="true"
Android:icon="@mipmap/ic_launcher"
...
...
</application>
次に、データを取得するクラスに戻り、このコードでダイアログを作成します
ProgressDialog TempDialog;
CountDownTimer mCountDownTimer;
int i=0;
TempDialog = new ProgressDialog(MainActivity.this);
TempDialog.setMessage("Please wait...");
TempDialog.setCancelable(false);
TempDialog.setProgress(i);
TempDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
TempDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.GRAY));
TempDialog.show();
mCountDownTimer = new CountDownTimer(2000, 1000)
{
public void onTick(long millisUntilFinished)
{
TempDialog.setMessage("Please wait..");
}
public void onFinish()
{
TempDialog.dismiss();
//Your action like intents are placed here
}
}.start();
上記のリンクを調べて、より良いアイデアを得ることができます
このパーティーに少し遅れて申し訳ありませんが、firebaseが値を返すのではなく、オブザーバー/ビューモデルを設定できます。その場合、非同期のfirebase関数を実行すると、onDataメソッドが呼び出され、ビューモデルデータが更新されます。次に、レイアウトを更新できるonDataChangedメソッドをトリガーします