为什么HttpURLConnection的getInputStream()方法返回RealBufferedSource类型的对象?

时间:2018-12-31 05:34:29

标签: java android android-asynctask inputstream httpurlconnection

我正在尝试使用以下代码从Android Studio中的AsyncTask发送HTTP请求。

protected Long doInBackground(URL... urls) {
    try {
        HttpURLConnection connection = (HttpURLConnection) urls[0].openConnection();
        connection.setRequestMethod("POST");
        connection.connect();

        byte[] loginRequestBytes = new Gson().toJson(loginRequest, LoginRequest.class).getBytes();
        connection.getOutputStream().write(loginRequestBytes);

        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
            ResponseBody responseBody = (ResponseBody) connection.getInputStream(); // ResponseBody extends InputStream
            loginResponse = new Gson().fromJson(responseBody.toString(), LoginResponse.class);
        }
    } catch (IOException e) {
        Log.e("HttpClient", e.getMessage(), e);
    }

    return null;
}

我的ResponseBody类扩展了InputStream,所以我认为使用

ResponseBody responseBody = (ResponseBody) connection.getInputStream();

可以工作,但这是问题所在:

我在代码中得到一个ClassCastException,因为connection.getInputStream()返回了一个com.android.okhttp.okio.RealBufferedSource$1类型的对象。为什么getInputStream没有按照Java documentation返回InputStream?这是特定于Android的问题吗?

编辑:我自己定义了ResponseBody类(如下所示)。据我所知,它不是来自okhttp的那个,它确实扩展了InputStream

public class ResponseBody extends InputStream {

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        String line;

        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(this, "UTF-8"))) {
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return stringBuilder.toString();
    }

    @Override
    public int read() throws IOException {
        return 0;
    }
}

1 个答案:

答案 0 :(得分:0)

getInputStream()方法确实返回一个InputStream。但是您正在尝试将结果强制转换为ResponseBody。除非结果对象是ResponseBody的子类型的实例,否则它不起作用。

现在,您不确定要在此处使用哪个ResponseBody类,但是如果它是okhttp3.ResponseBodyjavadoc),则无法通过强制转换{ {1}}。


  

我实际上是自己定义了InputStream类。它是ResponseBody的简单扩展(请参见编辑),所以我似乎向下转换应该可以工作

啊。我知道了。

不,那是行不通的。您不能将对象强制转换为非强制类型。那不是类型转换对引用类型所做的。

您有一个匿名内部类的实例

InputStream

,它是 com.android.okhttp.okio.RealBufferedSource$1 的子类型。您正在尝试将其强制转换为InputStream的子类型ResponseBody。但是InputStream不是匿名类的超类或接口,因此类型转换无法成功。

我建议您将ResponseBody重写为ResponseBody的包装类和/或使用此处列出的解决方案之一,将InputStream的内容提取到{{1 }}: