为什么这个Android Volley请求永远不会完成?

时间:2017-12-19 01:17:59

标签: java android multithreading android-volley

使用Volley HTTP库在Android活动中考虑此代码。 HTTP请求永远不会完成。它既不接收正常响应也不接收错误响应。但是如果注释掉while (!done)块,那么一切都会正常完成。这让我感到惊讶,因为Volley我正在制作一个RequestQueue,其中包含一个线程池,其中使用完全独立的线程来执行HTTP请求。那么为什么如果这个线程正在睡眠,请求永远不会完成?

代码:

package com.adobe.instore.activities;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import com.adobe.instore.R;
import com.adobe.instore.Urls;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONObject;

public class VolleyTestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_volley_test);
    }

    private static boolean done = false;
    protected void makeRequest(View v) {
        Log.i(getLocalClassName(), "Request");

        RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
        queue.start();
        queue.add(new JsonObjectRequest(Request.Method.GET, Urls.STATIC_URL + "/profiles.json", null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.i(getLocalClassName(), "Response");
                done = true;
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(getLocalClassName(), "Error");
            }
        }));

        Log.i(getLocalClassName(), "Awaiting completion");
        while(!done) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.i(getLocalClassName(), "Done");
    }
}

2 个答案:

答案 0 :(得分:1)

在UI线程上调用Volley onResponse和onErrorResponse。因此,如果您的主线程处于休眠状态,则不会调用onResponse和onErrorResponse

答案 1 :(得分:1)

视图在主线程中呈现(有时称为UI线程)。您创建的循环会阻止渲染以及后面的其他代码。从技术上讲,在这个线程中调用Thread.sleep(...);是一个坏主意,因为很多事情都会受到影响。 Volley是一个http库,旨在通过不需要显式调用自己的Thread来简化您的生活。

在Volley中,所有网络和缓存调度都在一个单独的线程(引擎盖后)完成,同时响应被发送回主线程。这只意味着onResponseonError发生在主线程中。

为了让它更简单,你可以这样做:

public class VolleyTestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_volley_test);
    }

    public void makeRequest(View v) {
        Log.i(getLocalClassName(), "Request");

        RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
        queue.start();
        queue.add(new JsonObjectRequest(Request.Method.GET, Urls.STATIC_URL + "/profiles.json", null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.i(getLocalClassName(), "Response");
                Log.i(getLocalClassName(), "Done");
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(getLocalClassName(), "Error");
            }
        }));

        Log.i(getLocalClassName(), "Awaiting completion");
    }
}

此外,while()Thread.sleep使线程保持忙碌状态。因此,在主线程中排队的任何执行都无法访问,直到循环完成(但它不会发生)。您可能会认为onResponse可以绕过无限循环?答案是不;因为onResponse由主线程而不是后台线程排队。为了说明,请参见下图: enter image description here

图1:Android Volley内部架构(图片来自文档)

如果您看到在主线程上传递的解析响应的框,其颜色为BLUE,则表示它是调用它的主线程(简化它意味着onResponse和{{ 1}}由主线程调用)除非它是橙色或绿色,否则循环将被你的布尔值绕过。