android.os.NetworkOnMainThreadException的解决方案

摘要:
方法1:我们可以从android Manifest中翻译android:targetSdkVersion=“VersionNum”这句话。如果删除了xml,问题将得到解决,但这不是根本原因的解决方案。如果程序不需要高实时性能,我们可以创建包含网络消息队列的异步任务类。当我们想要发送消息时,我们将网络消息添加到队列中。在异步任务中,我们使用while循环来查询队列。当队列中有数据时,我们发送它。如果队列中没有数据,我们会休眠一段时间。

06-24 18:04:36.857: E/AndroidRuntime(22251): FATAL EXCEPTION: main
06-24 18:04:36.857: E/AndroidRuntime(22251): android.os.NetworkOnMainThreadException
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1128)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:175)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at libcore.io.IoBridge.sendto(IoBridge.java:473)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at java.net.DatagramSocket.send(DatagramSocket.java:284)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at com.example.com.ihome.bang.util.UdpHelper.send(UdpHelper.java:93)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at com.example.com.ihome.bang.adapter.ListViewAdapter$2.onClick(ListViewAdapter.java:210)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.view.View.performClick(View.java:4171)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.view.View$PerformClick.run(View.java:17070)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.os.Handler.handleCallback(Handler.java:615)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.os.Handler.dispatchMessage(Handler.java:92)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.os.Looper.loop(Looper.java:137)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at android.app.ActivityThread.main(ActivityThread.java:4797)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at java.lang.reflect.Method.invokeNative(Native Method)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at java.lang.reflect.Method.invoke(Method.java:511)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:804)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:571)
06-24 18:04:36.857: E/AndroidRuntime(22251):     at dalvik.system.NativeStart.main(Native Method)

原来在Android2.2上面运行的好好的一个网络应用程序,主要是发送UDP信息跟服务器进行通信的程序,安装到4.0上面就爆出了这个问题。

查了一下官方文档。文档上说:NetworkOnMainThreadException是因为应用程序在主线程上尝试网络操作。另外,这个异常在Honeycomb SDK或更高版本的SDK上才会抛出。低版本的SDK允许应用程序在主线程或loop线程执行网络操作,但不鼓励这样做。

方法1:我们可以把android:targetSdkVersion=”Version Num”这句话从AndroidManifest.xml去掉,问题就解决了,但不是治本的解决方案。(如下图所示)

image

方法2:在进行网络通信的部分,单独执行异步任务。

现在让我们思考一下,让原有代码修改最小的一种方法。如果程序对实时性的要求不是很高的话,我们可以创建一个异步任务类,这个异步任务类里面含有一个网络消息队列(Queue)。这个类通过对外提供一个消息入队列的接口,在异步类内部进行消息的发送。当要发送消息的时候(也就是原来进行网络操作的地方,我们假设是发送消息),我们将网络消息加入Queue,在异步任务里面用一个while循环查询Queue,当Queue中有数据的时候就进行发送,没有的话,sleep一段时间。具体的代码如下所示。

package com.example.com.ihome.bang.tool;

import java.util.LinkedList;
import java.util.Queue;

import com.example.com.ihome.bang.util.UdpHelper;

import android.os.AsyncTask;
import android.util.Log;

public class SendThread extends AsyncTask{
    private static Queue<String> queue = new LinkedList<String>();  
    public static Boolean SendOrder(String Order){
        queue.offer(Order);
        return true;
    }
    
    
    @Override
    protected Object doInBackground(Object... params) {
        String str;
        while (true) {
            //Log.d(SendThread.class.getName(), "进入doInBackground");
            if ((str = queue.poll()) != null) {

                //Log.d(SendThread.class.getName(), "doInBackground_发送"+str);
                UdpHelper.sendReally(str);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    
                    e.printStackTrace();
                    
                }
            }
            

        }
    }

}

方法3:在进行网络通信的部分,用后台线程来执行操作

自己创建线程的话,比创建异步任务更麻烦一点。记住,当你要用线程来处理网络通信部分的时候,记得将线程设置为后台运行,也就是通过设置线程的属性为”background”。我们可以通过传递参数 THREAD_PRIORITY_BACKGROUNDProcess.setThreadPriority() 。.如果我们不通过这种方法将线程的优先级设为较低级别的话,那么这个线程就会拥有跟UI线程一样的优先级,我们的应用程序就可能被这个线程拖慢。

免责声明:文章转载自《android.os.NetworkOnMainThreadException的解决方案》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MVC教程八:母版页(布局页)视图关于react实现类似vue keep-alive 的cache router的功能解决方案下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

神奇的Timer之lock篇

严格的说,这篇叫做lock篇不是太合适,为什么这么说,看完短文就知道了! 大家都对上一篇神奇的Timer中情景2中的示例有很多自己的看法,请允许我今天一一的评说一下吧,说的不对的地方,欢迎拍砖! 1.还是应该写一个5分钟的定时器,只不过在回调函数中检查内容是否有变化! 这个方案是没有问题的,因为RichTextBox中有一个Modified属性,用它可以来...

winform进程、线程

随笔- 86 文章- 0 评论- 0 winform进程、线程 进程: 一般来说,一个程序就是一个进程,不过也有一个程序需要多个进程支持的情况。 进程所使用的类:Process 所需命名空间:System.Diagnostics; 可以通过进行来开启计算机上现有的程序: 1、使用静态方法Start();但必须要知道进程名 2、也可以实例化对象,来调用S...

JVM 详解

1 jdk  和jre 的区别     jre 石 Java 运行环境,只能运行 class 不能编辑 Java文件,不能dubug。  2  jdk下面的  bin/jconsole.exe 监控 一些内存,线程,jvm 。 3 Java 的 层级 ,以前我们关注的是三面 三次。jvm 是最下面一层    4 Java的  作者是  詹姆斯·高斯林   ...

[译]GPUView

【本文翻译自GPUView的开发者Matt的blog.  https://graphics.stanford.edu/~mdfisher/GPUView.html  】 【 GPUview可以在 https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install 这里下载到】...

关于使用 VisualVM 进行性能分析及调优

概述 开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未释放,未优化的算法等。 随着应用程序的持续运行,可能会造成整个系统运行效率下降,严重的则会造成系统崩溃。 为了找出程序中隐藏的这些问题,在项目开发后期往往会使用性能分析工具来对应用程序的性能进行分析和优化。 VisualVM 是一款免费的性能分析工具...

Python3之并发(五)---线程条件(Condition)和事件(Event)

一、线程条件Condition(条件变量) 依赖锁对象(Lock,RLock),锁对象可以通过参数传入获得,或者使用自动创建的默认锁对象当多个条件变量需要共享同一个锁时,建议传入锁对象 除了带有获取到锁的锁定池,Condition还包含一个未获取到锁的等待池,等待池中的线程处于等待阻塞状态,直到锁定池中的线程调用notify()/notifyAll()通知...