NetworkOnMainThreadException

31

我刚在官方文档中发现了NetworkOnMainThreadException

我想知道模拟器是否会抛出此异常。我已经对我的应用进行了相当多的测试,据我所知所有的网络操作都不是在主线程(使用Roboguice RoboAsyncTask),但你永远不知道是否漏掉了一些。

我还使用StrictMode,并没有看到任何异常。

  1. 我的代码只是干净的,还是模拟器上没有抛出这个异常?

  2. 我们应该如何为在生产中出现这种情况做好准备?

  3. 是否有优雅的期限或者其他方式?或者已经过期了吗 ;-)?


1
这是在Android 3.0中引入的。正如文档所述,当我在UI线程上执行网络操作时,我遇到了这个问题。我将操作移动并在单独的线程上运行,问题就解决了。 - Samuh
你在模拟器中也能得到它,还是只有在设备上?没有启用StrictMode吗? - Manfred Moser
我在模拟器上获得了它,而没有在StrictMode下运行。 - Samuh
如果你想确保会出现错误消息,有意识地引发这种情况并不难。 - Chris Stratton
@Samuh,我可以问一下你在遇到NetworkOnMainThreadException时使用的是哪个版本的Android模拟器吗?因为我无法在模拟器上重现这个错误。谢谢! - sammiwei
阅读此关于**NetworkOnMainThreadException**的博客文章以获取更多信息...它非常有帮助! - Alex Lockwood
5个回答

13

使用“Handler”并不能解决问题。 “Handler”的默认行为也在主(UI)线程上执行。 - David Wasser

5
我已经测试过了,实际上模拟器上也会发生这种情况。如果你计划将应用程序放到3.0平板电脑及以上设备上,请确保在模拟器上至少测试一下你的应用程序。

2
文档中提到: "只有针对Honeycomb SDK或更高版本的应用程序才会抛出此异常。针对较早版本SDK的应用程序允许在其主事件循环线程上进行网络操作,但这是极不推荐的。请参阅《响应性设计》文档。" - Jeremy Edwards
1
请阅读我的博客文章,了解有关“NetworkOnMainThreadException”的更多信息。该文章解释了为什么在Android 3.0及以上版本中会出现此问题。 - Alex Lockwood

2

NetworkOnMainThreadException 是指在主线程中执行某些网络操作时发生的异常,比如在 Oncreate() 方法中。为了解决这个问题,你可以使用 AsyncTask,或者你也可以使用

StrictMode.ThreadPolicy mypolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

onCreate() 方法内部。


1
这是错误的。当在主线程上执行网络I/O时,会抛出异常。这可能发生在任何方法中,而不仅仅是在onCreate()中。 - David Wasser

1
从Honeycomb SDK (3)开始,Google将不再允许在主线程类中直接进行网络请求(HTTP、Socket)和其他相关操作,事实上,在UI线程中不应该直接进行网络操作,这会阻塞UI,用户体验很差!即使Google没有禁止,在正常情况下,我们也不会这样做!
因此,在Honeycomb SDK (3)版本中,您仍然可以在主线程中继续这样做,但是在3以上的版本中,这将无法工作。
1.使用Handler 将与网络相关的耗时操作放入子线程中,然后使用Handler消息机制与主线程通信。
public static final String TAG = "NetWorkException";

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.activity_net_work_exception);
    // Opens a child thread, performs network operations, waits for a return result, and uses handler to notify UI
    new Thread(networkTask).start();
}

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // get data from msg and notify UI
        Bundle data = msg.getData();
        String val = data.getString("data");
        Log.i(TAG, "the result-->" + val);
    }
};

/**
 * net work task
 */
Runnable networkTask = new Runnable() {

    @Override
    public void run() {
        // do here, the HTTP request. network requests related operations
        Message msg = new Message();
        Bundle data = new Bundle();
        data.putString("data", "request");
        msg.setData(data);
        handler.sendMessage(msg);
    }
};

使用AsyncTask。
public static final String TAG = "NetWorkException";
private ImageView mImageView;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.activity_net_work_exception);
    mImageView = findViewById(R.id.image_view);
    new DownImage(mImageView).execute();
}


class DownImage extends AsyncTask<String, Integer, 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 {
            //load image from internet , http request here
            InputStream is = new URL(url).openStream();
            bitmap = BitmapFactory.decodeStream(is);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        // nodify UI here
        imageView.setImageBitmap(result);
    }
}

3.使用 StrictMode

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

1

如果您正在运行3.0版本,我无法提供帮助;因为它默认启用了严格模式;但如果您的版本高于此,那么这可能会有所帮助。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

在创建HTTP连接之前,请包含此内容;然后它就可以工作了。

6
虽然这个回答有点老,但请放心:这种方法是错误的!绝对不能在UI线程上执行任何网络相关操作。每毫秒的延迟都可能导致一只小猫的死亡…… - WarrenFaith

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