簡體   English   中英

從Google App Engine調用Firebase數據庫

[英]Call Firebase database from Google App Engine

我按照本教程設置了我的Google App Engine實例,我也在使用Firebase。 我的目標是將所有“計算”放在Google App Engine上。 我想調用下面這樣的函數:

MyEndpoint:

package productions.widowmaker110.backend;

/** An endpoint class we are exposing */
@Api(
 name = "myApi",
 version = "v1",
 namespace = @ApiNamespace(
 ownerDomain = "backend.widowmaker110.productions",
 ownerName = "backend.widowmaker110.productions",
 packagePath=""
 )
)
public class MyEndpoint {

 /** A simple endpoint method that takes a name and says Hi back */
 @ApiMethod(name = "sayHi")
 public MyBean sayHi(@Named("name") String name) {

 // Write a message to the database
 FirebaseDatabase database = FirebaseDatabase.getInstance();
 DatabaseReference myRef = database.getReference("message");

 // Read from the database
 myRef.addValueEventListener(new ValueEventListener() {
 @Override
 public void onDataChange(DataSnapshot dataSnapshot) {
 // This method is called once with the initial value and again
 // whenever data at this location is updated.
 String value = dataSnapshot.getValue(String.class);
 Log.d(TAG, "Value is: " + value);
 }

 @Override
 public void onCancelled(DatabaseError error) {
 // Failed to read value
 Log.w(TAG, "Failed to read value.", error.toException());
 }
 });

 MyBean response = new MyBean();
 response.setData("Hi, " + name);

 return response;
 }

}

主要活動:

package productions.widowmaker110.gpsweather;

// imports...

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new EndpointsAsyncTask().execute(new Pair<Context, String>(this, "Manfred"));
 }

 class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
    private MyApi myApiService = null;
  private Context context;

 @Override
 protected String doInBackground(Pair<Context, String>... params) {
   if(myApiService == null) { // Only do this once
      MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
      new AndroidJsonFactory(), null)
      // options for running against local devappserver
      // - 10.0.2.2 is localhost's IP address in Android emulator
      // - turn off compression when running against local devappserver
     .setRootUrl("http://10.0.2.2:8080/_ah/api/")
     .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
 @Override
 public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
    abstractGoogleClientRequest.setDisableGZipContent(true);
 }
 });
 // end options for devappserver

 myApiService = builder.build();
 }

 context = params[0].first;
 String name = params[0].second;

 try {
 return myApiService.sayHi(name).execute().getData();
 } catch (IOException e) {
 return e.getMessage();
 }
 }

 @Override
 protected void onPostExecute(String result) {
 Toast.makeText(context, result, Toast.LENGTH_LONG).show();
 }
 }
}

我了解Firebase的上述代碼是特定於Android的,因此在Google App Engine實例上運行不起作用。 我想知道是否有人知道如何從Google App Engine后端對firebase數據庫執行CRUD操作。 任何幫助表示贊賞。

您需要使用Firebase Server SDK進行服務器端調用。 您可以在此處找到有關設置和使用它的信息:

將Firebase添加到您的服務器

Firebase Server SDK安裝和設置

將Firebase與Google Cloud Endpoints一起使用時,請注意您需要將Firebase方法與Tasks API結合使用。 由於Firebase方法沒有阻止,如果您不使用任務,則在您對Firebase進行的呼叫有機會返回其結果之前,您的端點將返回。 有關使用任務的簡要介紹,請查看以下鏈接。 這是在Google I / O 2016上發表的演講。演講者正在討論Android上的任務和Firebase,但在服務器上使用Tasks和Firebase時的概念是相同的。 請注意,他們已將Tasks API與Firebase Server SDK一起包含在內。 我已經跳過直接涉及任務的談話部分。

適用於Android的Firebase SDK:深入了解技術

以下示例是您需要在Endpoint返回值之前處理Firebase讀/寫操作的結果,或者其他代碼是否依賴於Firebase讀/寫操作的結果。 這些是服務器端示例。 我將假設你關心寫操作是否成功。 可能有更好的方法來執行這些服務器端操作,但這是我到目前為止所做的。

使用setValue()進行示例寫入操作:

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
YourModelClass obj = new YourModelClass();
  1. 當調用setValue()方法時,它返回一個Task對象,保持對它的引用。

     Task<Void> setValueTask = ref.setValue(obj); 
  2. 創建TaskCompletionSource對象。 應使用您選擇的結果類型對此對象進行參數化。 我將使用Boolean作為此示例的結果類型。

     final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); 
  3. 產生TaskTaskCompletionSource將在步驟2中創建同樣,將所生成的Task應該使用相同的參數類型作為TaskCompletionSource對象。

     Task<Boolean> tcsTask = tcs.getTask(); 
  4. 將完成偵聽器添加到由setValue()調用生成的Task 在完成偵聽器中,在步驟3中創建的Task上設置適當的結果。在TaskCompletionSouce對象上調用setResult()將從其創建的Task標記為完成。 這對第5步很重要。

     setValueTask.addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if(task.isSuccessful()){ tcs.setResult(true); }else{ tcs.setResult(false); } } }); 
  5. 調用Task.await()來阻止當前線程,直到您感興趣的Task完成。 我們正在等待TaskCompletionSource對象生成的Task被標記為complete。 當我們在用於生成TaskTaskCompletionSource上調用setResult()時,我們將認為此Task已完成,就像我們在步驟4中所做的那樣。一旦完成,它將返回結果。

     try { Boolean result = Tasks.await(tcsTask); }catch(ExecutionException e){ //handle exception }catch (InterruptedException e){ //handle exception } 

就是這樣,當前線程將阻塞,直到Tasks.await()返回一個值。 如果要保持當前線程無限期地被阻止,您還可以(並且應該)在Tasks.await()方法上設置超時值。

如果您只對setValue()生成的Task是否已完成並且不關心它是否成功感興趣,那么您可以跳過TaskCompletionSource的創建並直接在該Task上使用Tasks.await() 這同樣適用於updateChildren() 如果您願意,可以使用updateChilden()setValue()的方法調用,它使用DatabaseReference.CompletionListener和TaskCompletionListener。

等待讀取操作完成是類似的。

使用addListenerForSingleValueEvent()進行示例讀取操作

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
YourModelClass mModelClassObject;
  1. 創建一個TaskCompletionSource對象,該對象使用您希望從其生成的Task所期望的結果進行參數化。

     final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>(); 
  2. TaskCompletionSource對象生成Task

     Task<YourModelClass> tcsTask = tcs.getTask(); 
  3. 在我們的DatabaseReference上調用addListenerForSingleValueEvent()並在步驟2中生成的Task上調用setResult()

     ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { YourModelClass result = dataSnapshot.getValue(YourModelClass.class); if(result != null){ tcs.setResult(result); } } @Override public void onCancelled(DatabaseError databaseError){ //handle error } }); 
  4. 調用Tasks.await()來阻止當前線程,直到您感興趣的Task完成。 當我們調用setResult()時, Task將被視為完成,就像我們在步驟3中所做的那樣,並將返回結果。

     try { mModelClassObject = Tasks.await(tcsTask); }catch(ExecutionException e){ //handle exception }catch (InterruptedException e){ //handle exception } 

如上所述,您可以使用Tasks.await()方法以及超時值來防止當前線程無限期地被阻止。

就像抬頭一樣,我發現Firebase不會殺死用於其操作的后台線程。 這意味着GAE實例永遠不會空閑。 查看此主題以獲取更多信息:

Firebase,后台主題和App Engine

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM