【问题标题】:HTTP connection fails with certain website on API 16, but not API 10HTTP 连接与 API 16 上的某些网站失败,但不是 API 10
【发布时间】:2014-02-24 04:06:50
【问题描述】:

我在 API 16 上运行时遇到 HTTP 连接失败的问题,但在 API 10 上运行良好。其他网站连接使用相同的代码可以正常执行,因此尤其是本网站的问题。使用以下代码创建并读入连接:(2014 年 2 月 4 日更新以包含整个测试程序)

package com.example.test2;


import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {     
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

public void getData(View view) {    
    new TaskGetDir().execute(); 
}




public class TaskGetDir extends AsyncTask<Void, Void, String> {


@Override
    protected String doInBackground(Void... params) {

    String gpx_url = "http://gpx.geotags.com/cgi-bin/gpx.cgi?saddr=Boston,MA%s&daddr=NewYork,NY%s";
    String doc_gpx = "";

    try {

        HttpURLConnection conn = (HttpURLConnection) new URL(gpx_url).openConnection();

        InputStream is = new BufferedInputStream(conn.getInputStream());

        Reader reader = null;
        reader = new InputStreamReader(is, "UTF-8");        
        char[] buffer = new char[512];
        reader.read(buffer);
        doc_gpx = new String(buffer);

    } catch (IOException e) {

        e.printStackTrace();
    } 

    return doc_gpx;

}


    protected void onPostExecute(String result) {   

        TextView out_loc1 = (TextView) findViewById(R.id.sample_out);           
        out_loc1.setText(result.toString());

    }

}

}

代码正确地将 512 个字符提取到缓冲区并通过 API10 上的 textView 显示,但它在 API 16 中崩溃。失败发生在 conn.getContent() 调用期间。 logcat 日志如下所示:

01-31 07:42:34.096: E/AndroidRuntime(11036): FATAL EXCEPTION: AsyncTask #1
01-31 07:42:34.096: E/AndroidRuntime(11036): java.lang.RuntimeException: An error occured while executing doInBackground()
01-31 07:42:34.096: E/AndroidRuntime(11036):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.lang.Thread.run(Thread.java:856)
01-31 07:42:34.096: E/AndroidRuntime(11036): Caused by: java.lang.IndexOutOfBoundsException
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:156)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.lang.StringBuilder.append(StringBuilder.java:311)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.UriCodec.appendEncoded(UriCodec.java:114)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.UriCodec.appendPartiallyEncoded(UriCodec.java:142)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.net.URLStreamHandler.toExternalForm(URLStreamHandler.java:281)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.net.URL.toURILenient(URL.java:510)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.http.HttpEngine.<init>(HttpEngine.java:195)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.http.HttpURLConnectionImpl.newHttpEngine(HttpURLConnectionImpl.java:256)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.http.HttpURLConnectionImpl.initHttpEngine(HttpURLConnectionImpl.java:243)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:78)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.net.URLConnection.getContent(URLConnection.java:190)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at com.example.test.MainActivity$TaskGetData.doInBackground(MainActivity.java:55)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at com.example.test.MainActivity$TaskGetData.doInBackground(MainActivity.java:1)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-31 07:42:34.096: E/AndroidRuntime(11036):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)  

当本网站进入浏览器窗口时,会提示自动下载文件,然后从服务器端终止连接。它以 xml 格式返回带有我想提取的纬度/经度属性的方向。我的理论是不同的 API 以不同的方式处理这种尝试下载。任何帮助表示赞赏。

【问题讨论】:

  • 您是否向我们展示了完整的代码?这是使用HttpURLConnection 的一种非常不寻常的方式。您最好搜索好的示例或使用abstraction library for HTTP requests。至少您应该删除 conn.getContent() 并将 InputStream 直接提供给您的 XML 解析器。
  • 我已经更新了上面的代码来展示整个测试程序。我删除了 conn.getContent() 调用并看到了相同的结果。它在模拟器上很好地显示缓冲区,但在 conn.getInputStream() 调用时在电话(API 16)上崩溃。我正在使用与此处找到的示例类似的代码:link。如果我使用不同的 url,例如“google.com”,它可以在两个设备上正常连接并显示内容。使用 API16 建立与此特定站点的连接似乎是一个问题。

标签: android xml api http url


【解决方案1】:

我认为这与编码不正确的 URL 有关。

我用自己的 HTTP 客户端 (DavidWebb) 进行了尝试:

public void testDownloadGpx() throws Exception {

    Webb webb = Webb.create();
    Response<String> response = webb
            .get("http://gpx.geotags.com/cgi-bin/gpx.cgi")
            .param("saddr", "Boston,MA%s")
            .param("daddr", "NewYork,NY%s")
            .asString();

    assertEquals(200, response.getStatusCode());
    assertNotNull(response.getBody());
    assertTrue(response.getBody().contains("Turn right to stay on Tremont"));
}

// the same request in a shorter form
public void testDownloadGpxShort() throws Exception {

    Webb webb = Webb.create();
    String xml = webb
            .get("http://gpx.geotags.com/cgi-bin/gpx.cgi")
            .param("saddr", "Boston,MA%s")
            .param("daddr", "NewYork,NY%s")
            .asString()
            .getBody();

    assertTrue(xml.contains("Turn right to stay on Tremont"));
}

在调试器中我可以看到 URL 是这样编码的:

http://.../gpx.cgi?saddr=Boston%2CMA%25s&daddr=NewYork%2CNY%25s

由于您的堆栈跟踪显示它在创建 URL 时崩溃,这可能是问题所在。 请用上面的网址试试。我希望它有效。

【讨论】:

  • 是的,这个 URL 工作正常。出于好奇,不知道为什么编码不正确的 URL 适用于 API 10,但不适用于 API 16。非常感谢您的帮助!
  • 我想这是新实现中的一个错误。我得看看Android的源代码。稍后...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 2013-08-04
  • 2019-06-12
  • 2019-10-18
  • 2014-01-11
  • 1970-01-01
  • 2020-02-29
相关资源
最近更新 更多