Java Android-异步网络调用-响应相互依赖

Java Android-异步网络调用-响应相互依赖,java,android,asynchronous,android-volley,sequential,Java,Android,Asynchronous,Android Volley,Sequential,我今天在开发一个Android应用程序时遇到了这种情况,当时我被要求根据来自两个不同API的响应绘制图形。我在使用截击,我所做的是我进行了一个连续的网络呼叫,即我发出了第一个请求,在该请求的onResponse方法中,我发出了第二个请求。然后我在第二次请求的onResponse方法中呈现视图(图形) 现在我想优化这种情况。我想知道一种异步进行这两个网络调用的方法,只有在收到两个API的响应后才能呈现视图。 那么,假设我有3个模块化方法,即- getDataFromServer1(从一台服务器获取

我今天在开发一个Android应用程序时遇到了这种情况,当时我被要求根据来自两个不同API的响应绘制图形。我在使用截击,我所做的是我进行了一个连续的网络呼叫,即我发出了第一个请求,在该请求的
onResponse
方法中,我发出了第二个请求。然后我在第二次请求的
onResponse
方法中呈现视图(图形)

现在我想优化这种情况。我想知道一种异步进行这两个网络调用的方法,只有在收到两个API的响应后才能呈现视图。 那么,假设我有3个模块化方法,即-

  • getDataFromServer1(从一台服务器获取数据的网络调用)
  • getDataFromServer2(从另一台服务器获取数据的网络调用)
  • loadView
    (根据从2个网络调用接收的数据渲染图形)

  • 我该怎么做呢?有人能解释一下吗?

    如果两个请求具有相同的数据格式,并且由相同的容器保存。 为什么不简单地检查一下容器的大小呢

    public class MainActivity extends AppCompatActivity {
    
    private List<Data> myList = new ArrayList<>();
    private boolean error; // if one request got error, another one need to konw,
    //use to handle response size 0 or other error
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        GsonRequest request1 = new GsonRequest(params... , this.mClazz, null, new Response.Listener() {
            @Override
            public void onResponse(Object response) {
                boolean updateUI = false;
                if(myList.size()>0){ //or > the init size
                    updateUI = true;
                }
    
                myList.addAll(response);
    
                if(updateUI){
                    notifydatasetchange();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
    
            }
        });
        GsonRequest request2 = new GsonRequest(params... , this.mClazz, null, new Response.Listener() {
            @Override
            public void onResponse(Object response) {
                boolean updateUI = false;
                if(myList.size()>0){ //or > the init size
                    updateUI = true;
                }
    
                myList.addAll(response);
    
                if(updateUI){
                    notifydatasetchange();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
    
            }
        });
    }
    
    public类MainActivity扩展了AppCompatActivity{
    private List myList=new ArrayList();
    private boolean error;//如果一个请求出错,另一个请求需要知道,
    //用于处理响应大小0或其他错误
    @凌驾
    创建时受保护的void(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    GsonRequest request1=新的GsonRequest(params…,this.mClazz,null,new Response.Listener()){
    @凌驾
    公共响应(对象响应){
    布尔更新i=false;
    如果(myList.size()>0){//或>初始大小
    updateUI=true;
    }
    myList.addAll(响应);
    如果(更新){
    notifydatasetchange();
    }
    }
    },new Response.ErrorListener(){
    @凌驾
    公共无效onErrorResponse(截击错误){
    }
    });
    GsonRequest request2=新的GsonRequest(参数…,this.mClazz,null,new Response.Listener()){
    @凌驾
    公共响应(对象响应){
    布尔更新i=false;
    如果(myList.size()>0){//或>初始大小
    updateUI=true;
    }
    myList.addAll(响应);
    如果(更新){
    notifydatasetchange();
    }
    }
    },new Response.ErrorListener(){
    @凌驾
    公共无效onErrorResponse(截击错误){
    }
    });
    }
    
    }

    1版-带外部库 这是一个很好的例子,它很方便(或者更一般——任何支持事件驱动编程的框架)


    假设我们有以下域类,它们允许我们从web服务获取一些数据:

    存储库类:

    public class Repository {
        protected String name;
    
        public Repository(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    }
    
    服务接口:

    public interface GitService {
        List<Repository> fetchRepositories();
    }
    
    上面的代码是魔法发生的地方。这是:

    • 定义了任务的上下文
    • 定义了创建异步线程的必要性
    • 定义当硬作业结束时,应在UI线程中处理结果
    • 定义了要调用哪些方法来处理结果和错误

    在上面的
    subscribe
    中,我们传递lambda调用以向用户显示结果/错误:

    private void showRepositories(List<Repository> repositories) {
        // Show repositories in your fragment.
    }
    
    private void showErrors() {
        // Pops up some contextual information / help.
    }
    
    我们将在异步任务中共享此对象

    接下来,我们必须实现任务本身,例如:

    public class FetchRepositories extends AsyncTask<Void, Void, List<Repository>> {
        private AtomicInteger counter;
        private GitService service;
    
        public FetchRepositories(AtomicInteger counter, GitService service) {
            this.counter = counter;
            this.service = service;
        }
    
        @Override
        protected List<Repository> doInBackground(Void... params) {
            return service.fetchRepositories();
        }
    
        @Override
        protected void onPostExecute(List<Repository> repositories) {
            super.onPostExecute(repositories);
    
            int tasksLeft = this.counter.decrementAndGet();
            if(tasksLeft <= 0) {
                Intent intent = new Intent();
                intent.setAction(TASKS_FINISHED_ACTION);
                sendBroadcast(intent);
            }
        }
    }
    
    您必须更新视图,而不是记录消息

    提到的常量
    任务\u已完成\u操作
    命名您的筛选器:

     private static final String TASKS_FINISHED_ACTION = "some.intent.filter.TASKS_FINISHED";
    
    记住在您的活动和清单中初始化并注册接收器和过滤器

    活动:

    private BroadcastReceiver receiver = new FetchBroadcastReceiver();
    
    @Override
    protected void onResume() {
        super.onResume();
    
        IntentFilter filter = new IntentFilter();
        filter.addAction(TASKS_FINISHED_ACTION);
    
        registerReceiver(receiver, filter);
    }
    
    清单(应用程序标记内部):

    请记住在
    onPause()方法中注销接收器


    准备好活动后,您可以在某处执行任务(例如,在
    onCreate
    方法中,如第一个示例中所示):

    正如您所注意到的,并行任务将仅在Honeycomb和更高版本上运行。 在此版本之前,Android线程池最多可以容纳1个任务



    至少我们使用了一些依赖注入和策略模式

    @tommus解决方案是最好的方法


    如果您想使用简单或更少代码的方法,可以使用布尔标志来确保这两种方法都已执行,并根据条件向前移动

    声明将用作标志的易失性布尔变量

    private volatile boolean flag = false;
    
    标志在开始时为false。现在,调用两个Web服务。执行的任何服务都会将此标志变为TRUE

    getDataFromServer1();
    function void onCompleteServer1() {
        if(flag) {
           loadViews();
        } else {
           flag = true;
        }
    }
    
    
    getDataFromServer2();
    onCompleteServer2Request() {
        if(flag) {
           loadViews();
        } else {
           flag = true;
        }
    }
    

    不完美,但我希望这个逻辑对你有用

     onDatafromServer1Fetched{
        flag1 = true;
        }
        onDataFromServer2Fetched{
        flag2=true;
        }
    
    main(){
            boolean flag1  = false;
            boolean flag2 =false;
    
        getDataFromSerVer1();
        getDataFromServer2();
        while(!flag1 && !flag2){/**no code required here*/}
        loadView();
     }
    

    回答得很好。尽管我认为,
    AndroidObservable
    有点过于复杂了——我认为对于RxJava新手来说,从简单的
    Observable
    另一个添加开始会更容易——正如谷歌最近宣布的那样,lambdas将得到新的Jack编译器的支持。所以,在(希望)不远的将来,你将不需要Retrolambda。@DmitryZaitsev-也许,但我认为-最终-
    AndroidObservable
    简化了一切。使用简单的
    Observable
    强制用户记住使用
    runOnUiThread
    方法等处理结果。在学习RxAndroid上投入一些时间可以很快获得回报。很高兴听到很快就推出了对lambdas的支持。不是真的,在你的例子中,AndroidObservable所做的就是在
    onDestroy
    中取消对源代码的订阅。您已经在观察
    AndroidSchedulers上的值。不需要使用mainThread()
    -
    runOnUiThread
    。此外,我发现它太依赖于活动-如果您使用类似MVP的东西,这可能会成为一个问题。@tommus-谢谢您对这个库的详细解释。但就像Dmitry提到的RxJ一样
    public class FetchBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("onReceive", "All tasks has been finished.");
            // No need to test 
            // if intent.getAction().equals(TASKS_FINISHED_ACTION) {}
            // as we used filter.
        }
    }
    
     private static final String TASKS_FINISHED_ACTION = "some.intent.filter.TASKS_FINISHED";
    
    private BroadcastReceiver receiver = new FetchBroadcastReceiver();
    
    @Override
    protected void onResume() {
        super.onResume();
    
        IntentFilter filter = new IntentFilter();
        filter.addAction(TASKS_FINISHED_ACTION);
    
        registerReceiver(receiver, filter);
    }
    
    <receiver android:name=".TestActivity$FetchBroadcastReceiver"/>
    
    <action android:name="some.intent.filter.TASKS_FINISHED"/>
    
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
        new FetchRepositories(counter, new GithubService())
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        new FetchRepositories(counter, new BitbucketService())
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } else {
        // Below Honeycomb there was no parallel tasks.
        new FetchRepositories(counter, new GithubService()).execute();
        new FetchRepositories(counter, new BitbucketService()).execute();
    }
    
    private volatile boolean flag = false;
    
    getDataFromServer1();
    function void onCompleteServer1() {
        if(flag) {
           loadViews();
        } else {
           flag = true;
        }
    }
    
    
    getDataFromServer2();
    onCompleteServer2Request() {
        if(flag) {
           loadViews();
        } else {
           flag = true;
        }
    }
    
     onDatafromServer1Fetched{
        flag1 = true;
        }
        onDataFromServer2Fetched{
        flag2=true;
        }
    
    main(){
            boolean flag1  = false;
            boolean flag2 =false;
    
        getDataFromSerVer1();
        getDataFromServer2();
        while(!flag1 && !flag2){/**no code required here*/}
        loadView();
     }