我在运行RssReader的Android项目时出错。

代码:

URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
RssHandler theRSSHandler = new RssHandler();
xmlreader.setContentHandler(theRSSHandler);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
return theRSSHandler.getFeed();

它显示以下错误:

android.os.NetworkOnMainThreadException

如何解决此问题?


当前回答

如果您在Kotlin和Anko工作,您可以添加:

doAsync {
    method()
}

其他回答

使用以下代码禁用严格模式:

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

不建议使用AsyncTask接口。

两种方法的完整代码

Executors.newFixedThreadPool(3).execute(() -> {
      //DO Task;        
 });

已经介绍了新的线程和异步任务解决方案。

AsyncTask理想情况下应用于短操作。普通线程不适用于Android。

看看使用HandlerThread和Handler的替代解决方案

处理程序线程

用于启动带有弯针的新线程的便捷类。然后可以使用looper创建处理程序类。请注意,仍然必须调用start()。

处理程序:

处理程序允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象。每个Handler实例都与一个线程和该线程的消息队列相关联。当您创建一个新的处理程序时,它被绑定到正在创建它的线程的线程/消息队列——从那时起,它将向该消息队列传递消息和可运行文件,并在它们从消息队列中出来时执行它们。

解决方案:

创建HandlerThread在HandlerThread上调用start()通过从HanlerThread获取Looper创建处理程序在Runnable对象中嵌入与网络操作相关的代码将可运行任务提交给处理程序

示例代码段,用于处理NetworkOnMainThreadException

HandlerThread handlerThread = new HandlerThread("URLConnection");
handlerThread.start();
handler mainHandler = new Handler(handlerThread.getLooper());

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Ravi", "Before IO call");
            URL page = new URL("http://www.google.com");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ( (line =  buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Ravi", "After IO call");
            Log.d("Ravi",text.toString());

        }catch( Exception err){
            err.printStackTrace();
        }
    }
};
mainHandler.post(myRunnable);

使用此方法的优点:

为每个网络操作创建新的线程/异步任务非常昂贵。线程/异步任务将被销毁并重新创建,以用于下一次网络操作。但使用Handler和HandlerThread方法,您可以通过使用Handler将许多网络操作(作为可运行任务)提交给单个HandlerThread。

你可以使用Kotlin和Anko。

Kotlin是Android的新官方语言。您可以在这里找到更多信息:适用于Android的Kotlin。

Anko是Android中Kotlin支持的库。GitHub页面上有一些文档。

这个解决方案非常有用,只有@AntonioLeiva编写的几行代码:使用Anko在Android中使用Kotlin运行后台任务(KAD 09)。

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}

虽然很简单,但当您在UI线程上运行后台作业时,就会出现NetworkOnMainThread,因此您必须做的一件事就是在后台运行longTask作业。你可以在Android应用程序中使用此方法和Kotlin与Anko来完成此操作。

科特林

如果您使用Kotlin,可以使用协程:

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}