Android HttpUrlConnection如何将响应分段读取

3
实际上,我需要更多关于如何在Android SDK中从HttpUrlConnection类读取响应的信息。我正在尝试从Web服务器读取响应,但当它太大时,我的应用程序会抛出一个OutOfMemoryException。因此,任何关于如何将整个响应分成块并读取的来源/帮助/建议都是受欢迎的。
根据我的研究,我发现我应该设置类似于这样的东西:((HttpURLConnection) connection).setChunkedStreamingMode(1024); 但我的问题是我不知道如何读取这个块流。所以如果有人能指导我正确的方法,我将非常高兴。
谢谢!
示例代码:
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            String deviceId = tm.getDeviceId();
            Log.w("device_identificator","device_identificator : "+deviceId);
            String resolution = Integer.toString(getWindow().getWindowManager().getDefaultDisplay().getWidth())+ "x" +
                                         Integer.toString(getWindow().getWindowManager().getDefaultDisplay().getHeight());
            Log.w("device_resolution","device_resolution : "+resolution);
            String version = "Android " + Build.VERSION.RELEASE;
            Log.w("device_os_type","device_os_type : "+version);
            Log.w("device_identification_string","device_identification_string : "+version);
            String locale = getResources().getConfiguration().locale.toString();
            Log.w("set_locale","set_locale : "+locale);
            String clientApiVersion = null;

            PackageManager pm = this.getPackageManager();
            PackageInfo packageInfo;

            packageInfo = pm.getPackageInfo(this.getPackageName(), 0);

            clientApiVersion = packageInfo.versionName;
            Log.w("client_api_ver","client_api_ver : "+clientApiVersion);

            long timestamp = System.currentTimeMillis()/1000;
            String timeStamp = Long.toString(timestamp);


            String url = "http://www.rpc.shutdown.com";
            String charset = "UTF-8";
            String usernameHash = hashUser(username,password);
            String passwordHash = hashPass(username,password);


            String query = String.format("username_hash=%s&password_hash=%s&new_auth_data=%s&debug_data=%s&client_api_ver=%s&set_locale=%s&timestamp=%s&"+
                     "device_os_type=%s&mobile_imei=%s&device_sync_type=%s&device_identification_string=%s&device_identificator=%s&device_resolution=%s", 
                     URLEncoder.encode(usernameHash, charset), 
                     URLEncoder.encode(passwordHash, charset),
                     URLEncoder.encode("1", charset),
                     URLEncoder.encode("1", charset),
                     URLEncoder.encode(clientApiVersion, charset),
                     URLEncoder.encode(locale, charset),
                     URLEncoder.encode(timeStamp, charset),
                     URLEncoder.encode(version, charset),
                     URLEncoder.encode(deviceId, charset),
                     URLEncoder.encode("14", charset),
                     URLEncoder.encode(version, charset),
                     URLEncoder.encode(deviceId, charset),
                     URLEncoder.encode(resolution, charset));

            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setDoOutput(true); // Triggers POST.
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Charset", charset);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
            OutputStream output = null;
            try {
                 output = connection.getOutputStream();
                 output.write(query.getBytes(charset));
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                 if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
            }

            int status = ((HttpURLConnection) connection).getResponseCode();
            Log.i("","Status : "+status);

            for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
                Log.i("Headers","Headers : "+header.getKey() + "=" + header.getValue());
            }

            InputStream response = connection.getInputStream();
            Log.i("","Response : "+response.toString());
            int bytesRead = -1;
            byte[] buffer = new byte[8*1024];
            while ((bytesRead = response.read(buffer)) >= 0) {
              String line = new String(buffer, "UTF-8");
              Log.i("","line : "+line);
              handleDataFromSync(buffer);
            }

你能否贴出一些示例代码?这样更容易解释在你特定情况下该怎么做。 - kaspermoerch
我刚刚添加了代码,用于发送参数并连接到服务器,并实际显示响应正文。 - Android-Droid
2个回答

3

只需分配一个可以容纳少量数据的字节缓冲区,并从输入流中读取到此缓冲区中(使用read方法)。类似于:

InputStream is = connection.getInputStream();

int bytesRead = -1;
byte[] buffer = new byte[1024];
while ((bytesRead = is.read(buffer)) >= 0) {
  // process the buffer, "bytesRead" have been read, no more, no less
}

那段代码在这一行抛出了一个“FileNotFoundException”异常:InputStream response = connection.getInputStream();。有什么想法吗? - Android-Droid
可能你提供的URL不正确(在浏览器中尝试一下)。另外,你粘贴的代码并不是从URL读取数据,而是向其写入数据(将数据发送到服务器并不接收任何数据)。我的代码会从服务器读取响应。 - Vincent Mimoun-Prat
是的,实际上我需要发布一些数据,然后根据我发送的数据读取服务器的响应。 - Android-Droid
我刚刚编辑了我的代码,我可以看出我没有收到整个输入流。我只收到了8 * 1024,然后什么也没有了。 - Android-Droid
这段代码可以运行,检查是否会抛出异常,因为那会打破 while 循环。 - Vincent Mimoun-Prat

2

尝试使用以下方式来读取响应头:

String sHeaderValue = connection.getHeaderField("Your_Header_Key");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接