【问题标题】:Need some explaining需要一些解释
【发布时间】:2012-03-09 23:26:42
【问题描述】:

所以这是我在编程过程中遇到的最奇怪的事情。是的,我不是编程专家,但我边走边学。我有一个应用程序与服务器通信,主线程中有一个套接字,读取是在一个单独的类和线程中完成的,并使用 asynctask 在一个单独的类中写入。

问题是位置管理器。我可以很好地与服务器通信并写入/读取命令,我实现了 LocationManager 及其监听器。

然后我开始实施一种方法,用 locatinChanged 上的新坐标更新我的 textview。到现在为止还挺好。事情是当我在 eclipse 中使用 Emulator 控件并发送坐标时,应用程序因 stringOutOfBoundsException 而崩溃(我已经编程了 3 年,现在从未见过这种情况)。我查看了通过它的代码等等。阅读stacktrace、logcat、控制台和我能想到的任何地方,但它让我无处可去。直到我终于去了看起来像这样的读者线程:

    public class ReaderThread extends Thread {
    public void run() {
        new Thread(new Runnable(){
            public void run(){                  
                try {
                    //Establish a bufferedreader to read from the socket/server.
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()), 8 * 1024);
            } 
            catch(Exception e) { e.printStackTrace(); }
        
        //As long as connect is true.       
        while (connected) {
            String line;
            try {
                //Try to read a line from the reader.
                line = in.readLine();
                System.out.println(in.readLine());
                if (in == null) {
                    //No one has sent a message yet.
                    System.out.println("No data recieved");
                }
            
                else {
                    int i = 0;
                    //As long as someone is sending messages.
                    while((line = in.readLine()) != null ){
                         //Make a new Message.
                        Message msg;
                        msg = new Message();
                        //Set the object to the input line.
                        msg.obj = line;
                        //Set an id so it can be identified in the main class and used in a switch.
                        msg.what = i;
                        System.out.println("i is: "+i);
                        //Send the message to the handler.
                        Main.this.h.sendMessage(msg);   
                    }
                }
            }
            catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        
            }           
        }).start(); 
    }

变量 i 位于 if 语句中,具体取决于服务器发送的内容,但我将其删除,因为它与此问题无关。

问题在于该死的捕获。当捕获为 IOException 时,应用程序崩溃。出于愚蠢的运气,我将其更改为 Exception 并打印 e.message 以捕获错误并查看导致错误的原因。事情是这个变化修复了它。如何将 IOException 切换为普通 Exception 来解决这样的问题?

就像 IOException 程序说:“嘿,你不会捕捉到错误,但没有错误”,但是 Exception 它说“现在你可以捕捉到它,所以我会继续”。

我的应用程序正在运行,但我无法理解这一点,为什么以及如何发生这种情况?

【问题讨论】:

  • 你一直说代码可以工作,但这显然是错误的,否则你就不会在这里。 @twaddington 告诉你问题出在哪里——如果你只捕获一个 IOException,那么你的应用程序在遇到任何其他异常时都会崩溃。相反,捕获异常将捕获所有可能的异常。这就是为什么您的应用不再崩溃的原因,不是因为发生了什么奇怪的事情,而是因为您忽略了所有可能的运行时错误,因此它会默默地继续,但会处于不确定状态。
  • 您似乎误解了这个问题。我在这里是因为代码正在运行,但它不应该。我有我想要的功能。一切都在做它应该做的,我一次又一次地测试了这个。我知道服务器应该响应什么,因为我在另一台计算机上将服务器与我的客户端并排放置,并带有其功能的文本文件。我发送一个命令,我得到了正确的响应。我设置了我的坐标,我得到了正确的响应,我用 if 和一个有效的响应的子字符串来拦截它。但从逻辑上讲(对我来说)它不应该工作。
  • 好吧,怎么样 - 通过捕获所有异常,您允许启动线程,但您没有正确处理导致抛出异常的错误状态 - 实际上只是忽略它。由于允许线程启动,它会给人一种印象,即只要捕获所有异常,您就已经修复了错误,而实际上您只是忽略了它。正如我在原始评论中所说 - 你只是忽略了问题,而不是解决它。
  • 我建议你重新阅读每个人的 cmets,阅读一本关于 Java 异常处理的好书/教程,然后你就会明白为什么你要为以后更令人困惑的错误做好准备。
  • @RivieraKid:但令人惊讶的是,程序的副作用显然正在按预期发生——这绝对是奇怪的,因为我当然不希望这段代码工作.我很困惑为什么这段代码似乎能正常运行——如果我负责维护它,我肯定会重写整个代码,让它按我的预期工作。

