我在运行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

如何解决此问题?


当前回答

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

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。

其他回答

我使用新线程解决了这个问题。

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

thread.start(); 

我解决了在Kotlin使用线程的问题。有很多使用Java的例子,所以我想在Kotlin中添加一个适合我的解决方案。

 Thread {
     println("NEW THREAD")
     callAPI() // add your own task
 }.start()

因此,正如许多其他人所解释的那样,您不能在调用时阻塞主线程,因此有必要创建一个新线程。

这在Android 3.0及更高版本中发生。从Android 3.0及更高版本开始,他们限制在主线程/UI线程中运行网络操作(访问Internet的功能)(活动中创建和恢复方法产生的内容)。

这是为了鼓励在网络操作中使用单独的线程。有关如何正确执行网络活动的详细信息,请参阅AsyncTask。

您不应该在主线程(UI线程)上执行任何耗时的任务,如任何网络操作、文件I/O或SQLite数据库操作。因此,对于这种操作,您应该创建一个工作线程,但问题是您不能直接从工作线程执行任何与UI相关的操作。为此,您必须使用Handler并传递消息。

为了简化所有这些事情,Android提供了各种方式,如AsyncTask、AsyncTaskLoader、CursorLoader或IntentService。因此,您可以根据您的要求使用任何这些。

尽管上面有一个巨大的解决方案池,但没有人提到com.koushikduta.ion:https://github.com/koush/ion

它也是异步的,使用起来非常简单:

Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
   @Override
    public void onCompleted(Exception e, JsonObject result) {
        // do stuff with the result or error
    }
});