笔者原以为,从后端的角度来讲,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
分享到:
相关推荐
在Android开发中,`Caused by: android.os.NetworkOnMainThreadException` 是一个常见的错误,它意味着开发者尝试在主线程(UI线程)中执行网络操作,这是被禁止的。自Android 4.0 (API Level 14)以后,为了保证用户...
当开发者违反这一规则时,系统会抛出`Android.os.NetworkOnMainThreadException`,提示主线程异常。 针对这个问题,Android提供了一些解决方案来确保网络请求等耗时操作不在主线程中执行。以下是几种常见的处理方式...
1. **UI线程不能被阻塞**:所有与UI相关的操作必须在UI线程中执行,否则会抛出`android.os.NetworkOnMainThreadException`等异常。为了避免阻塞UI线程,长耗时的操作如网络请求、数据库操作应放在子线程中执行。 2. ...
- 在异步操作中创建`AlertDialog`时,需确保操作在UI线程执行,否则会抛出`android.os.NetworkOnMainThreadException`异常。 9. **Material Design兼容** - 对于Android 5.0(API级别21)及以上版本,`...
本文将深入探讨如何处理“android.os.NetworkOnMainThreadException”这一常见的异常,该异常通常发生在尝试在网络主线程上执行网络操作时。理解这个问题并找到解决方案对于优化应用性能和提升用户体验至关重要。 ...
请确保在UI线程中执行这些操作,否则可能会抛出 `android.os.NetworkOnMainThreadException` 异常。可以使用 `runOnUiThread` 或 `Handler` 来更新UI: ```java @Override public void onTick(long ...
这意味着,如果你在子线程中尝试修改任何UI元素,如文本、图片或者布局,系统会抛出`android.os.NetworkOnMainThreadException`异常,提示你在子线程中进行了网络操作或者UI更新。因此,要在子线程中更新主线程的...
例如,当一个服务或者后台线程需要更新UI时,它可以通过`Handler`将更新操作的消息发送到UI线程,确保不会抛出`android.os.NetworkOnMainThreadException`等异常。 7. **生命周期管理**: 当不再需要使用`Handler`...
- 在更新UI时,确保始终在主线程进行,以免抛出`android.os.NetworkOnMainThreadException`异常。 - 管理好生命周期,避免内存泄漏和资源浪费。 - 使用适当的缓存策略,减少不必要的网络请求或数据库查询。 通过...
在实际应用中,显示传感器信息通常涉及到更新UI,这可能需要用到线程同步技术,比如`runOnUiThread()`或使用`Handler`,因为直接在主线程外修改UI可能会导致`android.os.NetworkOnMainThreadException`异常。...
- `Toast`需要运行在主线程中,否则会抛出`android.os.NetworkOnMainThreadException`异常。 - 每次调用`show()`方法,都会重新启动`Toast`的显示计时器,因此连续调用可能导致`Toast`显示时间延长。 - `Toast`在...
如果在其他线程中修改UI元素,会抛出`android.os.NetworkOnMainThreadException`异常。因此,我们需要使用异步处理或者Handler、Runnable、AsyncTask等工具来处理后台任务,然后在主线程中更新UI。 1. **Handler和...
但这里有一个问题,Android不允许在非主线程中直接修改UI,因此这段代码会抛出`android.os.NetworkOnMainThreadException`异常,导致程序崩溃。 正确的做法是使用Handler来处理子线程与主线程的通信。Handler通常...
4. 避免在`doInBackground()`中执行与UI相关的操作,这可能导致`android.os.NetworkOnMainThreadException`异常。 5. 对于大文件或大量数据,考虑使用流式解析(如`JsonReader`),以节省内存并提高性能。 总之,...
如果其他线程尝试更新UI,Android会抛出`android.os.NetworkOnMainThreadException`或`android.view.ViewRootImpl$CalledFromWrongThreadException`异常,提示开发者必须在正确的线程中执行这些操作。 源码分析是...
- 不要在非UI线程中直接更新UI,否则会导致`android.os.NetworkOnMainThreadException`等错误。 - 使用`Looper.quit()`或`Looper.quitSafely()`可以结束`Looper`的消息循环,但需谨慎操作,因为这可能会影响到其他...
任何对UI的操作都必须在这个线程中进行,否则会抛出`android.os.NetworkOnMainThreadException`等异常。因此,当需要执行网络请求、数据库操作或大计算量的任务时,我们需要在其他线程(非UI线程)中执行。 接着,...
- 在处理用户交互(如点击按钮)时,通常需要在UI线程中进行,否则可能会抛出`android.os.NetworkOnMainThreadException`异常。 - 如果需要在视频播放完成后执行某些操作,可以监听`OnCompletionListener`事件。 ...