简体   繁体   English

从Google App Engine调用Firebase数据库

[英]Call Firebase database from Google App Engine

I followed this tutorial for setting up my Google App Engine instance and I am also using Firebase. 我按照本教程设置了我的Google App Engine实例,我也在使用Firebase。 My goal is to put all of the "computation" on Google App Engine. 我的目标是将所有“计算”放在Google App Engine上。 I want to call a function like this one below: 我想调用下面这样的函数:

MyEndpoint: 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;
 }

}

MainActivity: 主要活动:

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();
 }
 }
}

I understand the above code for Firebase is Android specific so running on a Google App Engine instance doesn't work. 我了解Firebase的上述代码是特定于Android的,因此在Google App Engine实例上运行不起作用。 I was wondering if any one knows how to perform CRUD operations on a firebase database from Google App Engine backend. 我想知道是否有人知道如何从Google App Engine后端对firebase数据库执行CRUD操作。 Any help is appreciated. 任何帮助表示赞赏。

You'll need to use the Firebase Server SDK to make server side calls. 您需要使用Firebase Server SDK进行服务器端调用。 You can find info on setting that up and using it here: 您可以在此处找到有关设置和使用它的信息:

Add Firebase to your Server 将Firebase添加到您的服务器

Firebase Server SDK Installation & Setup Firebase Server SDK安装和设置

When using Firebase with Google Cloud Endpoints be aware that you'll need to use Firebase methods in conjunction with the Tasks API . 将Firebase与Google Cloud Endpoints一起使用时,请注意您需要将Firebase方法与Tasks API结合使用。 Since Firebase methods are not blocking, if you don't use Tasks your Endpoint will return before the call you made to Firebase has a chance to return its result. 由于Firebase方法没有阻止,如果您不使用任务,则在您对Firebase进行的呼叫有机会返回其结果之前,您的端点将返回。 For a brief intro on using tasks check out the link below. 有关使用任务的简要介绍,请查看以下链接。 Its a talk given at Google I/O 2016. The speaker is talking about Tasks and Firebase on Android but the concepts are the same when using Tasks and Firebase on a server. 这是在Google I / O 2016上发表的演讲。演讲者正在讨论Android上的任务和Firebase,但在服务器上使用Tasks和Firebase时的概念是相同的。 Note that they have included the Tasks API with the Firebase Server SDK. 请注意,他们已将Tasks API与Firebase Server SDK一起包含在内。 I've skipped to the portion of the talk which deals directly with tasks. 我已经跳过直接涉及任务的谈话部分。

Firebase SDK for Android: A tech deep dive 适用于Android的Firebase SDK:深入了解技术

The samples below are if you need to process the result from your Firebase read/write operation before your Endpoint returns a value or if other code depends on the result of the Firebase read/write operation. 以下示例是您需要在Endpoint返回值之前处理Firebase读/写操作的结果,或者其他代码是否依赖于Firebase读/写操作的结果。 These are server-side examples. 这些是服务器端示例。 I'm going to assume you care whether or not the write operation was successful. 我将假设你关心写操作是否成功。 There may be better ways to perform these server-side operations but this is what I've done so far. 可能有更好的方法来执行这些服务器端操作,但这是我到目前为止所做的。

