2017-11-02 21 views
0

私はAndroidアプリケーションでFirebaseを使用しています。アプリはグループチャットのようなものを設定し、ユーザーが参加できるようにします。 ユーザーはキーを取得し、対応するDatabaseReferenceに自身を接続できます。 鍵が有効かどうかのチェックが必要です。したがって、グループが作成されると、ホストは自動的にユーザーのリストに自身を追加します。新しいクライアントは、リストにエントリがあるかどうかを確認できます。リストが空の場合、キーは無効です。Firebaseコールバックはテスト中に動作しますが、実行時には動作しません

これは、setValue呼び出しの完了を待つ必要があることを意味します。 Firebaseにはこのことを伝えるコールバックがたくさんありますが、かなり問題があります。場合によっては、単に呼び出されないこともあります。 私は既にこの非決定論的な振る舞いについて質問してきました:How to listen for Firebase setValue completion

これらのコールバックに関する新しい問題を発見しました。 インフラストラクチャを非同期設定に変更しました。すべてのインタラクションはCallableにパッケージ化され、ExecutorServiceに送信されます。結果はFuture <>です。今、私が何かが完了するのを待っていたいならば、私はその未来を待つことができます。未来の中で、Firebaseコールバックを使用する必要があります。

コードは、DBConnectionというラッパークラスにあります。ここで

は、新しいグループ(パーティ)を作成するための私のコードです:

public Future<DBState> createParty() { 
    // assert entries 
    assertState(DBState.SignedIn); 

    // process for state transition 
    Callable<DBState> creationProcess = new Callable<DBState>() { 
     @Override 
     public DBState call() throws Exception { 

      lock.lock(); 
      try { 
       // create a new party 
       ourPartyDatabaseReference = partiesDatabaseReference.push(); 
       usersDatabaseReference = ourPartyDatabaseReference.child("users"); 

       // try every remedy for the missing callbacks 
       firebaseDatabase.goOnline(); 
       ourPartyDatabaseReference.keepSynced(true); 
       usersDatabaseReference.keepSynced(true); 

       // push a value to the users database 
       // this way the database reference is actually created 
       // and new users can search for existing users when they connect 

       // we can only continue after that task has been completed 
       // add listeners for success and failure and wait for their completion 

       // TODO: we need information that this task has been finished 
       // but no callback seems to work 
       // onSuccess, onCompletion on the task are not reliable 
       // and the child and value event listeners on the userDatabaseReference are not reliable, too 
       final CountDownLatch waiter = new CountDownLatch(1); 
       usersDatabaseReference.addValueEventListener(new ValueEventListener() { 
        @Override 
        public void onDataChange(DataSnapshot dataSnapshot) { 
         waiter.countDown(); 
        } 

        @Override 
        public void onCancelled(DatabaseError databaseError) { 
         waiter.countDown(); 
        } 
       }); 
       Task addingTask = usersDatabaseReference.child(user.getUid()).setValue(true); 
       addingTask.addOnSuccessListener(new OnSuccessListener() { 
        @Override 
        public void onSuccess(Object o) { 
         waiter.countDown(); 
        } 
       }); 
       addingTask.addOnCompleteListener(new OnCompleteListener() { 
        @Override 
        public void onComplete(@NonNull Task task) { 
         waiter.countDown(); 
        } 
       }); 
       try { 
        waiter.await(); 
       } catch (InterruptedException ex) { 
       } 
       connectToParty(); 
      } finally { 
       lock.unlock(); 
      } 

      // if we could connect, we are now DBState.Connected, 
      // otherwise we are still DBState.SignedIn 
      return state; 
     } 
    }; 

    // start process 
    return executorService.submit(creationProcess); 

} 

あなたはこのようにそれを使用することができます:私はこれのためにテストを書いた

Future<DBState> creationFuture = dbConnection.createParty(); 

    try { 
     creationFuture.get(TIMEOUT, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException ex) { 
     throw new AssertionError("there should be no interrupt"); 
    }catch (TimeoutException ex) { 
     throw new AssertionError("timeout in party creation"); 
    }catch (ExecutionException ex) { 
     throw new AssertionError("concurrent execution exception"); 
    } 

。 テストでは、すべて正常に動作します。私は今少なくとも12回、canCreatePartyのテストを実行しました。

コールバックが機能することを確認するために、CountDownLatchを3カウントに増やして、countDownsにブレークポイントを追加しました。すべてcountDownに達します。

しかし、実行時にはコールバックが呼び出されません。 ブレークポイントに達しておらず、最終的には将来を待ってタイムアウトします。

私は、エミュレータのすぐ隣にFirebaseコンソールを開いています。私は新しい関係者がどのように作成され、ユーザーが追加されたかを見ることができます。テストと実行時の両方で、パーティーの作成は期待通りに機能し、新しいユーザーが追加されます。 実行時にコールバックが発生しないのはなぜですか?

+0

「ランタイム」には異なるキーストアが含まれていませんか?デバッグ/リリースのように - あなたはSHA1が違うので、私が知っている限り、別のfirebaseキーが必要です。 –

+0

Hm、私は分かりません。私はアンドロイドのsigningReportからFirebaseに自分のデバッグキーを追加しました。そして私はちょうど確認しました:そのレポートはただ一つの鍵を生成します。私が鍵を調べなければならない他の場所はありますか?いずれにしても、キーが拒否された場合、実行時にデータベースに書き込むことができませんでしたか?私は新しいパーティーが作成されていることと、ユーザーが追加されているのを見ることができます。完了のためのコールバックがありません – lhk

+1

うーん、わかりません - あなたがやっていることに全く慣れていない、私はFCMを本当に使っただけです。署名の報告書に1つのSHAが記載されている場合、それは問題ではありません。これは問題が何であるかを知るまで意味をなさない問題の1つです。あなたのテストがどんな方法でも不正にならないことを再度確認し、ファイアベースからの着信メッセージをドロップするだけではないことを確認してください。実際のデバイスから同じ動作をしますか?私はどちらも問題ではないはずだが、それでもなお –

答えて

0

理由は、Firebaseが常にメインスレッドからコールバックを呼び出すからです。

テストの「メイン」スレッドは、「junittestrunnerXXX」のようなものです。 Firebaseはコールバックを呼び出すために "main"という新しいスレッドを作成します。

実行時に、「メイン」スレッドは実際の「メイン」スレッドです。もし私がget()を呼び出すと、それは良いためにブロックされます。 Firebaseはこのスレッドが存在するかどうか、すでに存在しているかどうかをチェックし、ブロックされているので何も起こりません。

関連する問題