Reputation: 29845
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?
Upvotes: 2744
Views: 1532051
Reputation: 11696
This is a big question, hence four pages of answers (many are old and should be culled)! Yet no one has yet mentioned the current google-approved kotlin solution for code within an Activity (or Fragment).
lifecycleScope.launch(Dispatchers.IO) {
result = myApiCall()
}
The lifecycleScope.launch(Dispatchers.IO)
will honor the activity lifecycle. This means that if the Activity is suspended or destroyed, the coroutine is also suspended or destroyed. GlobalScope has the potential of running even after an Activity is destroyed (causing a nasty crash).
If you are in a viewmodel, then your code is even easier:
class MyViewModel : ViewModel {
...
viewModelScope.launch {
result = myApiCall()
}
// if you want to launch off the main thread:
viewModelScope.launch(Dispatchers.IO) {
result = myApiCall()
}
...
}
This code will honor the lifecycle of MyViewModel.
Upvotes: 1
Reputation: 230
The android.os.NetworkOnMainThreadException is thrown when an application attempts to perform network operations on its main thread. This exception is specifically designed to prevent the main thread, which handles UI updates, from being blocked by potentially slow network operations. Performing network operations on the main thread can make your app appear unresponsive, which leads to a poor user experience. for more detail read this artcle
Upvotes: 0
Reputation: 1226
android.os.NetworkOnMainThreadException is thrown when network operations are performed on the main thread. You better do this in AsyncTask to remove this Exception. Write it this way:
new AsyncTask<Void, String, String>() {
@Override
protected Void doInBackground(Void... params) {
// Perform your network operation.
// Get JSON or XML string from the server.
// Store in a local variable (say response) and return.
return response;
}
protected void onPostExecute(String results) {
// Response returned by doInBackGround() will be received
// by onPostExecute(String results).
// Now manipulate your jason/xml String(results).
}
}.execute();
}
Upvotes: 4
Reputation: 381
Google deprecated the Android AsyncTask API in Android 11.
Even if you create a thread class outside the main activity, just by calling it in main, you will get the same error. The calls must be inside a runnable thread, but if you need some asynchronous code to execute in the background or some on post afterwards here, you can check out some alternatives for both Kotlin and Java:
*https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives*
The one that worked for me specifically was an answer by mayank1513 for a Java 8 implementation of a runnable thread found on the above link. The code is as follows:
new Thread(() -> {
// do background stuff here
runOnUiThread(() -> {
// OnPostExecute stuff here
});
}).start();
However, you can define the thread first in some part of your code and start it somewhere else like this:
Thread definition
Thread thread = new Thread(() -> {
// do background stuff here
runOnUiThread(() -> {
// OnPostExecute stuff here
});
});
Thread call
thread.start();
I hope this saves someone the headache of seeing the deprecated AsyncTask
.
Upvotes: 8
Reputation: 2260
You are not allowed to implement network operations on the UI thread on Android. You will have to use AsyncTask class to perform network-related operations like sending API requests, downloading an image from a URL, etc., and using callback methods of AsyncTask
, you can get your result in onPostExecute
method and you will be in the UI thread and you can populate UI with data from web service or something like that.
Example: Suppose you want to download an image from an URL: https://www.samplewebsite.com/sampleimage.jpg
Solution using AsyncTask
:
<String, Void, Bitmap>
are <Params, Progress, Result>
respectively.
public class MyDownloader extends AsyncTask<String, Void, Bitmap>
{
@Override
protected void onPreExecute() {
// Show progress dialog
super.onPreExecute();
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//Populate Ui
super.onPostExecute(bitmap);
}
@Override
protected Bitmap doInBackground(String... params) {
// Open URL connection read bitmaps and return form here
return result;
}
@Override
protected void onProgressUpdate(Void... values) {
// Show progress update
super.onProgressUpdate(values);
}
}
}
Note: Do not forget to add the Internet permission in the Android manifest file. It will work like a charm. :)
Upvotes: 6
Reputation: 38950
New Thread
and AsyncTask solutions have been explained already.
AsyncTask
should ideally be used for short operations. Normal Thread
is not preferable for Android.
Have a look at alternate solution using HandlerThread and Handler
HandlerThread
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that
start()
must still be called.
Handler:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Solution:
Create HandlerThread
Call start()
on HandlerThread
Create Handler
by getting Looper
from HanlerThread
Embed your Network operation related code in Runnable
object
Submit Runnable
task to Handler
Sample code snippet, which address 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);
Pros of using this approach:
Thread/AsyncTask
for each network operation is expensive. The Thread/AsyncTask
will be destroyed and re-created for the next Network operations. But with Handler
and HandlerThread
approach, you can submit many network operations (as Runnable tasks) to single HandlerThread
by using Handler
.Upvotes: 11
Reputation: 5121
Put your code inside:
new Thread(new Runnable() {
@Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Or:
class DemoTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... arg0) {
// Your implementation
}
protected void onPostExecute(Void result) {
// TODO: do something with the feed
}
}
Upvotes: 53
Reputation: 1066
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:
new Thread(new Runnable() {
@Override
public void run() {
try {
// Your implementation goes here
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
Upvotes: 65
Reputation: 3921
Do the network actions on another thread.
For example:
new Thread(new Runnable() {
@Override
public void run() {
// Do network action in this function
}
}).start();
And add this to file AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Upvotes: 97
Reputation: 6221
I solved this problem using a new Thread
.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
// Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
Upvotes: 532
Reputation: 856
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads.
Upvotes: 31
Reputation: 2729
I solved using Thread
in Kotlin. There are many examples using Java, so I wanted to add a solution that worked for me in Kotlin.
Thread {
println("NEW THREAD")
callAPI() // add your own task
}.start()
So, as many others greatly explained, you cannot block the main thread with you call, so it is necessary to create a new thread.
Upvotes: 3
Reputation: 317
Executors.newFixedThreadPool(3).execute(() -> {
//DO Task;
});
Upvotes: -2
Reputation: 1096
We can also use RxJava to move network operations to a background thread. And it's fairly simple as well.
webService.doSomething(someData)
.subscribeOn(Schedulers.newThread())-- This for background thread
.observeOn(AndroidSchedulers.mainThread()) -- for callback on UI
.subscribe(result -> resultText.setText("It worked!"),
e -> handleError(e));
You can do a lot more stuff with RxJava. Here are some links for RxJava. Feel free to dig in.
Upvotes: 5
Reputation: 1215
You have to simply add the following line in file manifest.xml after the manifest tag
<uses-permission android:name="android.permission.INTERNET"/>
And in the activity file, add the following code after the binding statement:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Upvotes: -3
Reputation: 1271
Different options:
Use a normal Java runnable thread to process the network task and one can use runOnUIThread() to update the UI
intentservice/ async task can be used in case you want to update the UI after getting a network response
Upvotes: -1
Reputation: 60261
As of 2018, I would recommend to use RxJava in Kotlin for network fetching. A simple example is below.
Single.fromCallable {
// Your Network Fetching Code
Network.fetchHttp(url)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
// What you need to do with your result on the view
result -> view.updateScreen(result)
}
Upvotes: -1
Reputation: 2811
I converted the network access function returning a value into a suspend function like so:
suspend fun isInternetReachable(): Boolean {
...
...
return result
}
Then I modified where I was using the function to fit into this:
...
Globalscope.async{
...
result = isInternetReachable()
...
}
...
Upvotes: 0
Reputation: 837
Android does not allow to run long-running operations on the main thread.
So just use a different thread and post the result to the main thread when needed.
new Thread(new Runnable() {
@Override
public void run() {
/*
// Run operation here
*/
// After getting the result
runOnUiThread(new Runnable() {
@Override
public void run() {
// Post the result to the main thread
}
});
}
}).start();
Upvotes: 9
Reputation: 1278
You can actually start a new Thread. I had this problem before and solved it by this way.
Upvotes: 0
Reputation: 5259
These answers need to be updated to use more contemporary way to connect to servers on the Internet and to process asynchronous tasks in general.
For example, you can find examples where Tasks are used in a Google Drive API sample. The same should be used in this case. I'll use the OP's original code to demonstrate this approach.
First, you'll need to define an off-main thread executor and you need to do it only once:
private val mExecutor: Executor = Executors.newSingleThreadExecutor()
Then process your logic in that executor, which will be running off main thread
Tasks.call (mExecutor, Callable<String> {
val url = URL(urlToRssFeed)
val factory = SAXParserFactory.newInstance()
val parser = factory.newSAXParser()
val xmlreader = parser.getXMLReader()
val theRSSHandler = RssHandler()
xmlreader.setContentHandler(theRSSHandler)
val is = InputSource(url.openStream())
xmlreader.parse(is)
theRSSHandler.getFeed()
// Complete processing and return a String or other object.
// E.g., you could return Boolean indicating a success or failure.
return@Callable someResult
}).continueWith{
// it.result here is what your asynchronous task has returned
processResult(it.result)
}
continueWith clause will be executed after your asynchronous task is completed and you will have an access to a value that has been returned by the task through it.result.
Upvotes: 1
Reputation: 11487
You can use Kotlin coroutines:
class YoutActivity : AppCompatActivity, CoroutineScope {
override fun onCreate(...) {
launch { yourHeavyMethod() }
}
suspend fun yourHeavyMethod() {
with(Dispatchers.IO){ yourNetworkCall() }
...
...
}
}
You can follow this guide.
Upvotes: 2
Reputation: 430
If you are working in Kotlin and Anko you can add:
doAsync {
method()
}
Upvotes: 1
Reputation: 2319
From developer-android:
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
Using newCachedThreadPool
is the good one. also you can consider other options like newSingleThreadExecutor
, newFixedThreadPool
ExecutorService myExecutor = Executors.newCachedThreadPool();
myExecutor.execute(new Runnable() {
@Override
public void run() {
URL url = new URL(urls[0]);
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);
}
});
ThreadPoolExecutor is a helper class to make this process easier. This class manages the creation of a group of threads, sets their priorities, and manages how work is distributed among those threads. As workload increases or decreases, the class spins up or destroys more threads to adjust to the workload.
See this for more information about Android threads.
Upvotes: 3
Reputation: 799
I had a similar problem. I just used the following in the oncreate method of your activity.
// Allow strict mode
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
And it worked well.
The caveat is that using this for a network request that takes more than 100 milliseconds will cause noticeable UI freeze and potentially ANRs (Application Not Responding), so keep that in mind.
Upvotes: 3
Reputation: 464
If you are using Kotlin, you can use a coroutine:
fun doSomeNetworkStuff() {
GlobalScope.launch(Dispatchers.IO) {
// ...
}
}
Upvotes: 13
Reputation: 3349
On Android, network operations cannot be run on the main thread. You can use Thread
, AsyncTask
(short-running tasks), Service
(long-running tasks) to do network operations. android.os.NetworkOnMainThreadException
is thrown when an application attempts to perform a networking operation on its main thread. If your task took above five seconds, it takes a force close.
Run your code in AsyncTask
:
class FeedTask extends AsyncTask<String, Void, Boolean> {
protected RSSFeed doInBackground(String... urls) {
// TODO: Connect
}
protected void onPostExecute(RSSFeed feed) {
// TODO: Check this.exception
// TODO: Do something with the feed
}
}
Or
new Thread(new Runnable(){
@Override
public void run() {
try {
// Your implementation
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
This is not recommended.
But for debugging purposes, you can disable the strict mode as well using the following code:
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
Upvotes: 5
Reputation: 415
You can either use Kotlin and Anko.
Kotlin is a new official language for Android. You can find more about it here: Kotlin for Android.
Anko is a supported library for Kotlin in Android. Some documentation is on the GitHub page.
The solution which is really useful and has only a few lines of code written by @AntonioLeiva: Using Anko to run background tasks with Kotlin in Android (KAD 09).
doAsync {
var result = runLongTask()
uiThread {
toast(result)
}
}
Simple as it is, NetworkOnMainThread
occurs when you run a background job on the UI thread, so one thing you have to do is to run your longTask job in the background. You can do this using this method and Kotlin with Anko in your Android app.
Upvotes: 6
Reputation: 3430
This works. I just made Dr.Luiji's answer a little simpler.
new Thread() {
@Override
public void run() {
try {
//Your code goes here
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Upvotes: 10
Reputation: 3282
There is another very convenient way for tackling this issue - use RxJava's concurrency capabilities. You can execute any task in the background and post results to the main thread in a very convenient way, so these results will be handed to the 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.
String getUrl() {
return "SomeUrl";
}
private Object makeCallParseResponse(String url) {
return null;
//
}
private void processResponse(Object o) {
}
The getUrl method provides the URL address, and it will be executed on the main thread.
makeCallParseResponse(..)
- does the actual work
processResponse(..)
- will handle the result on the main thread.
The code for asynchronous execution will look like:
rx.Observable.defer(new Func0<rx.Observable<String>>() {
@Override
public rx.Observable<String> call() {
return rx.Observable.just(getUrl());
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map(new Func1<String, Object>() {
@Override
public Object call(final String s) {
return makeCallParseResponse(s);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
processResponse(o);
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// Process error here, it will be posted on
// the main thread
}
});
Compared to AsyncTask, this method allows 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 your own schedulers.
In order to use this library, include following lines into your build.gradle file:
compile 'io.reactivex:rxjava:1.1.5'
compile 'io.reactivex:rxandroid:1.2.0'
The last dependency includes support for the .mainThread() scheduler.
There is an excellent e-book for RxJava.
Upvotes: 8