Как я могу исправить android.os.NetworkOnMainThreadException? - PullRequest
2239 голосов
/ 14 июня 2011

Я получил ошибку при запуске моего проекта Android для RssReader.

Код:

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

И это показывает ошибку ниже:

android.os.NetworkOnMainThreadException

Как я могу исправить эту проблему?

Ответы [ 53 ]

6 голосов
/ 24 июня 2016

Существует еще один очень удобный способ решения этой проблемы - использование возможностей параллелизма rxJava.Вы можете выполнить любую задачу в фоновом режиме и опубликовать результаты в основном потоке очень удобным способом, поэтому эти результаты будут переданы в цепочку обработки.

Первый проверенный ответ - использовать AsynTask.Да, это решение, но в настоящее время оно устарело, потому что вокруг появились новые инструменты.

String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}

Метод getUrl предоставляет URL-адрес, и он будет выполняться в главном потоке.

makeCallParseResponse (..) - выполняет фактическую работу

processResponse (..) - обрабатывает результат в основном потоке.

Код для асинхронного выполнения будет выглядеть следующим образом:

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

По сравнению с AsyncTask этот метод позволяет переключать планировщики произвольное количество раз (скажем, получать данные из одного планировщика и обрабатывать эти данные в другом (например, Scheduler.computation ()). Вы также можете определить свой собственныйпланировщики.

Чтобы использовать эту библиотеку, включите в файл build.gradle следующие строки:

   compile 'io.reactivex:rxjava:1.1.5'
   compile 'io.reactivex:rxandroid:1.2.0'

Последняя зависимость включает поддержку планировщика .mainThread ().

Существует отличная книга для rx-java .

6 голосов
/ 18 декабря 2015

Вы не можете осуществлять сетевые операции в потоке пользовательского интерфейса на Android. Вам придется использовать класс AsyncTask для выполнения операций, связанных с сетью, таких как отправка запроса API, загрузка изображения с URL-адреса и т. Д. И использование методов обратного вызова AsyncTask, вы можете получить результат с помощью метода onPostExecute, вы будете в потоке пользовательского интерфейса может заполнять пользовательский интерфейс данными из веб-службы или чем-то подобным.

Пример. Предположим, вы хотите загрузить изображение с URL: https://www.samplewebsite.com/sampleimage.jpg

Решение с использованием AsyncTask: соответственно.

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


    }
}

Примечание. Не забудьте добавить интернет-разрешение в файл манифеста Android. Это будет работать как шарм. :)

5 голосов
/ 04 сентября 2017

Основной поток является потоком пользовательского интерфейса, и вы не можете выполнить в основном потоке операцию, которая может заблокировать взаимодействие с пользователем. Вы можете решить это двумя способами:

Принудительно выполнить задачу в главном потоке, как это

StrictMode.ThreadPolicy threadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(threadPolicy);

Или создайте простой обработчик и обновите основной поток, если хотите.

Runnable runnable;
Handler newHandler;

newHandler = new Handler();
runnable = new Runnable() {
    @Override
    public void run() {
         try {
            //update UI
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
};
newHandler.post(runnable);

И для остановки потока используйте:

newHandler.removeCallbacks(runnable);

Для получения дополнительной информации проверьте это: Безболезненная резьба

4 голосов
/ 19 февраля 2017

Вы также можете решить эту проблему, используя строгий режим, используя приведенный ниже код.Это также альтернатива решению этой проблемы.

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

Но лучше всего использовать AsyncTask.

4 голосов
/ 16 января 2017

android.os.NetworkOnMainThreadException генерируется, когда сетевые операции выполняются в основном потоке. Вам лучше сделать это в AsyncTask, чтобы удалить это исключение. Запишите это так:

    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();
}
4 голосов
/ 04 октября 2016

Как исправить android.os.NetworkOnMainThreadException

Что такое исключение NetworkOnMainThreadException:

В Android все операции пользовательского интерфейса мы должны выполнять в потоке пользовательского интерфейса (основной поток). Если мы выполняем фоновые операции или некоторые сетевые операции в главном потоке, мы рискуем, что произойдет это исключение, и приложение не ответит.

Как это исправить:

Чтобы избежать этой проблемы, вы должны использовать другой поток для фоновых операций или сетевых операций, например asyncTask, и использовать некоторую библиотеку для сетевых операций, таких как Volley, AsyncHttp и т. Д.

4 голосов
/ 15 января 2016

Это исключение выдается, когда приложение пытается выполнить сетевую операцию в своем основном потоке.Если ваше задание заняло более пяти секунд, оно требует принудительного закрытия.

Запустите ваш код в AsyncTask:

class RetrieveFeedTask 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
    }
}
3 голосов
/ 21 декабря 2014

Я решил эту проблему простым способом ...

Я добавил после oncreate StrictMode.enableDefaults(); и решил это.

Или

Использование Serviceили AsyncTask, чтобы решить эту проблему

Примечание:

Do not change SDK version
Do not use a separate thread

Для получения дополнительной информации проверьте это .

3 голосов
/ 23 мая 2016

Мы также можем использовать RxJava для перемещения сетевых операций в фоновый поток. И это довольно просто.

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

Вы можете сделать намного больше с RxJava. Вот несколько ссылок на RxJava. Не стесняйтесь копаться.

Асинхронное задание RxJava в Android

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

2 голосов
/ 17 марта 2017

Вы не можете вызвать сеть в основном потоке или потоке пользовательского интерфейса. На Android, если вы хотите позвонить в сеть, есть два варианта -

  1. Вызовите asynctask, который запустит один фоновый поток для обработки сетевой операции.
  2. Вы можете создать свой собственный работающий поток для обработки сетевых операций.

Лично я предпочитаю asynctask. Для получения дополнительной информации вы можете обратиться по этой ссылке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...