标签: android try-catch indexoutofboundsexception


【解决方案1】:

您实际上是在告诉应用程序捕获基本的Exception 类。这意味着任何类型的错误都将被捕获,因为所有异常类都来自该基类型。由于StringOutOfBoundsException 不是从IOException 下降的,因此之前没有被捕获并且错误没有被捕获。您可以尝试以下方法,而不是捕获所有异常:

try {
    // Your code here...
} catch (IOException e) {
    Log.e(TAG, "Caught an IOException!", e);
} catch (StringOutOfBoundsException e) {
    Log.e(TAG, "Caught a string out of bounds Exception!", e);
}

我无法确定到底是什么开始抛出 StringOutOfBoundsException。您可能在 if 语句中删除了您的示例。

【讨论】:

  • 是的,我知道这一点。问题是我只将 IOException 更改为 Exception NOTHING。那么,如果甚至有一个错误,是什么导致了错误呢?更改捕获应该修复错误?只是发现存在的错误对吗?导致错误的原因是实现了一个将我的坐标发送到服务器的位置监听器,所以当我使用模拟器控件设置坐标时,它在读取响应时崩溃了
  • 附加:否 if 仅捕获传入消息并将 i 设置为取决于消息是什么,如果它不是我想要捕获的内容,则将其打印到 system.out.println。在我修复错误之后添加了 if ,所以 if 与它无关
  • 再读一遍,是的,IOException 不会捕获字符串的出站,但更改捕获“修复”了一个显然从未存在过的问题。通过更改捕获并且只有捕获,应用程序可以正常工作,因此永远不会捕获错误。感觉就像 eclipse 告诉我,我永远无法捕捉到那个错误,因此我让你的应用程序崩溃,修复了这个问题,然后让你继续。
【解决方案2】:
    while (connected) {
        String line;
        try {
            //Try to read a line from the reader.
            line = in.readLine();
            System.out.println(in.readLine());
            if (in == null) {
                //No one has sent a message yet.
                System.out.println("No data recieved");
            }

in == null 的测试位于一个有趣的位置。如果该测试由于在前几行调用方法而返回true,您应该收到NullPointerException。显然,这段代码有些有趣。

您第二次调用时未能保存来自in.readLine() 的返回值。我希望它没有包含任何有用的东西。 (不过,既然您打印了该行,您显然想知道它包含哪些数据。)

无论line是什么(从第一次调用in.readLine()开始),它都会被丢弃;在此行被覆盖之前,循环中没有其他任何东西使用它:

                while((line = in.readLine()) != null ){

此时,您阅读的那两行已经一去不复返了。

我不完全确定应该做些什么来解决这个问题;如果是我,我会非常想从一张纸开始,并在不查看现有代码的情况下勾勒出该方法应该做什么,然后将草图与代码进行比较,看看每个人都忽略了哪些情况.

【讨论】:

  • 是的,这段代码完全是意大利面,我知道,我只是把废话拼凑起来工作,它确实如此。无需修复,此代码有效。问题是将捕获从 IOException 更改为普通 Exception 以某种方式修复了它。为什么?
  • 我可以发布我的整个类和子类,但老实说,代码看起来像废话,但它的工作原理和我在 android 上不太好,所以我通过使用“次优”选项来解决问题。到 C# 并且我将问题隔离到读取线程并发布我的所有代码会让我感到尴尬:p。
  • 我刚刚在重读时注意到您在该try 块中调用了in.readLine() 两次;第一次将其存储在从未使用过的变量中,第二次打印该值但将其丢弃。您确定要同时做这两件事吗?
  • 不,我可能不会,说实话,很多代码都是垃圾,可以删除,但我并不关心,我知道这段代码并不漂亮,它只是为了让事情运行,所以我可以将我的项目提交给我的大学,但我只想知道是否有人可以解释改变捕获可以防止崩溃的事实。
  • 您的代码能够正常工作的唯一方法是您以完整的意图进行编程。确保你知道为什么每一行代码都在你的程序中。您从服务器丢弃了至少两行输入。如果你不知道为什么,你的代码永远不会被称为正确工作。您可能还没有发现错误,但唯一可以称代码正确的方法是它是否符合您的期望。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多