I got an error while running my Android project for RssReader.
Code:
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();
And it shows the below error:
android.os.NetworkOnMainThreadException
How can I fix this issue?
There is another very convenient way for tackling this issue - use rxJava's concurrency capabilities. You can execute any task in background and post results to main thread in a very convenient way, so these results will be handed to processing chain.
The first verified answer advice is to use AsynTask. Yes, this is a solution, but it is obsolete nowadays, because there are new tools around.
The getUrl method provides the URL address, and it will be executed on the main thread.
makeCallParseResponse(..) - does actual work
processResponse(..) - will handle result on main thread.
The code for asynchronous execution will look like:
Compared to AsyncTask, this method allow to switch schedulers an arbitrary number of times (say, fetch data on one scheduler and process those data on another (say, Scheduler.computation()). You can also define you own schedulers.
In order to use this library, include following lines into you build.gradle file:
The last dependency includes support for the .mainThread() scheduler.
There is an excellent ebook for rx-java.
In simple words,
DO NOT DO NETWORK WORK IN THE UI THREAD
For example, if you do an HTTP request, that is a network action.
Solution:
Way:
Put all your works inside
run()
method of new threaddoInBackground()
method of AsyncTask class.But:
When you get something from Network response and want to show it on your view (like display response message in TextView), you need to return back to the UI thread.
If you don't do it, you will get
ViewRootImpl$CalledFromWrongThreadException
.How to?
onPostExecute()
methodrunOnUiThread()
method and update view inside therun()
method.You should almost always run network operations on a thread or as an asynchronous task.
But it is possible to remove this restriction and you override the default behavior, if you are willing to accept the consequences.
Add:
In your class,
and
ADD this permission in android manifest.xml file:
Consequences:
Your app will (in areas of spotty internet connection) become unresponsive and lock up, the user perceives slowness and has to do a force kill, and you risk the activity manager killing your app and telling the user that the app has stopped.
Android has some good tips on good programming practices to design for responsiveness: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
You cannot perform network I/O on the UI thread on Honeycomb. Technically, it is possible on earlier versions of Android, but it is a really bad idea as it will cause your app to stop responding, and can result in the OS killing your app for being badly behaved. You'll need to run a background process or use AsyncTask to perform your network transaction on a background thread.
There is an article about Painless Threading on the Android developer site which is a good introduction to this, and it will provide you with a much better depth of an answer than can be realistically provided here.
The accepted answer has some significant down-sides. It is not advisable to use AsyncTask for networking unless you really know what you are doing. Some of the down-sides include:
executeOnExecutor
method and supply an alternative executor). Code that works fine when run serially on ICS may break when executed concurrently on Gingerbread, say, if you have inadvertent order-of-execution dependencies.If you want to avoid short-term memory leaks, have well defined execution characteristics across all platforms, and have a base to build really robust network handling, you might want to consider:
Service
orIntentService
instead, perhaps with aPendingIntent
to return the result via the Activity'sonActivityResult
method.IntentService approach
Down-sides:
AsyncTask
, though not as much as you might thinkIntentService
with an equivalentService
implementation, perhaps like this one.Up-sides:
onActivityResult
methodAsyncTask
in anActivity
, but if the user context-switches out of the app to take a phone-call, the system may kill the app before the upload completes. It is less likely to kill an application with an activeService
.IntentService
(like the one I linked above) you can control the level of concurrency via theExecutor
.Implementation summary
You can implement an
IntentService
to perform downloads on a single background thread quite easily.Step 1: Create an
IntentService
to perform the download. You can tell it what to download viaIntent
extra's, and pass it aPendingIntent
to use to return the result to theActivity
:Step 2: Register the service in the manifest:
Step 3: Invoke the service from the Activity, passing a PendingResult object which the Service will use to return the result:
Step 4: Handle the result in onActivityResult:
A github project containing a complete working Android-Studio/gradle project is available here.
Network-based operations cannot be run on the main thread. You need to run all network-based tasks on a child thread or implement AsyncTask.
This is how you run a task in a child thread: