AndroidStudio中相互依赖的回调函数——更优雅的解决方案

Callback functions that depend on one another in Android Studio - a more elegant solution

我的应用程序中有 2 个回调函数,其中一个需要另一个的结果,所以我希望它们异步执行。场景是这样的:

  1. 我使用 FirebaseInstanceId.getInstance().getInstanceId() 获取设备的令牌。这是第一次回调。

  2. 当我有了令牌后,我用它来访问 Firebase 实时数据库以获取用户的数据。这是第二次回调。

在我当前的解决方案中,我在 doInBackground 函数中使用 AsyncTaskSemaphore,如下所示:

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