AndroidStudio中相互依赖的回调函数——更优雅的解决方案
Callback functions that depend on one another in Android Studio - a more elegant solution
我的应用程序中有 2 个回调函数,其中一个需要另一个的结果,所以我希望它们异步执行。场景是这样的:
我使用 FirebaseInstanceId.getInstance().getInstanceId()
获取设备的令牌。这是第一次回调。
当我有了令牌后,我用它来访问 Firebase 实时数据库以获取用户的数据。这是第二次回调。
在我当前的解决方案中,我在 doInBackground
函数中使用 AsyncTask
和 Semaphore
,如下所示:
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();
它工作得很好,但我忍不住觉得我错过了这里的全部要点,我可以使用更好的解决方案。我搜索了处理类似问题的其他 Whosebug 问题并找到了一些建议,但我在尝试实施它们时遇到了麻烦,对整个考验来说还是个新手(这实际上是我的第一个 "real" 项目)。我尝试寻找可以像 Promise
一样工作的东西并找到了 Future
但我可能没有正确地做到这一点,因为它不起作用。这是唯一对我有用的解决方案,而不是简单地将 getUser(token)
嵌套在第一个回调中。因此,如果您有任何对我有用的想法,我将很高兴听到。
Firebase 在主线程之外执行所有网络和磁盘 I/O。这意味着很少有理由 运行 在后台任务中进行 Firebase 交互。
除此之外,当您使用信号量时,流程要复杂得多。我会考虑将获取用户的调用放入上一个调用的完成处理程序中。
合并后变为:
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
token = instanceIdResult.getToken();
JSONObject requestObject = new JSONObject();
requestObject.put("token", token);
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");
getUser(token);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG_MAINACTIVITY, "Failed to save token - " + error);
}
});
_queue.add(req);
}
});
我的应用程序中有 2 个回调函数,其中一个需要另一个的结果,所以我希望它们异步执行。场景是这样的:
我使用
FirebaseInstanceId.getInstance().getInstanceId()
获取设备的令牌。这是第一次回调。当我有了令牌后,我用它来访问 Firebase 实时数据库以获取用户的数据。这是第二次回调。
在我当前的解决方案中,我在 doInBackground
函数中使用 AsyncTask
和 Semaphore
,如下所示:
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();
它工作得很好,但我忍不住觉得我错过了这里的全部要点,我可以使用更好的解决方案。我搜索了处理类似问题的其他 Whosebug 问题并找到了一些建议,但我在尝试实施它们时遇到了麻烦,对整个考验来说还是个新手(这实际上是我的第一个 "real" 项目)。我尝试寻找可以像 Promise
一样工作的东西并找到了 Future
但我可能没有正确地做到这一点,因为它不起作用。这是唯一对我有用的解决方案,而不是简单地将 getUser(token)
嵌套在第一个回调中。因此,如果您有任何对我有用的想法,我将很高兴听到。
Firebase 在主线程之外执行所有网络和磁盘 I/O。这意味着很少有理由 运行 在后台任务中进行 Firebase 交互。
除此之外,当您使用信号量时,流程要复杂得多。我会考虑将获取用户的调用放入上一个调用的完成处理程序中。
合并后变为:
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
token = instanceIdResult.getToken();
JSONObject requestObject = new JSONObject();
requestObject.put("token", token);
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");
getUser(token);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG_MAINACTIVITY, "Failed to save token - " + error);
}
});
_queue.add(req);
}
});