bejoy george
bejoy george

Reputation: 29845

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

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

Answers (30)

SMBiggs
SMBiggs

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

rajeev ranjan
rajeev ranjan

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

Mansuu....
Mansuu....

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

Shay Ribera
Shay Ribera

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

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

Ravindra babu
Ravindra babu

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:

  1. Create HandlerThread

  2. Call start() on HandlerThread

  3. Create Handler by getting Looper from HanlerThread

  4. Embed your Network operation related code in Runnable object

  5. 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:

  1. Creating a new 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

Vaishali Sutariya
Vaishali Sutariya

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

Dhruv Jindal
Dhruv Jindal

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

henry4343
henry4343

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

Dr.Luiji
Dr.Luiji

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

perry
perry

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.

The error is the SDK warning!

Upvotes: 31

programandoconro
programandoconro

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

Sourav Kumar Verma
Sourav Kumar Verma

Reputation: 317

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

Upvotes: -2

bpr10
bpr10

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.

RxJava async task in Android

http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/

Upvotes: 5

prat3ik-patel
prat3ik-patel

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

Ashok Kumar
Ashok Kumar

Reputation: 1271

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

Upvotes: -1

Elye
Elye

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

nyxee
nyxee

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

Sunny Gupta
Sunny Gupta

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

RobotCharlie
RobotCharlie

Reputation: 1278

You can actually start a new Thread. I had this problem before and solved it by this way.

Upvotes: 0

Oleg Gryb
Oleg Gryb

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

Santanu Sur
Santanu Sur

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

Devix
Devix

Reputation: 430

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

doAsync {
    method()
}

Upvotes: 1

majurageerthan
majurageerthan

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

Richard Kamere
Richard Kamere

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

El Sushiboi
El Sushiboi

Reputation: 464

Kotlin

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

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

Upvotes: 13

Rahul
Rahul

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

J.D.1731
J.D.1731

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

Kacy
Kacy

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

Alex Shutov
Alex Shutov

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

Related Questions