关于安卓高版本访问网络出现.NetworkOnMainThreadException异常的问题 .

 

原文转自http://blog.csdn.net/wangjinyu501/article/details/8755259

 

  一、问题
  在安卓2.3版本之前,我们在MainThread里面进行网络操作时没有问题的,但是在2.3版本之后(也就是3.0等),就会出现.NetworkOnMainThreadException异常。举一个例子,比如我们要显示一张网络图片,以csdn的logo为例,可以这样写:
[java] view plaincopyprint?
package com.example.netimageviewer; 
 
import java.io.IOException; 
import com.example.netimageviewer.service.ImageUtil; 
import android.os.Bundle; 
import android.os.StrictMode; 
import android.app.Activity; 
import android.graphics.Bitmap; 
import android.view.Menu; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.ImageView; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
 
    private Button button; 
    private ImageView imageView; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
              
        button = (Button) findViewById(R.id.button); 
        imageView = (ImageView) findViewById(R.id.img); 
 
        button.setOnClickListener(new OnClickListener() { 
 
            @Override 
            public void onClick(View v) { 
                               
        }); 
    } 
 
    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
        getMenuInflater().inflate(R.menu.main, menu); 
        return true; 
    } 
 

package com.example.netimageviewer;

import java.io.IOException;
import com.example.netimageviewer.service.ImageUtil;
import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.graphics.Bitmap;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

 private Button button;
 private ImageView imageView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
      
  button = (Button) findViewById(R.id.button);
  imageView = (ImageView) findViewById(R.id.img);

  button.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
                             
  });
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}
  获取图片的工具类:
[java] view plaincopyprint?
package com.example.netimageviewer.service; 
 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import com.example.netimageviewer.util.StreamUtil; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
 
public class ImageUtil { 
 
    public static Bitmap getImage(String addressUrl) throws IOException { 
 
        URL url = new URL(addressUrl); 
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
        conn.setRequestMethod("GET"); 
        conn.setConnectTimeout(5000); 
        InputStream is = conn.getInputStream(); 
        byte[] b = StreamUtil.getByte(is); 
        Bitmap bf = BitmapFactory.decodeByteArray(b, 0, b.length); 
 
        return bf; 
    } 

package com.example.netimageviewer.service;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import com.example.netimageviewer.util.StreamUtil;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class ImageUtil {

 public static Bitmap getImage(String addressUrl) throws IOException {

  URL url = new URL(addressUrl);
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  conn.setRequestMethod("GET");
  conn.setConnectTimeout(5000);
  InputStream is = conn.getInputStream();
  byte[] b = StreamUtil.getByte(is);
  Bitmap bf = BitmapFactory.decodeByteArray(b, 0, b.length);

  return bf;
 }
}
  把inputstream转化成一个byte[] 的工具类:
[java] view plaincopyprint?
package com.example.netimageviewer.util; 
 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
 
public class StreamUtil { 
 
