【问题标题】:BufferedReader.readLine() blocks for a whileBufferedReader.readLine() 会阻塞一段时间
【发布时间】:2012-11-06 15:56:52
【问题描述】:

我正在尝试获取一个 http 响应字符串(只是一个 JSON 对象),有时这段代码会在

中等待无限时间

line = reader.readLine()

可能是,这种行为的原因是互联网连接不好(我使用 3G 调制解调器),但我需要一个稳定的解决方案来避免这种无限锁定。这里可以做些什么来避免它?

HttpResponse response = httpClient.execute(httpPost);

InputStream content = null;
JSONObject json_obj;
if (response.getStatusLine().getStatusCode() == 200) {
    HttpEntity entity = response.getEntity();

    try {
        content = entity.getContent();

        BufferedReader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"), 256);
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (Exception e) {}
}

【问题讨论】:

  • 你可以在一个单独的线程中做readLine()的东西,当你想杀死所有东西时关闭阅读器
  • 为什么(最重要的是如何)您认为避免网络查询是非阻塞的? (另外,EntityUtils.toString 做了你在 1 行中所做的事情)
  • @fiddler 我已经在后台线程中这样做了,问题只是关于阻塞。
  • @njzk2 非常感谢,伙计!这是最好的解决方案:)
  • @njzk2 还有关于阻塞。问题是当请求已经发送到服务器并且服务器响应时发生阻塞,但是响应从未收到并且没有完全收到并且线程什么都不等待。所以超时是好事,只是不知道怎么设置。

标签: java android tcp bufferedreader


【解决方案1】:

您可以指定读取超时:

HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);

应将读取超时设置为 30 秒。 可能,您还想指定连接超时:

client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);

【讨论】:

    【解决方案2】:
    readLine()
    

    或者任何网络/IO都应该在后台线程中完成,以防止主线程被锁定。

    如果您在 Android 4.0+ 上测试您的代码,您还会发现主线程上不再允许联网,并且会引发异常。

    看看AsyncTask,这是一种在后台线程上运行此类任务的简单、轻松的方式。

    【讨论】:

    • 我已经在后台线程中这样做了,问题只是关于阻塞。
    【解决方案3】:

    避免“无限”锁定的一个很好的解决方案是在单独的线程中执行此 http 调用,并使用 Handler 通知主线程该信息已加载并且可以随意使用它。

    这是我自己使用 SaxParser 的示例:

    public void SearchFromSuperClass(String text)
    {   
        mHandler = new Handler();
        Thread t = new Thread(){
            public void run() {
                try {
                  String strurl="URLTOPATH";
                  URL url = new  URL(strurl);
                  SAXParserFactory factory = SAXParserFactory.newInstance();
    
                  SAXParser parser = factory.newSAXParser();
                  FundsHandlerRanking handler = new FundsHandlerRanking();
                  parser.parse(url.openConnection().getInputStream(), handler);
                  search_response = handler.getrankings();
    
    
                  mHandler.post(mUpdateResults);
                } catch (Exception e) {
                    search_response = null;
                    mHandler.post(mUpdateResults);
    
                }
    
            }
        };
    
        t.start();
    }
    final Runnable mUpdateResults = new Runnable() {
        public void run() {
            updateResultsInUi();
        }
    };
    
    private void updateResultsInUi() {
    
        try
        {
            if(search_response != null)
            {
                lview.setAdapter(new SearchRankingAdapter(mycontext, search_response, false));
            }
            Pdialog.dismiss();
        }
        catch (Exception e) {
            lview.setAdapter(null);
            if (Pdialog.isShowing())
            {
                Pdialog.dismiss();
            }
        }
    }
    

    使用 mHandler.post(...) 您将调用放入队列中以发送到主 UI 线程,在那里,您可以毫无问题地修改 UI 对象(不能在主线程之外修改 UI 对象) .

    希望对你有帮助

    【讨论】:

    • 有一个很好的选择将超时作为http调用参数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-19
    • 2015-08-06
    • 2011-11-20
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    相关资源
    最近更新 更多