从Google App Engine调用Firebase数据库 [英] Call Firebase database from Google App Engine

查看:186
本文介绍了从Google App Engine调用Firebase数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循这个教程来设置我的Google App Engine实例,我也在使用Firebase。我的目标是将所有的计算放在Google App Engine上。我想调用下面的这个函数:

MyEndpoint:

  package productions.widowmaker110.backend; 
$ b $ **我们公开的端点类* /
@Api(
name =myApi,
version =v1,
namespace = @ApiNamespace(
ownerDomain =backend.widowmaker110.productions,
ownerName =backend.widowmaker110.productions,
packagePath =


public class MyEndpoint {

/ **一个简单的端点方法,它接受一个名字并说Hi返回* /
@ApiMethod(name =sayHi)
公共MyBean sayHi(@Named(name)字符串名称){

//写入消息到数据库
FirebaseDatabase数据库= FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(message);

//从数据库读取
myRef.addValueEventListener(new ValueEventListener(){
@Override
public void onDataChange(DataSnapshot dataSnapshot){
/ /这个方法被初始值调用一次,再次
//每当这个位置的数据被更新。
String value = dataSnapshot.getValue(String.class);
Log.d( TAG,Value is:+ value);
}

@Override
public void onCancelled(DatabaseError error){
//读取值失败
Log.w(TAG,Failed to read value。,error.toException());
}
});

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

返回响应;


$ b

MainActivity:

  package productions.widowmaker110.gpsweather; 

// imports ...
$ b $ public class MainActivity extends AppCompatActivity {

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

endpointsAsyncTask()。execute(new Pair< Context,String>(this,Manfred));
}

class EndpointsAsyncTask extends AsyncTask< Pair< Context,String> ;, Void,String> {
private MyApi myApiService = null;
私有上下文上下文;
$ b @Override
保护字符串doInBackground(Pair< Context,String> ... params){
if(myApiService == null){//只做一次
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),$ b $ new AndroidJsonFactory(),null)
//针对本地devappserver运行的选项
// - 10.0。 2.2是Android模拟器中的localhost的IP地址
// - 在运行本地devappserver时关闭压缩
.setRootUrl(http://10.0.2.2:8080/_ah/api/)
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer(){
@Override $ b $ public void initialize(AbstractGoogleClientRequest<> abstract> abstractGoogleClientRequest)throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
//结束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();


$ b $ @覆盖
保护无效onPostExecute(字符串结果){
Toast.makeText(上下文,结果,Toast.LENGTH_LONG).show ();





$ b我知道上面的代码Firebase是Android专用的,因此在Google App Engine实例上运行不起作用。我想知道是否有人知道如何从Google App Engine后端对Firebase数据库执行CRUD
操作。任何帮助都是值得赞赏的。

解决方案

您需要使用Firebase Server SDK进行服务器端调用。您可以在这里找到有关设置和使用的信息:



将Firebase添加到您的服务器



Firebase服务器SDK安装&设置



使用Firebase和Google Cloud Endpoints时,请注意,您需要将Firebase方法与任务API 。由于Firebase方法未被阻止,因此如果您不使用任务,则在您对Firebase进行的调用有机会返回其结果之前,您的Endpoint将返回。有关使用任务的简要介绍,请查看下面的链接。这是在Google I / O 2016上的一次演讲。演讲者正在讨论Android上的任务和Firebase,但在服务器上使用任务和Firebase时,概念是相同的。请注意,他们已经将Tasks API与Firebase Server SDK一起使用。我跳到了直接处理任务的部分。

Firebase SDK for Android:技术深度挖掘

下面的示例是您需要在您的端点之前处理Firebase读/写操作的结果返回值,或者其他代码取决于Firebase读/写操作的结果。这些是服务器端的例子。我会假设你在乎写操作是否成功。可能有更好的方法来执行这些服务器端操作,但这是我迄今为止所做的。



使用setValue() / strong>

  DatabaseReference ref = FirebaseDatabase.getInstance()。getReference(); 
YourModelClass obj = new YourModelClass();




  1. 当调用 setValue()方法返回一个任务对象,保留对它的引用。

     任务<无效> setValueTask = ref.setValue(obj); 


  2. 创建一个 TaskCompletionSource 这个对象应该用你选择的结果类型参数化。我将在这个例子中使用 Boolean 作为结果类型。

      final TaskCompletionSource< Boolean> tcs = new TaskCompletionSource<>(); 


  3. 生成任务 TaskCompletionSource 是在步骤2中创建的。同样,生成的 Task 应该使用与<$ c相同的参数类型$ c> TaskCompletionSource
    object。

     任务< Boolean> tcsTask = tcs.getTask(); 


  4. 任务添加一个完成监听器是通过调用 setValue()生成的。在完成监听器中,在步骤3中创建的 Task 中设置相应的结果。在<$ $ $>上调用 setResult() c $ c> TaskCompletionSouce 对象会将从它创建的 Task 标记为完整。

      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 被标记为完成。当我们在 TaskCompletionSource 上调用 setResult()时,这个 Task c $ c>用来生成 Task ,就像我们在第4步所做的那样。一旦完成,它将返回结果。

      try {
    布尔结果= Tasks.await(tcsTask);
    catch(ExecutionException e){
    //处理异常
    } catch(InterruptedException e){
    //处理异常
    }



    $ b

    就是这样,当前线程会阻塞,直到任务.await()返回一个值。你也可以(也应该)在 Tasks.await()方法上设置一个超时值,如果你想保持当前线程无限期地被阻塞。 b
    $ b

    如果您只关心由 setValue()生成的任务 c>完成,并不关心它是否成功,那么你可以跳过创建 TaskCompletionSource ,并使用 Tasks.await() 直接在任务上。同样的作品 updateChildren()。如果你喜欢,你可以使用方法调用 updateChilden() setValue(),它们使用 DatabaseReference.CompletionListener 以及一个TaskCompletionListener。

    等待读取操作完成是类似的。
    $ b

    使用addListenerForSingleValueEvent()

      DatabaseReference ref = FirebaseDatabase.getInstance()。getReference(); 
    YourModelClass mModelClassObject;




    1. 创建 TaskCompletionSource object参数化了你期望从任务中得到的结果。

       最后的TaskCompletionSource< YourModelClass> tcs = new TaskCompletionSource<>(); 


    2. 生成任务 TaskCompletionSource object

       任务< YourModelClass> tcsTask = tcs.getTask(); 


    3. 调用 addListenerForSingleValueEvent()我们的 DatabaseReference 并在 Task 上调用 setResult()

      pre $ ref $ add $ value $ $ $ $ $ $ public void onDataChange(new ValueEventListener(){
      @Override
      public void onDataChange (DataSnapshot dataSnapshot){
      YourModelClass result = dataSnapshot.getValue(YourModelClass.class); $ b $ if(result!= null){
      tcs.setResult(result);
      }

      $ b @Override
      public void onCancelled(DatabaseError databaseError){
      //处理错误
      }
      });


  6. 调用 Tasks.await()阻止当前线程,直到您感兴趣的 Task 已经完成。当我们调用 setResult()的时候, Task 会被认为是完整的,并且会返回结果。

      try {
    mModelClassObject = Tasks.await(tcsTask);
    catch(ExecutionException e){
    //处理异常
    } catch(InterruptedException e){
    //处理异常
    }



    如上所述,您可以使用 Tasks.await ()方法和一个超时值,以防止当前线程无限期地被阻塞。



    就像我刚刚发现的那样Firebase不会终止用于其操作的后台线程。这意味着GAE实例从不闲置。请参阅此主题了解更多信息:



    Firebase,后台线程和App Engine

    I followed this tutorial for setting up my Google App Engine instance and I am also using Firebase. My goal is to put all of the "computation" on Google App Engine. I want to call a function like this one below:

    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. I was wondering if any one knows how to perform CRUD operations on a firebase database from Google App Engine backend. Any help is appreciated.

    解决方案

    You'll need to use the Firebase Server SDK to make server side calls. You can find info on setting that up and using it here:

    Add Firebase to your Server

    Firebase Server SDK Installation & Setup

    When using Firebase with Google Cloud Endpoints be aware that you'll need to use Firebase methods in conjunction with the 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. 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. Note that they have included the Tasks API with the 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

    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. 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():

    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.

      Task<Void> setValueTask = ref.setValue(obj);
      

    2. Create a TaskCompletionSource object. 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.

      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.

      Task<Boolean> tcsTask = tcs.getTask();
      

    4. Add a completion listener to the Task that was generated by the call to setValue(). 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. This is important for step 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. We are waiting for the Task generated by the TaskCompletionSource object to be marked 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.

      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. 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.

    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. The same works for 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.

    Waiting for a read operation to complete is similar.

    Sample read operation using 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.

      final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>();
      

    2. Generate a Task from the TaskCompletionSource object

      Task<YourModelClass> tcsTask = tcs.getTask();
      

    3. Call addListenerForSingleValueEvent() on our DatabaseReference and call setResult() on the Task generated in step 2.

      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. The Task will be considered complete when we call setResult() as we did in step 3 and will return the result.

      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.

    Just as a heads up I've found that Firebase doesn't kill the background thread that is uses for its operations. This means that the GAE Instance is never idle. Check out this thread for more info:

    Firebase, Background Threads, and App Engine

    这篇关于从Google App Engine调用Firebase数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