2016-06-18 2 views
8

Я выполнил это задание tutorial для настройки экземпляра моего приложения 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; 
} 

} 

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

Я понимаю, что приведенный выше код для Firebase это Android конкретный так работает на Google App Engine экземпляр не работает. Мне было интересно, знает ли кто-нибудь, как выполнять операции CRUD в базе данных firebase из бэкэнда Google App Engine. Любая помощь приветствуется.

ответ

11

Для выполнения вызовов на стороне сервера вам необходимо использовать SDK Firebase Server. Вы можете найти информацию по его установке и использовании его здесь:

Add Firebase to your Server

Firebase Server SDK Installation & Setup

При использовании Firebase с Google Cloud Endpoints быть в курсе, что вы должны будете использовать Firebase методы в сочетании с Tasks API , Поскольку методы Firebase не блокируются, если вы не используете Задачи, ваша конечная точка вернется до того, как вызов, который вы сделали в Firebase, имеет возможность вернуть его результат. Для краткого введения в использование задач ознакомьтесь с приведенной ниже ссылкой. Это разговор, заданный в Google I/O 2016. Докладчик говорит о задачах и Firebase на Android, но концепции одинаковы при использовании Tasks и Firebase на сервере. Обратите внимание, что они включили API задач с SDK Firebase Server. Я перешел к той части беседы, которая напрямую касается задач.

Firebase SDK for Android: A tech deep dive

Приведенные ниже образцы, если вам нужно обработать результат с вашей Firebase чтения/записи операции перед вашей конечной точке возвращает значение, или если другой код зависит от результата Firebase чтения/записи операции. Это примеры на стороне сервера. Я собираюсь предположить, что вы заботитесь о том, была ли операция записи успешной. Там могут быть более эффективные способы выполнения этих операций на стороне сервера, но это то, что я сделал до сих пор.

операции Пример записи с помощью SetValue():

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 
YourModelClass obj = new YourModelClass(); 
  1. При выполнении вызова к setValue() метода он возвращает объект Task, сохранить ссылку на него.

    Task<Void> setValueTask = ref.setValue(obj); 
    
  2. Создайте объект TaskCompletionSource. Этот объект должен быть параметризован по типу результата по вашему выбору. Я буду использовать Boolean как тип результата для этого примера.

    final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); 
    
  3. Генерация Task из TaskCompletionSource, который был создан в шаге 2. Снова, сгенерированный Task должны использовать один и тот же тип параметра в качестве TaskCompletionSource объекта.

    Task<Boolean> tcsTask = tcs.getTask(); 
    
  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); 
         } 
        } 
    }); 
    
  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 
    } 
    

Вот это, текущий поток блокируется до тех пор, пока Tasks.await() возвращает значение. Вы также можете (и должны) установить значение тайм-аута для метода Tasks.await(), если вы хотите, чтобы текущий поток блокировался неограниченно.

Если вы были заинтересованы только в том, является ли в Task генерируемой setValue() завершена, и не волнует, если она была успешной или нет, то вы можете пропустить создание TaskCompletionSource и просто использовать Tasks.await() непосредственно на этом Task. То же самое работает для updateChildren(). И если вам нравится, вы можете просто использовать вызовы метода для updateChilden() или setValue(), которые используют DatabaseReference.CompletionListener вместе с TaskCompletionListener.

Ожидание выполнения операции чтения аналогично.

Пример операции чтения с помощью addListenerForSingleValueEvent()

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 
YourModelClass mModelClassObject; 
  1. Создать TaskCompletionSource объект параметрироваться с результатом вы ожидаете от Task, который будет генерироваться из него.

    final TaskCompletionSource<YourModelClass> tcs = new TaskCompletionSource<>(); 
    
  2. Сформировать Task от TaskCompletionSource объекта

    Task<YourModelClass> tcsTask = tcs.getTask(); 
    
  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 
        } 
    }); 
    
  4. вызов Tasks.await() к блокировать поток до тех пор, пока вы не нашли интересующий вас Task. Task будет считаться завершенным, когда мы назовем setResult(), как это было на шаге 3, и вернем результат.

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

Как уже упоминалось выше, можно использовать метод Tasks.await() наряду со значением тайм-аута, чтобы предотвратить текущий поток от блокирования до бесконечности.

Как раз в голову, я обнаружил, что Firebase не убивает фоновый поток, который используется для его операций. Это означает, что экземпляр GAE никогда не работает. Проверить эту нить для получения дополнительной информации:

Firebase, Background Threads, and App Engine

+0

Благодаря Кевин, я собираюсь дать ему попробовать в эти выходные. Цените помощь. Если это сработает, я дам вам лучший ответ в течение 24 часов. – booky99

+0

Без проблем, когда я получаю шанс, я добавлю дополнительную информацию об использовании задач, потому что это может быть довольно сложно. –

+0

Я понимаю многопоточность, но мне трудно понять, как реализовать API задач. Как вы сказали выше, когда у вас есть шанс поделиться этой информацией, я бы очень признателен. – booky99