    public static byte[] getByte(InputStream is) throws IOException{ 
        ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
        byte[] b = new byte[1024]; 
        int len = 0; 
        while ((len = is.read(b)) != -1) { 
            stream.write(b, 0, len); 
        } 
        is.close(); 
        byte[] byteStream=stream.toByteArray(); 
        System.out.println(byteStream.toString()); 
        return byteStream; 
    } 

package com.example.netimageviewer.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class StreamUtil {

 public static byte[] getByte(InputStream is) throws IOException{
  ByteArrayOutputStream stream = new ByteArrayOutputStream();
  byte[] b = new byte[1024];
  int len = 0;
  while ((len = is.read(b)) != -1) {
   stream.write(b, 0, len);
  }
  is.close();
  byte[] byteStream=stream.toByteArray();
  System.out.println(byteStream.toString());
  return byteStream;
 }
}
  然后添加上访问网络权限:<uses-permission android:name="android.permission.INTERNET"/>,最后运行程序,如果在2.3版本之前就可以显示出图片,但是在2.3版本之后就会出现.NetworkOnMainThreadException异常。
二、解决方法:
  1、一是在主线程的onCreate()方法中加入如下代码:
[java] view plaincopyprint?
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 
        .detectDiskReads().detectDiskWrites().detectNetwork() 
        .penaltyLog().build()); 
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 
        .detectLeakedSqlLiteObjects().detectLeakedClosableObjects() 
        .penaltyLog().penaltyDeath().build()); 
  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
    .detectDiskReads().detectDiskWrites().detectNetwork()
    .penaltyLog().build());
  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
    .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
    .penaltyLog().penaltyDeath().build());注:
       通过查阅相关资料,发现,自从Android 2.3之后,系统增加了一个类:StrictMode。这个类对网络的访问方式进行了一定的改变。Android的官方文档给出了这个类设置的目的:StrictMode是一个系统提供的开发工具,用以检测在开发过程中因为偶然的事故从而造成的系统潜在的问题,进而提示开发者对其进行修复。StrictMode通常用于捕获磁盘访问或者网络访问中与主进程之间交互产生的问题,因为在主进程中,UI操作和一些动作的执行是最经常用到的,它们之间会产生一定的冲突问题。将磁盘访问和网络访问从主线程中剥离可以使磁盘或者网络的访问更加流畅,提升响应度和用户体验。
       显然,大多数初学者在进行网络开发时,会选择将访问网络的代码直接放到主进程中,由于和主进程的首要工作——UI交互——相矛盾,因此,必须设置一定的检测机制,以保证系统运行的流畅,所有的异常都可以被检测。 使用的时候只需要在你项目运行的入口Activity的OnCreate中放入这段代码,那么整个项目程序都有用。不需要每个Activity里面加入。
       但是呢,从StrictMode类的用途我们就可以知道这不是一个好方法。
  2、一个比较稳妥的方法就是使用AsyncTask,这个类相信都不陌生。那代码就可以这样来写了:
[java] view plaincopyprint?
package com.example.netimageviewer.util; 
 
import java.io.InputStream; 
import java.net.URL; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.AsyncTask; 
import android.widget.ImageView; 
 
public class DownImage extends AsyncTask<String, Void, Bitmap> { 
 
    private ImageView imageView; 
 
    public DownImage(ImageView imageView) { 
        this.imageView = imageView; 
    } 
 
    @Override 
    protected Bitmap doInBackground(String... params) { 
        String url = params[0]; 
        Bitmap bitmap = null; 
        try { 
            InputStream is = new URL(url).openStream(); 
            bitmap = BitmapFactory.decodeStream(is); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return bitmap; 
    } 
 
    @Override 
    protected void onPostExecute(Bitmap result) { 
        super.onPostExecute(result); 
        imageView.setImageBitmap(result); 
    } 
 

package com.example.netimageviewer.util;

import java.io.InputStream;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

public class DownImage extends AsyncTask<String, Void, Bitmap> {

 private ImageView imageView;

 public DownImage(ImageView imageView) {
  this.imageView = imageView;
 }

 @Override
 protected Bitmap doInBackground(String... params) {
  String url = params[0];
  Bitmap bitmap = null;
  try {
   InputStream is = new URL(url).openStream();
   bitmap = BitmapFactory.decodeStream(is);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return bitmap;
 }

 @Override
 protected void onPostExecute(Bitmap result) {
  super.onPostExecute(result);
  imageView.setImageBitmap(result);
 }

}
那么MainActivity的代码就应该是这样的了:
[java] view plaincopyprint?
package com.example.netimageviewer; 
 
import java.io.IOException; 
import com.example.netimageviewer.util.DownImage; 
import android.os.Bundle; 
import android.app.Activity; 
import android.view.Menu; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import com.android.internal.util.*; 
import android.widget.ImageView; 
 
 
public class MainActivity extends Activity { 
 
    private Button button; 
    private ImageView imageView; 
    private String uriCSDN = "http://csdnimg.cn/www/images/csdnindex_logo.gif?20121229"; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
 
        button = (Button) this.findViewById(R.id.button); 
        imageView = (ImageView) this.findViewById(R.id.img); 
        button.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                new DownImage(imageView).execute(uriCSDN); 
            } 
        }); 
    } 
 
    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
        getMenuInflater().inflate(R.menu.main, menu); 
        return true; 
    } 
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值