从Google App Engine调用Firebase数据库

boo*_*y99 8 java google-app-engine android firebase

我按照本教程设置了我的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;
 }

}
Run Code Online (Sandbox Code Playgroud)

主要活动:

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();
 }
 }
}
Run Code Online (Sandbox Code Playgroud)

我了解Firebase的上述代码是特定于Android的,因此在Google App Engine实例上运行不起作用.我想知道是否有人知道如何从Google App Engine后端对firebase数据库执行CRUD操作.任何帮助表示赞赏.

Kev*_*eil 11

您需要使用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();
Run Code Online (Sandbox Code Playgroud)
  1. 当对setValue()方法进行调用时,它返回一个Task对象,保持对它的引用.

    Task<Void> setValueTask = ref.setValue(obj);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个TaskCompletionSource对象.应使用您选择的结果类型对此对象进行参数化.我将使用Boolean此示例的结果类型.

    final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>();
    
    Run Code Online (Sandbox Code Playgroud)
  3. TaskTaskCompletionSource步骤2中创建的内容生成a .同样,生成的Task应使用与TaskCompletionSource对象相同的参数类型.

    Task<Boolean> tcsTask = tcs.getTask();
    
    Run Code Online (Sandbox Code Playgroud)
  4. 添加完成侦听器到Task调用生成的侦听器setValue().在完成监听器上设置适当的结果Task在步骤3呼叫建立setResult()您的TaskCompletionSouce对象将迎来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);
          }
       }
    });
    
    Run Code Online (Sandbox Code Playgroud)
  5. 调用Task.await()阻止当前线程直到Task您感兴趣已完成.我们正在等待对象Task生成的TaskCompletionSource标记完成.这Task时候,我们的通话将被认为是完整setResult()TaskCompletionSource用来生成Task正如我们在第4步做.一旦完成,它将返回结果.

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

就是这样,当前线程将阻塞,直到Tasks.await()返回一个值.Tasks.await()如果要保持当前线程无限期地被阻止,您还可以(并且应该)在方法上设置超时值.

如果您只对完成Task生成setValue()并且不关心它是否成功感兴趣,那么您可以跳过创建TaskCompletionSourceTasks.await()直接使用它Task.同样适用于updateChildren().如果你喜欢,你可以使用方法调用updateChilden()setValue()使用DatabaseReference.CompletionListener与TaskCompletionListener一起使用.

等待读取操作完成是类似的.

使用addListenerForSingleValueEvent()进行示例读取操作

DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
YourModelClass mModelClassObject;
Run Code Online (Sandbox Code Playgroud)
  1. 创建一个TaskCompletionSource参数化的对象,该对象具有您希望从中Task生成的结果.

    final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>();
    
    Run Code Online (Sandbox Code Playgroud)
  2. TaskTaskCompletionSource对象生成a

    Task<YourModelClass> tcsTask = tcs.getTask();
    
    Run Code Online (Sandbox Code Playgroud)
  3. 拨打addListenerForSingleValueEvent()我们DatabaseReference并呼吁setResult()Task在步骤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
       }
    });
    
    Run Code Online (Sandbox Code Playgroud)
  4. 调用Tasks.await()阻止当前线程直到Task您感兴趣已完成.在Task当我们调用将被认为是完整的setResult(),因为我们没有在第3步,并返回结果.

    try {
        mModelClassObject = Tasks.await(tcsTask);
    }catch(ExecutionException e){
        //handle exception 
    }catch (InterruptedException e){
        //handle exception
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

就像抬头一样,我发现Firebase不会杀死用于其操作的后台线程.这意味着GAE实例永远不会空闲.查看此主题以获取更多信息:

Firebase,后台主题和App Engine