从Google App Engine调用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; } } 

主要活动:

 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操作。 任何帮助表示赞赏。

Solutions Collecting From Web of "从Google App Engine调用Firebase数据库"

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

将Firebase添加到您的服务器

Firebase Server SDK安装和设置

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

适用于Android的Firebase SDK:深入技术

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

使用setValue()进行写入操作示例:

 DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); YourModelClass obj = new YourModelClass(); 
  1. 当对setValue()方法进行调用时,它将返回一个Task对象,并保存对它的引用。

     Task<Void> setValueTask = ref.setValue(obj); 
  2. 创build一个TaskCompletionSource对象。 这个对象应该用你select的结果types参数化。 在这个例子中,我将使用Boolean作为结果types。

     final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); 
  3. 从步骤2中创build的TaskCompletionSource生成一个Task 。同样,生成的Task应该使用与TaskCompletionSource对象相同的参数types。

     Task<Boolean> tcsTask = tcs.getTask(); 
  4. 将完成侦听器添加到通过调用setValue()生成的Task 。 在完成监听器中,在步骤3中创build的Task上设置适当的结果。在TaskCompletionSouce对象上调用setResult() TaskCompletionSouce创build的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被标记为完成。 当我们调用TaskCompletionSource setResult()来生成Task时,这个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的创build,直接在该Task上使用Tasks.await()updateChildren()作品也是updateChildren() 。 如果你喜欢,你可以使用方法调用updateChilden()setValue() ,它们使用DatabaseReference.CompletionListener和TaskCompletionListener。

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

使用addListenerForSingleValueEvent()示例读取操作

 DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); YourModelClass mModelClassObject; 
  1. 创build一个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完成。 如我们在第3步中所做的那样,调用setResult()时, Task将被视为完成,并将返回结果。

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

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

就像我刚刚发现的那样,我发现Firebase不会杀死用于其操作的后台线程。 这意味着GAE实例从不闲置。 看看这个线程的更多信息:

Firebase,后台线程和App引擎