2016-06-18 3 views
8

Ich folgte dieser tutorial für die Einrichtung meiner Google App Engine-Instanz und ich verwende auch Firebase. Mein Ziel ist es, die gesamte "Berechnung" auf Google App Engine zu setzen. Ich möchte im Folgenden eine Funktion wie diese nennen:Firebase-Datenbank von Google App Engine anrufen

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

Ich verstehe den obigen Code für Firebase Android spezifisch ist so auf einer Google App Engine ausgeführt wird Instanz funktioniert nicht. Ich habe mich gefragt, ob jemand CRUD Operationen in einer Firebase-Datenbank vom Google App Engine-Backend ausführen kann. Jede Hilfe wird geschätzt.

Antwort

11

Sie müssen das Firebase Server SDK verwenden, um serverseitige Anrufe durchzuführen. Sie können Informationen finden auf das Aufstellen und es hier mit:

Add Firebase to your Server

Firebase Server SDK Installation & Setup

Bei der Verwendung von Firebase mit Google Cloud Endpoints bewusst sein, dass Sie mit den Tasks API Firebase Methoden in Verbindung zu verwenden, benötigen . Da Firebase-Methoden nicht blockiert werden, kehrt Ihr Endpunkt zurück, wenn Sie keine Aufgaben verwenden, bevor der Anruf, den Sie an Firebase gesendet haben, eine Chance hat, sein Ergebnis zurückzugeben. Eine kurze Einführung in die Verwendung von Aufgaben finden Sie unter dem folgenden Link. Es ist eine Rede auf Google I/O 2016. Der Redner spricht über Aufgaben und Firebase auf Android, aber die Konzepte sind die gleichen, wenn Sie Aufgaben und Firebase auf einem Server verwenden. Beachten Sie, dass sie die Aufgaben-API mit dem Firebase Server SDK enthalten haben. Ich habe den Teil des Vortrags übersprungen, der sich direkt mit Aufgaben beschäftigt.

Firebase SDK for Android: A tech deep dive

Die Proben unten sind, wenn Sie das Ergebnis von Ihrem Firebase Lese-/Schreibvorgang, bevor Sie Ihren Endpoint einen Wert zurückgibt oder wenn ein anderer Code ist abhängig von dem Ergebnis der Firebase Lese-/Schreibvorgang verarbeiten müssen. Dies sind serverseitige Beispiele. Ich nehme an, Sie interessieren sich, ob der Schreibvorgang erfolgreich war oder nicht. Möglicherweise gibt es bessere Möglichkeiten, diese serverseitigen Vorgänge durchzuführen, aber das habe ich bisher getan.

Musterschreiboperation unter Verwendung von setValue():

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 
YourModelClass obj = new YourModelClass(); 
  1. Wenn ein Aufruf der Methode setValue() gemacht ist es ein Task Objekt zurückgibt, halten einen Verweis darauf.

    Task<Void> setValueTask = ref.setValue(obj); 
    
  2. Erstellen Sie ein Objekt TaskCompletionSource. Dieses Objekt sollte mit dem gewünschten Ergebnistyp parametrisiert werden. Ich werde Boolean als Ergebnistyp für dieses Beispiel verwenden.

    final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); 
    
  3. Generieren eines Task vom TaskCompletionSource die 2. Wieder in Schritt erstellt wurde, die erzeugte Task sollte den gleichen Parametertyp wie das TaskCompletionSource Objekt verwenden.

    Task<Boolean> tcsTask = tcs.getTask(); 
    
  4. einen Abschluss Zuhörer zum Task hinzufügen, die durch den Aufruf von setValue() generiert wurde. Setzen Sie im Beendigungslistener das entsprechende Ergebnis für die in Schritt 3 erstellte Task. Das Aufrufen von setResult() auf Ihrem TaskCompletionSouce-Objekt markiert die davon erstellte Task als vollständig. Dies ist wichtig für Schritt 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. Anruf Task.await() den aktuellen Thread, bis die Task Sie in beendet Interesse zu blockieren. Wir warten auf die Task generiert von der TaskCompletionSource Objekt als abgeschlossen markiert werden. Dieses Task wird als abgeschlossen betrachtet, wenn wir setResult() auf dem TaskCompletionSource aufrufen, das verwandt wird, um das Task wie in Schritt 4 zu generieren. Sobald es abgeschlossen wird, wird es das Ergebnis zurückgeben.

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

dass es wird die aktuelle Thread blockiert, bis Tasks.await() einen Wert zurückgibt. Sie können (und sollten) auch einen Zeitüberschreitungswert für die Methode Tasks.await() festlegen, wenn Sie verhindern möchten, dass der aktuelle Thread auf unbestimmte Zeit blockiert wird.

Wenn Sie daran interessiert sind nur waren, ob die von setValue() erzeugt Task abgeschlossen und kümmerte sich nicht darum, ob es erfolgreich ist oder nicht, dann war können Sie die Erstellung des TaskCompletionSource und einfach auf das TaskTasks.await() direkt verwenden überspringen. Das gleiche funktioniert für updateChildren(). Und wenn Sie möchten, können Sie einfach die Methodenaufrufe für updateChilden() oder setValue() verwenden, die einen DatabaseReference.CompletionListener zusammen mit einem TaskCompletionListener verwenden.

Das Warten auf einen Lesevorgang ist ähnlich.

Probenlesevorgang mit addListenerForSingleValueEvent()

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 
YourModelClass mModelClassObject; 
  1. erstellen TaskCompletionSource Objekt parametriert mit dem Ergebnis, das Sie aus den Task erwarten, die daraus erzeugt werden.

    final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>(); 
    
  2. Generieren eines Task aus dem TaskCompletionSource Objekt

    Task<YourModelClass> tcsTask = tcs.getTask(); 
    
  3. Anruf addListenerForSingleValueEvent() auf unserer DatabaseReference und rufen setResult() auf dem erzeugten Task in Schritt 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. Anruf Tasks.await() zu Blockiere den Strom ent thread bis die Task die dich interessiert hat abgeschlossen ist. Die Task wird als abgeschlossen betrachtet, wenn wir wie in Schritt 3 setResult() aufrufen und das Ergebnis zurückgeben.

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

Wie oben erwähnt Sie Tasks.await() Verfahren zusammen mit einem Timeout-Wert den aktuellen Thread verwenden können, um zu verhindern unbestimmte Zeit blockiert werden.

Genau wie ein Heads-up habe ich festgestellt, dass Firebase nicht den Hintergrund Thread, der für seine Operationen verwendet wird töten. Dies bedeutet, dass die GAE-Instanz niemals inaktiv ist. Schauen Sie sich dieses Themas für weitere Informationen:

Firebase, Background Threads, and App Engine

+0

Dank Kevin, ich werde es geben, an diesem Wochenende versuchen. Schätze die Hilfe. Wenn das klappt, gebe ich Ihnen innerhalb von 24 Stunden die beste Antwort. – booky99

+0

Kein Problem, wenn ich eine Chance bekomme, werde ich einige weitere Informationen zur Verwendung von Aufgaben hinzufügen, weil es schwierig sein kann. –

+0

Ich verstehe das Multithreading beteiligt, aber ich habe Schwierigkeiten zu verstehen, wie Sie die Aufgaben-API implementieren. Wie Sie oben gesagt haben, wenn Sie die Möglichkeit haben, diese Informationen zu teilen, würde ich es wirklich schätzen. – booky99