【问题标题】:How to deal with Java AssertionError(java.lang.SocketException)?如何处理 Java AssertionError(java.lang.SocketException)?
【发布时间】:2012-03-09 14:48:37
【问题描述】:

我有 Android 应用程序,它从服务器中提取 xml。

public class FeedParser {

    private final URL mURL;

    public FeedParser(String feedUrl) {
        try {
            mURL = new URL(feedUrl);
        } catch (MalformedURLException e) {
            throw new RuntimeException();
        }
    }

    private InputStream getInputStream() throws IOException {
        return mURL.openConnection().getInputStream();
    }

    public FeedItem parseFeed() {
        // SAX stuff here

        try {
            Xml.parse(getInputStream(), Xml.Encoding.UTF_8,
                    root.getContentHandler());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

有时,当 XML.parse(...) 执行时,我得到异常:

 AndroidRuntime: java.lang.RuntimeException: An error occured while executing doInBackground()
 AndroidRuntime:    at android.os.AsyncTask$3.done(AsyncTask.java:200)
 AndroidRuntime:    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
 AndroidRuntime:    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
 AndroidRuntime:    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
 AndroidRuntime:    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
 AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
 AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
 AndroidRuntime:    at java.lang.Thread.run(Thread.java:1019)
 AndroidRuntime: Caused by: java.lang.AssertionError: java.net.SocketException: Connection reset by peer
 AndroidRuntime:    at android.util.Xml.parse(Xml.java:89)
 AndroidRuntime:    at com.packagename.FeedParser.parseFeed(FeedParser.java:60)
 AndroidRuntime:    at com.packagename.UpdateService$FeedLookupTask.doInBackground(UpdateService.java:84)
 AndroidRuntime:    at com.packagename.UpdateService$FeedLookupTask.doInBackground(UpdateService.java:1)
 AndroidRuntime:    at android.os.AsyncTask$2.call(AsyncTask.java:185)
 AndroidRuntime:    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
 AndroidRuntime:    ... 4 more
 AndroidRuntime: Caused by: java.net.SocketException: Connection reset by peer
 AndroidRuntime:    at org.apache.harmony.luni.platform.OSNetworkSystem.read(Native Method)
 AndroidRuntime:    at dalvik.system.BlockGuard$WrappedNetworkSystem.read(BlockGuard.java:273)
 AndroidRuntime:    at org.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:458)
 AndroidRuntime:    at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:85)
 AndroidRuntime:    at org.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:65)
 AndroidRuntime:    at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:140)
 AndroidRuntime:    at java.io.BufferedInputStream.read(BufferedInputStream.java:225)
 AndroidRuntime:    at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.readLine(HttpURLConnectionImpl.java:660)
 AndroidRuntime:    at org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream.readChunkSize(ChunkedInputStream.java:77)
 AndroidRuntime:    at org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream.read(ChunkedInputStream.java:45)
 AndroidRuntime:    at java.io.InputStream.read(InputStream.java:157)
 AndroidRuntime:    at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:516)
 AndroidRuntime:    at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:479)
 AndroidRuntime:    at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:318)
 AndroidRuntime:    at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:275)

如何处理此类错误?

编辑 知道捕捉错误是不好的编程风格,我寻求更优雅的解决方案。

【问题讨论】:

  • 重试解析/获取?基本上一个例外还不错,它只是表明出了点问题。因此,只需想一种方法来重试它并完成(不要永远重试!制作一个限制它的重试计数器)......
  • 我听说捕获错误是个坏主意。为此,我需要编写 catch(Throwable)?
  • 不,你没有。 catch(AssertionError e) 就足够了。
  • 您可以通过仅处理导致 SocketException 的 AssertionErrors 并重新抛出任何其他错误来进一步防止捕获错误的陷阱。

标签: java android error-handling


【解决方案1】:

对等连接重置意味着您正在读取的远程服务器正在关闭连接,然后您尝试再次读取它。远程端执行此操作不一定是网络错误——它可能出于多种原因而执行此操作。不知道服务器的协议,很难知道确切的原因。

您可以将代码设置为捕获并重试有限的次数,如上文所建议的那样。捕获错误不是一个坏主意。

根据 xml 的大小,另一种可能性是将其读入字符串缓冲区,然后对其进行解析。对于大数据,这降低了重置的可能性,因为您的服务器连接将比您进行解析时短得多。我在这里想到了一个场景,当你在解析时,tcp 窗口被关闭了很长时间,最终对方认为你已经死了并重置了连接。

【讨论】:

  • @JarleHansen 为什么捕获错误是个坏主意?如果是你可以处理的异常,为什么不捕获它,重试 x 次,如果仍然失败则重新抛出?
  • @JarleHansen 当然,远程挂断在客户端是一个“严重问题”,但也许服务器刚才很忙?在这种情况下捕获错误并重试合理的次数是一个非常好的主意。
  • 你们是对的,看起来这是你真正需要捕获 AssertionError 的情况。我在这个问题上的错误。
【解决方案2】:

AssertionError 提供了一种标准方法来警告程序员所做的断言不正确

因此,如果使用得当,他们会说“这里有一个编码错误”(因为您将它们扔在您断言无法到达的地方),这就是 AssertionError 是(扩展)Error 的原因而不是Exception:它们会通知不可恢复的(在运行时)故障(因为您必须重新编码算法)。

这个错误的其他用法是错误的,因为它们违反了它的合同。

所以,回答你的问题,你可以通过以下方式来处理它:

  • 如果引发错误的代码是您的(我怀疑您的问题是这种情况,但将来应该是):检查并更正您的算法。
  • 如果来自第三方库:向作者注册错误(或尝试自行解决)

但是你不应该在你的代码中处理它。

附加说明:您的案例让我怀疑android.util.Xml.parse() 是否正确使用它。很奇怪 AssertionError 有一个原因(由另一个 Throwable 构造),所以这是另一个需要考虑的选项:也许这个库没有很好地实现......

【讨论】:

    猜你喜欢
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 2016-10-08
    • 2020-09-28
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多