Sample write operation using setValue(): 使用setValue()进行示例写入操作:

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
YourModelClass obj = new YourModelClass();
  1. When a call is made to the setValue() method it returns a Task object, keep a reference to it. 当调用setValue()方法时,它返回一个Task对象,保持对它的引用。

     Task<Void> setValueTask = ref.setValue(obj); 
  2. Create a TaskCompletionSource object. 创建TaskCompletionSource对象。 This object should be parameterized with the result type of your choice. 应使用您选择的结果类型对此对象进行参数化。 I'm going to use Boolean as the result type for this example. 我将使用Boolean作为此示例的结果类型。

     final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); 
  3. Generate a Task from the TaskCompletionSource that was created in step 2. Again, the generated Task should use the same parameter type as the TaskCompletionSource object. 产生TaskTaskCompletionSource将在步骤2中创建同样,将所生成的Task应该使用相同的参数类型作为TaskCompletionSource对象。

     Task<Boolean> tcsTask = tcs.getTask(); 
  4. Add a completion listener to the Task that was generated by the call to setValue() . 将完成侦听器添加到由setValue()调用生成的Task In the completion listener set the appropriate result on the Task created in step 3. Calling setResult() on your TaskCompletionSouce object will mark the Task created from it as complete. 在完成侦听器中,在步骤3中创建的Task上设置适当的结果。在TaskCompletionSouce对象上调用setResult()将从其创建的Task标记为完成。 This is important for step 5. 这对第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. Call Task.await() to block the current thread until the Task you are interested in has completed. 调用Task.await()来阻止当前线程,直到您感兴趣的Task完成。 We are waiting for the Task generated by the TaskCompletionSource object to be marked complete. 我们正在等待TaskCompletionSource对象生成的Task被标记为complete。 This Task will be considered complete when we call setResult() on the TaskCompletionSource used to generate the Task as we did in step 4. Once complete it will return the result. 当我们在用于生成TaskTaskCompletionSource上调用setResult()时,我们将认为此Task已完成,就像我们在步骤4中所做的那样。一旦完成,它将返回结果。

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

That's it, the current thread will block until Tasks.await() returns a value. 就是这样,当前线程将阻塞,直到Tasks.await()返回一个值。 You can also (and should) set a timeout value on the Tasks.await() method if you want to keep the current thread from being blocked indefinitely. 如果要保持当前线程无限期地被阻止,您还可以(并且应该)在Tasks.await()方法上设置超时值。

If you were only interested in whether or not the Task generated by setValue() completed and didn't care if it was successful or not then you can skip the creation of the TaskCompletionSource and just use Tasks.await() directly on that Task . 如果您只对setValue()生成的Task是否已完成并且不关心它是否成功感兴趣,那么您可以跳过TaskCompletionSource的创建并直接在该Task上使用Tasks.await() The same works for updateChildren() . 这同样适用于updateChildren() And if you like you can just use the method calls for updateChilden() or setValue() which use a DatabaseReference.CompletionListener along with a TaskCompletionListener. 如果您愿意,可以使用updateChilden()setValue()的方法调用,它使用DatabaseReference.CompletionListener和TaskCompletionListener。

Waiting for a read operation to complete is similar. 等待读取操作完成是类似的。

Sample read operation using addListenerForSingleValueEvent() 使用addListenerForSingleValueEvent()进行示例读取操作

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
YourModelClass mModelClassObject;
  1. Create a TaskCompletionSource object parameterized with the result you expect from the Task that will be generated from it. 创建一个TaskCompletionSource对象,该对象使用您希望从其生成的Task所期望的结果进行参数化。

     final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>(); 
  2. Generate a Task from the TaskCompletionSource object TaskCompletionSource对象生成Task

     Task<YourModelClass> tcsTask = tcs.getTask(); 
  3. Call addListenerForSingleValueEvent() on our DatabaseReference and call setResult() on the Task generated in step 2. 在我们的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. Call Tasks.await() to block the current thread until the Task you are interested in has completed. 调用Tasks.await()来阻止当前线程,直到您感兴趣的Task完成。 The Task will be considered complete when we call setResult() as we did in step 3 and will return the result. 当我们调用setResult()时, Task将被视为完成,就像我们在步骤3中所做的那样,并将返回结果。

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

As mentioned above you can use the Tasks.await() method along with a timeout value to prevent the current thread from being blocked indefinitely. 如上所述,您可以使用Tasks.await()方法以及超时值来防止当前线程无限期地被阻止。

Just as a heads up I've found that Firebase doesn't kill the background thread that is uses for its operations. 就像抬头一样,我发现Firebase不会杀死用于其操作的后台线程。 This means that the GAE Instance is never idle. 这意味着GAE实例永远不会空闲。 Check out this thread for more info: 查看此主题以获取更多信息:

Firebase, Background Threads, and App Engine Firebase,后台主题和App Engine

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM