В моем приложении есть 2 функции обратного вызова, одна из которых требует результата другой, поэтому я хочу, чтобы они выполнялись асинхронно. Сценарий такой:
Я получаю токен устройства с FirebaseInstanceId.getInstance().getInstanceId()
. Это 1-й обратный вызов.
Когда у меня есть токен, я использую его для доступа к базе данных Firebase Realtime для получения данных пользователя. Это второй обратный вызов.
В моем текущем решении я использую AsyncTask
с Semaphore
в функции doInBackground
, например:
private class AsyncOp extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
final Semaphore semaphore = new Semaphore(0);
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
token = instanceIdResult.getToken();
JSONObject requestObject = new JSONObject();
try {
requestObject.put("token", token);
semaphore.release();
} catch (JSONException e) {
Log.e(TAG_MAINACTIVITY, token);
semaphore.release();
}
JsonObjectRequest req = new JsonObjectRequest(Request.Method.POST, REQUEST_URL + "token",
requestObject, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.i(TAG_MAINACTIVITY, "Token saved successfully");
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG_MAINACTIVITY, "Failed to save token - " + error);
}
});
_queue.add(req);
}
});
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
return token;
}
@Override
protected void onPostExecute(String token) {
getUser(token);
}
}
public void getUser(String token) {
db.child("users").child(token).addListenerForSingleValueEvent(new ValueEventListener() {
@SuppressLint("SetTextI18n")
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()) {
// Navigate to fragment where new users can sign up:
goToSignup();
} else {
currentUser = dataSnapshot.getValue(User.class);
assert currentUser != null;
updateHeadline(currentUser.getName()); // Update UI to display the user's name
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d(TAG_MAINACTIVITY, databaseError.getMessage());
}
});
}
, а в моем OnCreate
я выполняю следующее:
_queue = Volley.newRequestQueue(this);
AsyncOp getToken = new AsyncOp();
getToken.execute();
Он работает отлично, но я не могу не чувствовать, что мне не хватает всего смысла здесь и что есть лучшее решение, которое я могу использовать. Я изучил другие вопросы StackOverflow, связанные с аналогичными проблемами, и нашел несколько предложений, но я запутался, пытаясь реализовать их, будучи довольно новичком во всем этом испытании (на самом деле это мой первый «настоящий» проект). Я попытался найти что-то, что работало бы как Promise
, и нашел Future
, но, вероятно, я сделал это неправильно, так как это не сработало. Это единственное решение, которое сработало для меня, кроме простого вложения getUser(token)
внутри первого обратного вызова. Так что, если у вас есть идеи, которые подойдут мне, я буду рад их услышать.