How can I fix 'android.os.NetworkOnMainThreadException'?

Viewed 1417121

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?

66 Answers

There are many great answers already on this question, but a lot of great libraries have come out since those answers were posted. This is intended as a kind of newbie-guide.

I will cover several use cases for performing network operations and a solution or two for each.

REST over HTTP

Typically JSON, but it can be XML or something else.

Full API Access

Let's say you are writing an app that lets users track stock prices, interest rates and currency exchange rates. You find an JSON API that looks something like this:

http://api.example.com/stocks                       // ResponseWrapper<String> object containing a
                                                    // list of strings with ticker symbols
http://api.example.com/stocks/$symbol               // Stock object
http://api.example.com/stocks/$symbol/prices        // PriceHistory<Stock> object
http://api.example.com/currencies                   // ResponseWrapper<String> object containing a
                                                    // list of currency abbreviation
http://api.example.com/currencies/$currency         // Currency object
http://api.example.com/currencies/$id1/values/$id2  // PriceHistory<Currency> object comparing the prices
                                                    // of the first currency (id1) to the second (id2)

Retrofit from Square

This is an excellent choice for an API with multiple endpoints and allows you to declare the REST endpoints instead of having to code them individually as with other libraries like Amazon Ion Java or Volley (website: Retrofit).

How do you use it with the finances API?

File build.gradle

Add these lines to your module level build.gradle file:

implementation 'com.squareup.retrofit2:retrofit:2.3.0' // Retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' // Gson serialization and deserialization support for retrofit, version must match retrofit version

File FinancesApi.java

public interface FinancesApi {
    @GET("stocks")
    Call<ResponseWrapper<String>> listStocks();
    @GET("stocks/{symbol}")
    Call<Stock> getStock(@Path("symbol")String tickerSymbol);
    @GET("stocks/{symbol}/prices")
    Call<PriceHistory<Stock>> getPriceHistory(@Path("symbol")String tickerSymbol);

    @GET("currencies")
    Call<ResponseWrapper<String>> listCurrencies();
    @GET("currencies/{symbol}")
    Call<Currency> getCurrency(@Path("symbol")String currencySymbol);
    @GET("currencies/{symbol}/values/{compare_symbol}")
    Call<PriceHistory<Currency>> getComparativeHistory(@Path("symbol")String currency, @Path("compare_symbol")String currencyToPriceAgainst);
}

Class FinancesApiBuilder

public class FinancesApiBuilder {
    public static FinancesApi build(String baseUrl){
        return new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(FinancesApi.class);
    }
}

Class FinancesFragment snippet

FinancesApi api = FinancesApiBuilder.build("http://api.example.com/"); //trailing '/' required for predictable behavior
api.getStock("INTC").enqueue(new Callback<Stock>(){
    @Override
    public void onResponse(Call<Stock> stockCall, Response<Stock> stockResponse){
        Stock stock = stockCall.body();
        // Do something with the stock
    }
    @Override
    public void onResponse(Call<Stock> stockCall, Throwable t){
        // Something bad happened
    }
}

If your API requires an API key or other header, like a user token, etc. to be sent, Retrofit makes this easy (see this awesome answer to Add Header Parameter in Retrofit for details).

One-off REST API access

Let's say you're building a "mood weather" app that looks up the user's GPS location and checks the current temperature in that area and tells them the mood. This type of app doesn't need to declare API endpoints; it just needs to be able to access one API endpoint.

Ion

This is a great library for this type of access.

Please read msysmilu's great answer to How can I fix 'android.os.NetworkOnMainThreadException'?.

Load images via HTTP

Volley

Volley can also be used for REST APIs, but due to the more complicated setup required, I prefer to use Retrofit from Square as above.

Let's say you are building a social networking app and want to load profile pictures of friends.

File build.gradle

Add this line to your module level build.gradle file:

implementation 'com.android.volley:volley:1.0.0'

File ImageFetch.java

Volley requires more setup than Retrofit. You will need to create a class like this to setup a RequestQueue, an ImageLoader and an ImageCache, but it's not too bad:

public class ImageFetch {
    private static ImageLoader imageLoader = null;
    private static RequestQueue imageQueue = null;

    public static ImageLoader getImageLoader(Context ctx){
        if(imageLoader == null){
            if(imageQueue == null){
                imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
                Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }
                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }
        return imageLoader;
    }
}

File user_view_dialog.xml

Add the following to your layout XML file to add an image:

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/profile_picture"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    app:srcCompat="@android:drawable/spinner_background"/>

File UserViewDialog.java

Add the following code to the onCreate method (Fragment, Activity) or the constructor (Dialog):

NetworkImageView profilePicture = view.findViewById(R.id.profile_picture);
profilePicture.setImageUrl("http://example.com/users/images/profile.jpg", ImageFetch.getImageLoader(getContext());

Picasso

Picasso is another excellent library from Square. Please see the website for some great examples.

Kotlin

If you are using Kotlin, you can use a coroutine:

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

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();

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);
}

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 on 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 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 deprecated AsyncTask.

How to fix android.os.NetworkOnMainThreadException

What is NetworkOnMainThreadException:

In Android all the UI operations we have to do on the UI thread (main thread). If we perform background operations or some network operation on the main thread then we risk this exception will occur and the app will not respond.

How to fix it:

To avoid this problem, you have to use another thread for background operations or network operations, like using asyncTask and use some library for network operations like Volley, AsyncHttp, etc.

Do this in Background Thread using AsycTask

Java

class NetworkThread extends AsyncTask<String, Void, String> {

    protected Void doInBackground(String... arg0) {
        //Your implementation
    }

    protected void onPostExecute(String result) {
        // TODO: do something with the feed
    }
}

Call wherever you need

new NetworkThread().execute("Your URL here");

Kotlin

internal class MyNetworkTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {
        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds
         } catch (e: Exception) {
            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

Call in kotlin

MyNetworkTask().execute(url)

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.

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.

If you are working in Kotlin and Anko you can add:

doAsync {
    method()
}

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.

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.

Android Jetpack introduced WorkManager, which fixes the problem of background service restriction in Android 8.1 (Oreo) and use of Alarm Manager below Android 5.0 (Lollipop) and JobScheduler above Lolipop.

Please use WorkManager to run tasks on the background thread, and it will continue to run even after the user closes the app.

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()
  ...
}
...

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) 
    }

Different options:

  1. Use a normal Java runnable thread to process the network task and one can use runOnUIThread() to update the UI

  2. intentservice/ async task can be used in case you want to update the UI after getting a network response

Kotlin version

internal class RetrieveFeedTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {

        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds

         } catch (e: Exception) {

            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

Call example,

RetrieveFeedTask().execute(url)

Here's a simple solution using OkHttp, Future, ExecutorService and Callable:

final OkHttpClient httpClient = new OkHttpClient();
final ExecutorService executor = newFixedThreadPool(3);

final Request request = new Request.Builder().url("http://example.com").build();

Response response = executor.submit(new Callable<Response>() {
   public Response call() throws IOException {
      return httpClient.newCall(request).execute();
   }
}).get();

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.

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