Question
How to Fix NetworkOnMainThreadException in Android (Java)
Question
I am getting an error while running my Android RSS reader project.
The following code loads and parses an RSS feed:
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();
When this code runs, Android throws the following exception:
android.os.NetworkOnMainThreadException
How can this issue be fixed correctly in Android?
Short Answer
By the end of this page, you will understand why Android throws NetworkOnMainThreadException, why network work should never run on the UI thread, and how to move RSS fetching code to a background thread safely. You will also learn how developers typically handle networking, parsing, and UI updates in real Android apps.
Concept
NetworkOnMainThreadException happens when your Android app tries to perform a network operation on the main thread.
In Android, the main thread is also called the UI thread. It is responsible for:
- drawing the screen
- responding to taps and scrolls
- updating views
- keeping the app responsive
Network calls such as this line:
url.openStream()
can take an unknown amount of time. The internet may be slow, the server may delay its response, or the connection may fail.
If Android allowed this work on the main thread, the app could freeze. To prevent that, Android throws NetworkOnMainThreadException.
Your code is doing two kinds of work:
- network I/O: downloading the RSS XML from the URL
- parsing: reading the XML using SAX
The important issue is the network request. That must happen off the main thread.
This matters in real programming because almost every app performs slow operations such as:
- API requests
- downloading files
- database access
- reading large files
A responsive app separates:
- background work for slow tasks
- main-thread work for updating the UI
That separation is a core Android programming rule.
Mental Model
Think of the main thread as a cashier serving customers in a busy store.
- If the cashier keeps helping customers, the line moves.
- If the cashier leaves to drive across town to pick up a package, everyone waits.
A network request is like sending someone across town. It may take a few seconds or much longer.
So instead of making the cashier do it, you send a worker in the background. When the package arrives, the cashier is told the result and updates the screen.
In Android terms:
- main thread = the cashier
- background thread = the worker
- UI update = telling the cashier what to display
Syntax and Examples
The core fix is: move network work off the main thread.
Problematic code
This code causes the exception if called on the UI thread:
URL url = new URL(urlToRssFeed);
InputSource is = new InputSource(url.openStream());
xmlreader.parse(is);
The openStream() call performs network I/O.
Simple background thread example
new Thread(() -> {
try {
URL url = new URL(urlToRssFeed);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlReader = parser.getXMLReader();
RssHandler rssHandler = new ();
xmlReader.setContentHandler(rssHandler);
(url.openStream());
xmlReader.parse(inputSource);
rssHandler.getFeed();
runOnUiThread(() -> {
});
} (Exception e) {
e.printStackTrace();
runOnUiThread(() -> {
});
}
}).start();
Step by Step Execution
Consider this example:
new Thread(() -> {
try {
URL url = new URL(urlToRssFeed);
InputSource inputSource = new InputSource(url.openStream());
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
XMLReader xmlReader = parser.getXMLReader();
RssHandler handler = new RssHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse(inputSource);
Feed feed = handler.getFeed();
runOnUiThread(() -> {
// show feed on screen
});
} catch (Exception e) {
runOnUiThread(() -> {
// show error
});
}
}).start();
Step by step
-
new Thread(...).start()
Real World Use Cases
This rule applies far beyond RSS parsing.
Common situations where background threading is required
- Fetching JSON from a REST API
- Downloading images or files
- Uploading form data
- Reading data from a remote server
- Parsing XML or JSON after downloading it
- Syncing app data with cloud services
Example scenarios
Weather app
A weather app requests forecast data from an API. The request must happen in the background, then the screen updates with temperature data.
News app
A news app downloads article feeds and parses them. This is very similar to your RSS reader case.
Login screen
A login form sends credentials to a backend server. The request runs in the background while a loading indicator is shown.
File downloader
A file download may take many seconds. Running it on the main thread would freeze the app immediately.
In all these cases, the pattern is the same:
- start background work
- wait for result or error
- update UI on main thread
Real Codebase Usage
In real Android projects, developers usually do more than just start a raw thread.
Common patterns
1. Guard clauses before networking
Developers validate input early:
if (urlToRssFeed == null || urlToRssFeed.isEmpty()) {
return;
}
This avoids starting bad requests.
2. Try-with-resources or proper stream closing
Streams should be closed to avoid leaks.
try (InputStream stream = url.openStream()) {
InputSource inputSource = new InputSource(stream);
xmlReader.parse(inputSource);
}
3. Error handling
Production apps distinguish different failures:
- no internet connection
- timeout
- malformed XML
- invalid URL
- server error
4. Loading state
Apps often show and hide a loading indicator:
- show spinner before request
- hide spinner after success or failure
5. Repository or service classes
Instead of putting networking directly in an Activity, developers often create classes like:
Common Mistakes
1. Performing network requests directly in onCreate() or button handlers
Broken example:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
URL url = new URL(urlToRssFeed);
InputSource is = new InputSource(url.openStream());
}
Why it is wrong:
onCreate()runs on the main threadopenStream()performs network I/O
How to avoid it:
- move the network call to a background thread
2. Updating UI from a background thread
Broken example:
new Thread(() -> {
textView.setText("Loaded");
}).start();
Why it is wrong:
- Android views must be updated on the main thread
Comparisons
| Approach | What it does | Good for | Limitations |
|---|---|---|---|
| Main thread networking | Runs request directly on UI thread | Never recommended | Causes NetworkOnMainThreadException and freezes UI |
new Thread() | Runs work in background manually | Small learning examples | More manual management |
ExecutorService | Manages background threads more cleanly | Real apps with multiple tasks | Slightly more setup |
AsyncTask | Older Android background helper | Legacy codebases only | Deprecated, should not be used in new code |
| Kotlin coroutines | Simplifies async code |
Cheat Sheet
Quick rules
NetworkOnMainThreadExceptionmeans you did network I/O on the UI thread.url.openStream()is a network operation.- Network calls must run on a background thread.
- UI updates must run on the main thread.
- Add internet permission in
AndroidManifest.xml.
Basic pattern
new Thread(() -> {
try {
// network work here
runOnUiThread(() -> {
// update UI here
});
} catch (Exception e) {
runOnUiThread(() -> {
// show error here
});
}
}).start();
Permission
<uses-permission android:name="android.permission.INTERNET" />
Safe stream usage
try (InputStream stream = url.openStream()) {
InputSource inputSource = new InputSource(stream);
xmlReader.parse(inputSource);
}
FAQ
Why does Android throw NetworkOnMainThreadException?
Because your app is trying to do a network request on the main UI thread, which can freeze the interface.
Which line in my code causes the problem?
This line is the main cause:
url.openStream()
It opens a network connection and reads data from the internet.
Can I parse XML on the main thread if the file is local?
If the file is truly local and small, parsing may be possible on the main thread, but heavy parsing can still make the UI lag. Network access must not run there.
Is AsyncTask the right fix?
For old codebases, you may see it used, but it is deprecated. Prefer a background thread, ExecutorService, or modern Android tools.
Do I also need internet permission?
Yes. Add this to the manifest:
<uses-permission android:name="android.permission.INTERNET" />
Can I update a TextView from the background thread?
No. Use runOnUiThread() or another main-thread mechanism.
What is the best modern approach in Android?
In modern apps, developers often use Retrofit with coroutines or other structured background execution tools. But the core idea is still the same: keep network work off the main thread.
Mini Project
Description
Build a small Android feature that downloads an RSS feed in the background and displays whether loading succeeded or failed. This project demonstrates the correct separation between network work and UI updates.
Goal
Create a simple RSS loader that fetches and parses a feed on a background thread, then updates the UI safely on the main thread.
Requirements
- Start the RSS download from a method such as
loadFeed() - Perform the network request and XML parsing on a background thread
- Update the UI on the main thread after success or failure
- Close the network stream properly
- Handle exceptions and show an error message if loading fails
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.