`
wx1569488408
  • 浏览: 79115 次
文章分类
社区版块
存档分类
最新评论

Android.os.NetworkOnMainThreadException异常的解决方式

 
阅读更多

笔者原以为,从后端的角度来讲,android和java客户端程序是大同小异的。

然而笔者有一次写一个爬取网页链接的小demo时,发现还是有不少区别的。

Android.os.NetworkOnMainThreadException异常产生的原因

Android4.0 以后不允许在主线程进网络连接,否则会出现 Android.os.NetworkOnMainThreadException。因此,必须另起一个线程进行网络连接方面的操作。

贴上代码

public class NetworkConnect {
	public static Gson gson = new Gson();
	public static String token = "5de492fe8fff9510a2c0e84f250c669557502862";

	public static String getJson(String httpUrl, String httpArg) {
		MyThread t = new MyThread(httpUrl,httpArg);
		t.start();
		try {
			t.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main thread stop");

		String result =t.getString();
		return result;// 通过out.Stream.toByteArray获取到写的数据;
	}

	private static class MyThread extends Thread{
		ByteArrayOutputStream outStream;
		String httpUrl;
		String httpArg;
		public MyThread(String httpUrl, String httpArg) {
			outStream = new ByteArrayOutputStream();
			this.httpUrl=httpUrl;
			this.httpArg=httpArg;
		}

		@Override
		public void run() {
			byte[] data = new byte[1024];
			int len = 0;
			URL url;
			try {
				if (httpUrl.contains("github")) {
					if (httpArg.contains("?"))
						url = new URL(httpUrl + httpArg + "&access_token=" + token);
					else
						url = new URL(httpUrl + httpArg + "?access_token=" + token);
				} else {
					url = new URL(httpUrl + httpArg);
				}

				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				InputStream inStream = conn.getInputStream();
				while ((len = inStream.read(data)) != -1) {
					outStream.write(data, 0, len);
				}
				inStream.close();
				System.out.println("subthread stop");
			} catch (MalformedURLException e) {
				e.printStackTrace();
				// TODO Auto-generated catch block
			} catch (IOException e) {
				e.printStackTrace();
				// TODO Auto-generated catch block
			}
		}

		public String getString(){
			return new String(outStream.toByteArray());
		}
	}

如图所示,将主要的获取json的Http请求放到子线程MThread中,将数据请求异步进行,可以解决上面问题。

PS:这是很久前的代码了,因为数据量很少,基本能够保证子线程在主线程之前返回完整数据。这样其实相当于仅仅解决异常。如果更合理一些的话,应当在子线程中以Message方式通知主线程数据获取完毕。

           //采用传送消息的模式 把view操作消息发给主线程  
                Message msg = new Message();  
                msg.what=DATA_FIN;  
                msg.obj=new String(outStream.toByteArray());  
                handler.sendMessage(msg);  
            }  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
            Toast.makeText(MainActivity.this, "访问网络失败",0).show();  
        }  
    }  
}.start();  

然后在主线程中定义handler

private Handler handler =new Handler(){  
        public void handleMessage(android.os.Message msg)  
        {  
            if(msg.what==DATA_FIN)  
            {  
                //Do Something
                .......
            }  
        };  
    };  

如此保证多线程中通信完毕。

附上顺序图(暂时上传不上去)

其他方法

1、把android:targetSdkVersion=”Version Num”这句话从AndroidManifest.xml去掉,问题就解决了,但不是治本的解决方案

2、在进行网络通信的部分,单独执行异步任务

创建一个异步的任务类,异步任务类里包含网络消息队列(Queue)。当要发送消息的时候(也就是原来进行网络操作的地方,我们假设是发送消息),我们将网络消息加入Queue,在异步任务里面用一个while循环查询Queue,当Queue中有数据的时候就进行发送,没有的话,sleep一段时间。

附上代码

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 string;
        while (true) {
            if ((string = queue.poll()) != null) {
                //若有队列中有消息,就异步发送
                UdpHelper.sendReally(string);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    
                    e.printStackTrace();
                    
                }
            }
            

        }
    }

}

3、可以再Activity的onCreate()方法中加入这样一段代码,如下:

if (Build.VERSION.SDK_INT >= 11) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        }

可以忽略如NetworkOnMainThreadException这样的限制策略

转载于:https://my.oschina.net/u/3508669/blog/910411

分享到:
评论

相关推荐

    Caused by: android.os.NetworkOnMainThreadException错误解决办法

    在Android开发中,`Caused by: android.os.NetworkOnMainThreadException` 是一个常见的错误,它意味着开发者尝试在主线程(UI线程)中执行网络操作,这是被禁止的。自Android 4.0 (API Level 14)以后,为了保证用户...

    Android 主线程Exception解决方案Demo

    当开发者违反这一规则时,系统会抛出`Android.os.NetworkOnMainThreadException`,提示主线程异常。 针对这个问题,Android提供了一些解决方案来确保网络请求等耗时操作不在主线程中执行。以下是几种常见的处理方式...

    多线程技术在Android手机开发中的运用.pdf

    1. **UI线程不能被阻塞**:所有与UI相关的操作必须在UI线程中执行,否则会抛出`android.os.NetworkOnMainThreadException`等异常。为了避免阻塞UI线程,长耗时的操作如网络请求、数据库操作应放在子线程中执行。 2. ...

    Android应用源码之alertDialog.zip

    - 在异步操作中创建`AlertDialog`时,需确保操作在UI线程执行,否则会抛出`android.os.NetworkOnMainThreadException`异常。 9. **Material Design兼容** - 对于Android 5.0(API级别21)及以上版本,`...

    Android网络通信之网络图片查看器事例代码

    本文将深入探讨如何处理“android.os.NetworkOnMainThreadException”这一常见的异常,该异常通常发生在尝试在网络主线程上执行网络操作时。理解这个问题并找到解决方案对于优化应用性能和提升用户体验至关重要。 ...

    Android倒计时功能的实现(CountDownTimer)

    请确保在UI线程中执行这些操作,否则可能会抛出 `android.os.NetworkOnMainThreadException` 异常。可以使用 `runOnUiThread` 或 `Handler` 来更新UI: ```java @Override public void onTick(long ...

    android里如何在子线程中如何更新主线程的控件

    这意味着,如果你在子线程中尝试修改任何UI元素,如文本、图片或者布局,系统会抛出`android.os.NetworkOnMainThreadException`异常,提示你在子线程中进行了网络操作或者UI更新。因此,要在子线程中更新主线程的...

    Android应用源码之HandlerLooper2.zip

    例如,当一个服务或者后台线程需要更新UI时,它可以通过`Handler`将更新操作的消息发送到UI线程,确保不会抛出`android.os.NetworkOnMainThreadException`等异常。 7. **生命周期管理**: 当不再需要使用`Handler`...

    android手机中应用程序异步加载,自己写的项目源代码

    - 在更新UI时,确保始终在主线程进行,以免抛出`android.os.NetworkOnMainThreadException`异常。 - 管理好生命周期,避免内存泄漏和资源浪费。 - 使用适当的缓存策略,减少不必要的网络请求或数据库查询。 通过...

    获取设备上的所有传感器信息并显示源码.zip

    在实际应用中,显示传感器信息通常涉及到更新UI,这可能需要用到线程同步技术,比如`runOnUiThread()`或使用`Handler`,因为直接在主线程外修改UI可能会导致`android.os.NetworkOnMainThreadException`异常。...

    Toast使用大全(附源码)

    - `Toast`需要运行在主线程中,否则会抛出`android.os.NetworkOnMainThreadException`异常。 - 每次调用`show()`方法,都会重新启动`Toast`的显示计时器,因此连续调用可能导致`Toast`显示时间延长。 - `Toast`在...

    动态刷新界面

    如果在其他线程中修改UI元素,会抛出`android.os.NetworkOnMainThreadException`异常。因此,我们需要使用异步处理或者Handler、Runnable、AsyncTask等工具来处理后台任务,然后在主线程中更新UI。 1. **Handler和...

    17.Handler消息传递机制

    但这里有一个问题,Android不允许在非主线程中直接修改UI,因此这段代码会抛出`android.os.NetworkOnMainThreadException`异常,导致程序崩溃。 正确的做法是使用Handler来处理子线程与主线程的通信。Handler通常...

    异步解析Json任务

    4. 避免在`doInBackground()`中执行与UI相关的操作,这可能导致`android.os.NetworkOnMainThreadException`异常。 5. 对于大文件或大量数据,考虑使用流式解析(如`JsonReader`),以节省内存并提高性能。 总之,...

    UI线程

    如果其他线程尝试更新UI,Android会抛出`android.os.NetworkOnMainThreadException`或`android.view.ViewRootImpl$CalledFromWrongThreadException`异常,提示开发者必须在正确的线程中执行这些操作。 源码分析是...

    应用源码之HandlerLooper2.zip

    - 不要在非UI线程中直接更新UI,否则会导致`android.os.NetworkOnMainThreadException`等错误。 - 使用`Looper.quit()`或`Looper.quitSafely()`可以结束`Looper`的消息循环,但需谨慎操作,因为这可能会影响到其他...

    ndroid异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    任何对UI的操作都必须在这个线程中进行,否则会抛出`android.os.NetworkOnMainThreadException`等异常。因此,当需要执行网络请求、数据库操作或大计算量的任务时,我们需要在其他线程(非UI线程)中执行。 接着,...

    android使用videoview播放视频

    - 在处理用户交互(如点击按钮)时,通常需要在UI线程中进行,否则可能会抛出`android.os.NetworkOnMainThreadException`异常。 - 如果需要在视频播放完成后执行某些操作,可以监听`OnCompletionListener`事件。 ...

Global site tag (gtag.js) - Google Analytics