突然出现 android.os.NetworkOnMainThreadException 错误

4
我是一名能够翻译文本的助手。
我有一个小应用程序,已经运行了几个月。但是突然出现了一个问题:
android.os.NetworkOnMainThreadException

我没有更改任何代码,这一行会导致程序崩溃。

try {   
    endPoint = InetAddress.getByName(target.getToIp());
    port = target.getPort();
    socket = new DatagramSocket();
}
catch(Exception e) {
}

请注意,我只是创建实例而没有发送任何内容,它在InetAddress行上已经中断。昨晚还可以使用,我手机上唯一做的就是在Google Play上运行更新,它更新到了最新版本的Google Maps,但这与此无关吗?在模拟器中它可以工作,只有我的HTC One X出了问题。完整代码请参见此处:https://github.com/AndersMalmgren/FreePIE/tree/master/Lib/Android/FreePIE%20Android%20IMU。编辑:清单。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.freepie.android.imu"
    android:versionCode="1"
    android:versionName="1.0">  

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET" /> 

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" 
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity> 
    </application>

</manifest>

尝试将问题代码转移到线程中,现在它不会崩溃了,但是套接字设置为空。

running = true;
worker = new Thread(new Runnable() { 
    public void run(){
        try {   
            endPoint = InetAddress.getByName(target.getToIp());
            port = target.getPort();
            socket = new DatagramSocket();
        }
        catch(Exception e) {
            Exception err = e;
        }

        while(running) {
            try {
            sync.await();
            } catch(Exception e) {}

            Send();
        }
        try  {
            socket.disconnect();
        }
        catch(Exception e)  {}
    }
}); 
worker.start();
更新: 解决方案是添加一些备用措施,以防用户输入DNS而不是IP地址。 https://github.com/AndersMalmgren/FreePIE/commit/e8017e02a7893d9df41e4ed67a037f016b6a7d39

请在您的清单文件中检查互联网权限。 - dakshbhatt21
尝试将您的try-catch放在AsyncTask中。 - Gaurav Agarwal
就像我说的,源代码没有改变,同样的 APK 昨晚能够工作。谢谢您的建议,我已更新问题并附上了清单文件。 - Anders
@Anders,你也遇到了相同的异常吗? - Blackbelt
不,catch语句没有被触发,但是getByName从未返回,看起来附加调试器现在非常困惑。sync.await之后的代码确实会被执行,这意味着代码必须返回,但调试器无法捕获它。当sync await代码触发时,socket为null。但在此期间发生了什么,无从得知,调试器已经崩溃了。使用Eclipse/Java工作的乐趣。 - Anders
3个回答

5

如果你试图在Android 4.0+的主应用程序线程上执行网络I / O操作,那么默认情况下会收到NetworkOnMainThreadException异常。如果提供的是域名而不是点分IP表示法,则getByName()将进行DNS查找,并触发NetworkOnMainThreadException


为什么在我的4.2手机上到这个时候它还能工作?如果我将代码移动到发送线程,调试器甚至不会在出现异常时中断,似乎有些奇怪的事情发生了。 - Anders
@Anders:也许target.getToIp()现在返回的是一个域名。 - CommonsWare
我将代码移动到发送者线程,但没有帮助,请参见编辑:顺便说一下,它是一个IP字符串。 - Anders
@Anders:永远不要编写空的catch块。记录您的异常,并发布带有所获取内容的堆栈跟踪,以及匹配的源代码。 - CommonsWare
我同意空的catch块,但Java是一种强制使用catch块的糟糕语言。你永远不应该有无法恢复的catch块。如果用C#编写,程序会崩溃并在通用位置记录异常。用日志代码污染代码是反模式。但我同意空的catch块是不好的。问题仍然存在 :) - Anders
显示剩余2条评论

1

你必须像这样把你的代码放在AsyncTask中:

new AsyncTask<Void,Void,Void>(){
doInBackground(){
  endPoint = InetAddress.getByName(target.getToIp());
    port = target.getPort();
    socket = new DatagramSocket();
}
}.execute();

请注意,此代码不可用,请在这里阅读有关AsyncTasks的更多信息。


0

在Android 4.0中不允许在主线程上使用网络。如果您在Android 2.3或其他版本上运行代码,它将不会抛出任何异常。


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