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

Posted

技术标签:

【中文标题】Android Studio中相互依赖的回调函数——更优雅的解决方案【英文标题】:Callback functions that depend on one another in Android Studio - a more elegant solution 【发布时间】:2020-09-15 16:39:32 【问题描述】:

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

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

    获得令牌后,我会使用它来访问 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();

它工作得很好,但我不禁觉得我错过了这里的全部要点,我可以使用更好的解决方案。我已经搜索了处理类似问题的其他 *** 问题并找到了一些建议,但我在尝试实施它们时陷入了纠结,对这整个考验来说是相当新的(这实际上是我的第一个“真正的”项目)。我尝试寻找可以像Promise 一样工作的东西,并找到了Future,但我可能没有正确地做到这一点,因为它不起作用。这是唯一对我有用的解决方案,而不是简单地将getUser(token) 嵌套在第一个回调中。因此,如果您有任何适合我的想法,我会很高兴听到。

【问题讨论】:

【参考方案1】:

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

【讨论】:

感谢 Frank :) 这实际上是我最初所做的,但我认为最好避免嵌套函数。谢谢。

以上是关于Android Studio中相互依赖的回调函数——更优雅的解决方案的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio 打包及引用 aar

Android Studio 打包及引用 aar

如何在没有Android Studio的情况下编译JNI共享库,并在[关闭]中编译依赖项

Android -- 每日一问:回调函数和观察者模式的区别?

如何将 Flash builder 项目作为库包含在 android Studio 中?

更新 Visual Studio 2017,现在出现编译错误 C7510:“回调”:使用依赖模板名称必须以“模板”为前缀