Как исправить ошибку android.os.NetworkOnMainThreadException?

avatar
bejoy george
14 июня 2011 в 12:02
1342298
67
2578

У меня возникла ошибка при запуске проекта 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

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

Источник
Adrian Monk
7 августа 2012 в 12:38
133

Прочтите это сообщение в блоге в NetworkOnMainThreadException для получения дополнительной информации. Это объясняет, почему это происходит на Android 3.0 и выше.

Anuj Sharma
23 января 2014 в 06:39
6

Чтобы быть в курсе, сначала прочтите о сетевых запросах в Android, а затем я бы рекомендовал изучить «Залп».

Snicolas
11 февраля 2014 в 22:55
3

Есть много альтернативных библиотек, которые решают эту проблему. Многие из них перечислены внизу этой страницы. Если есть еще, берем :)

Naveed Ahmad
30 октября 2014 в 20:44
0

Вам нужно запускать интернет-действия в потоке, отдельном от основного (UI) потока.

Jay
19 ноября 2017 в 22:51
0

"Из-за ошибки в предыдущих версиях Android система не помечала запись в сокет TCP в основном потоке как нарушение строгого режима. Android 7.0 исправляет эту ошибку. Приложения, которые демонстрируют такое поведение, теперь выдают файл android.os. NetworkOnMainThreadException. " - Значит, до недавнего времени некоторые из нас этого не делали! developer.android.com/about/versions/nougat/…

Ответы (67)

avatar
Michael Spector
14 июня 2011 в 12:15
2637

ПРИМЕЧАНИЕ: AsyncTask устарел на уровне API 30.
AsyncTask | Разработчики Android

Это исключение возникает, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Запустите свой код в AsyncTask:

class RetrieveFeedTask extends AsyncTask<String, Void, RSSFeed> {

    private Exception exception;

    protected RSSFeed doInBackground(String... urls) {
        try {
            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);

            return theRSSHandler.getFeed();
        } catch (Exception e) {
            this.exception = e;

            return null;
        } finally {
            is.close();
        }
    }

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

Как выполнить задачу:

В файле MainActivity.java вы можете добавить эту строку в свой oncreate() метод

new RetrieveFeedTask().execute(urlToRssFeed);

Не забудьте добавить это в AndroidManifest.xml файл:

<uses-permission android:name="android.permission.INTERNET"/>
y_159
14 июня 2021 в 03:18
0

Таким образом, выполнение сетевых операций в основном потоке проблематично только в Android, а не в стандартном Java-коде (код написан на Java, но не для приложения Android). ??

avatar
programandoconro
10 мая 2022 в 08:46
0

Я решил использовать Thread в Котлине. Есть много примеров использования Java, поэтому я хотел добавить решение, которое сработало для меня в Kotlin.

 Thread {
     println("NEW THREAD")
     callAPI() // add your own task
 }.start()

Итак, как объясняли многие другие, вы не можете заблокировать основной поток своим вызовом, поэтому необходимо создать новый поток.

avatar
Sourav Kumar Verma
1 мая 2022 в 09:58
-1
Executors.newFixedThreadPool(3).execute(() -> {
      //DO Task;        
 });
Joseph
3 мая 2022 в 01:15
0

Вам нужно добавить некоторые пояснения к вашему ответу

avatar
Alex Mamo
22 марта 2022 в 09:44
0

Для пользователей Kotlin, которые не хотят использовать сопрограммы, это будет так же просто, как:

Thread {
    //Run the long-time operation.
    val serverResponse = getResponseFromServer()

    runOnUiThread {
        //Display the result on the main thread.
        Log.d("TAG", serverResponse.toString())
    }
}.start()
avatar
nyxee
4 апреля 2021 в 23:52
1

Я преобразовал функцию доступа к сети, возвращающую значение, в функцию приостановки, например:


suspend fun isInternetReachable(): Boolean {
  ...
  ...
  return result
}

Затем я изменил место использования функции, чтобы вписаться в это:

...
Globalscope.async{
  ...
  result = isInternetReachable()
  ...
}
...
avatar
Sunny Gupta
21 февраля 2021 в 08:54
3

Android не позволяет выполнять длительные операции в основном потоке.

Так что просто используйте другой поток и опубликуйте результат в основном потоке, когда это необходимо.

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();
avatar
neu242
25 января 2021 в 10:12
0

Вот простое решение с использованием OkHttp, Future, ExecutorService и 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();
Arpan Saini
6 февраля 2021 в 11:54
0

Получение ошибки: System.err: java.util.concurrent.ExecutionException: javax.net.ssl.SSLException: невозможно проанализировать заголовок пакета TLS

neu242
8 февраля 2021 в 10:48
0

@ArpanSaini Работает ли ваш точный URL с помощью curl или в браузере? Может быть, переключиться с https на http (или наоборот) и посмотреть, работает ли это?

avatar
Shay Ribera
15 октября 2020 в 14:56
4

Google не поддерживает Android AsyncTask API в Android 11.

Даже если вы создадите класс потока вне основного действия, просто вызвав его в main, вы получите ту же ошибку. Вызовы должны происходить внутри исполняемого потока, но если вам нужен асинхронный код для выполнения в фоновом режиме или какой-то после публикации по почте здесь, вы можете проверить некоторые альтернативы как для Kotlin, так и для Java:

*https://coderhelper.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives*

То, что сработало для меня, было ответом mayank1513 на реализацию Java 8 исполняемого потока, найденную по приведенной выше ссылке. Код выглядит следующим образом:

new Thread(() -> {
        // do background stuff here
        runOnUiThread(()->{
            // OnPostExecute stuff here
        });
    }).start();

Однако вы можете сначала определить поток в какой-то части вашего кода и запустить его в другом месте, например:

Определение резьбы

Thread thread = new Thread(() -> {
            // do background stuff here
            runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        });

Вызов потока

thread.start();

Я надеюсь, что это избавит кого-то от головной боли при просмотре устаревшего AsyncTask.

avatar
El Sushiboi
14 августа 2020 в 14:19
8

Котлин

Если вы используете Kotlin, вы можете использовать сопрограмму :

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}
avatar
Oleg Gryb
14 марта 2020 в 00:11
2

Эти ответы необходимо обновить, чтобы использовать более современный способ подключения к серверам в Интернете и обрабатывать асинхронные задачи в целом.

Например, вы можете найти примеры использования задач в примере Google Drive API. То же самое следует использовать и в этом случае. Я буду использовать исходный код OP, чтобы продемонстрировать этот подход.

Во-первых, вам нужно определить исполнителя внешнего потока, и вам нужно сделать это только один раз:

private val mExecutor: Executor = Executors.newSingleThreadExecutor()

Затем обработайте вашу логику в этом исполнителе, который будет работать вне основного потока

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 будет выполнено после завершения асинхронной задачи, и у вас будет доступ к значению, которое было возвращено задачей через it.result .

.

avatar
Rahul
11 февраля 2020 в 10:28
7

В Android сетевые операции не могут выполняться в основном потоке. Вы можете использовать Thread, AsyncTask (краткосрочные задачи), Service (длительные задачи) для выполнения сетевых операций. android.os.NetworkOnMainThreadException выдается, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Если ваша задача заняла более пяти секунд, потребуется принудительное закрытие.

Введите свой код в 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
    }
}

Или

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();

Это не рекомендуется.

Но для отладки вы также можете отключить строгий режим, используя следующий код:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy =
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
avatar
majurageerthan
1 января 2020 в 14:52
3

От developer-android:

AsyncTasks в идеале следует использовать для коротких операций (максимум несколько секунд).

Использование newCachedThreadPool - хороший вариант. также вы можете рассмотреть другие варианты, такие как 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 - вспомогательный класс, упрощающий этот процесс. Этот класс управляет созданием группы потоков, устанавливает их приоритеты и управляет распределением работы между этими потоками. По мере увеличения или уменьшения рабочей нагрузки класс раскручивается или разрушается больше потоков для адаптации к рабочей нагрузке.

См. этот для получения дополнительной информации о потоках Android.

avatar
Jinesh Francis
6 ноября 2019 в 04:52
1

Представлен Android Jetpack WorkManager, который устраняет проблему ограничения фонового обслуживания в Android 8.1 Android 8.1 <706281784922 (ниже) > Android 5.0 (Lollipop) и JobScheduler выше Lolipop.

Используйте WorkManager для выполнения задач в фоновом потоке, и он будет продолжать работать даже после того, как пользователь закроет приложение.

Peter Mortensen
22 июля 2021 в 18:30
0

Есть только один фоновый поток или их несколько (в данном контексте)?

avatar
Richard Kamere
18 августа 2019 в 17:27
4

У меня была аналогичная проблема. Я просто использовал следующее в методе oncreate вашей деятельности.

// Allow strict mode
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

И это сработало.

Предостережение заключается в том, что использование этого параметра для сетевого запроса, который занимает более 100 миллисекунд, вызовет заметное зависание пользовательского интерфейса и, возможно, ANR (приложение не отвечает), так что имейте это в виду.

Shubham Suryawanshi
13 сентября 2019 в 07:41
1

@RichardKamere из официальной документации для StrictMode, вы можете проверить, что «StrictMode - это инструмент разработчика, который обнаруживает вещи, которые вы могли делать случайно, и обращает на них ваше внимание, чтобы вы могли их исправить» и «вы никогда не должны оставлять StrictMode включенным в приложения, распространяемые в Google Play ». Проверить здесь

Jorgesys
28 октября 2019 в 21:04
1

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

shareef
10 марта 2020 в 08:42
0

@Zun что, если я хочу проверить интернет-соединение на сервере API?

avatar
Vipul Prajapati
10 июня 2019 в 04:50
4

Сделайте это в фоновом потоке, используя 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
    }
}

Звоните, где вам нужно

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

Котлин

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

Звоните в котлин

MyNetworkTask().execute(url)
avatar
Sazzad Hissain Khan
1 июня 2019 в 07:41
0

Версия Kotlin

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

Пример вызова:

RetrieveFeedTask().execute(url)
avatar
Santanu Sur
1 марта 2019 в 17:37
2

Вы можете использовать Kotlin сопрограммы:

 class YoutActivity : AppCompatActivity, CoroutineScope {
      
      override fun onCreate(...) {
         launch {  yourHeavyMethod() }
      }

      suspend fun yourHeavyMethod() {
         with(Dispatchers.IO){ yourNetworkCall() }
         ...
         ...
      }
 } 

Вы можете следовать этому руководству.

avatar
Devix
10 декабря 2018 в 22:09
2

Если вы работаете в Котлине и Анко, вы можете добавить:

doAsync {
    method()
}
EpicPandaForce
31 декабря 2019 в 11:53
1

Анко устарел

Peter Mortensen
22 июля 2021 в 18:15
0

Источник устаревания Anko.

avatar
Ashok Kumar
10 мая 2018 в 09:24
0

Различные варианты:

  1. Используйте обычный исполняемый поток Java для обработки сетевой задачи, и можно использовать runOnUIThread () для обновления пользовательского интерфейса

  2. задача intentservice / async может использоваться в случае, если вы хотите обновить пользовательский интерфейс после получения сетевого ответа

avatar
yoAlex5
17 марта 2018 в 15:58
14

Вы можете переместить часть кода в другой поток, чтобы разгрузить main thread и избежать получения ANR, NetworkOnMainThreadException, , не может получить доступ к базе данных в основном потоке, поскольку это может потенциально заблокировать пользовательский интерфейс на длительный период времени).

Есть несколько подходов, которые вы должны выбрать в зависимости от ситуации

Java Thread или Android HandlerThread:

Потоки Java используются только один раз и умирают после выполнения своего метода выполнения.

HandlerThread - удобный класс для запуска нового потока, имеющего петлитель.

AsyncTask ( устарело на уровне API 30)

AsyncTask разработан как вспомогательный класс вокруг Thread и Handler и не представляет собой универсальную структуру потоков. В идеале AsyncTasks следует использовать для коротких операций (максимум несколько секунд). Если вам необходимо поддерживать работу потоков в течение длительного времени, настоятельно рекомендуется использовать различные API-интерфейсы, предоставляемые пакетом java.util.concurrent, такие как Executor , ThreadPoolExecutor и FutureTask .

Поскольку основной поток монополизирует компоненты пользовательского интерфейса, невозможно получить доступ к некоторым View, поэтому на помощь приходит Handler

[Структура исполнителя]

Класс ThreadPoolExecutor, реализующий ExecutorService, который обеспечивает точный контроль над пулом потоков (например, размер основного пула, максимальный размер пула, время сохранения активности и т. Д.)

ScheduledThreadPoolExecutor - класс, расширяющий ThreadPoolExecutor. Он может планировать задачи с заданной задержкой или периодически.

FutureTask

FutureTask выполняет асинхронную обработку, однако, если результат еще не готов или обработка не завершена, вызов get () заблокирует поток

AsyncTaskLoaders

AsyncTaskLoaders, поскольку они решают множество проблем, присущих AsyncTask

IntentService

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

Планировщик заданий

Фактически вы должны создать службу и создать задание с помощью JobInfo.Builder, в котором указаны ваши критерии для запуска службы.

RxJava

Библиотека для создания асинхронных программ и программ, основанных на событиях, с использованием наблюдаемых последовательностей.

Сопрограммы (Котлин)

Суть его в том, что асинхронный код выглядит так же, как синхронный

Подробнее здесь, здесь, здесь и здесь702994420

avatar
Elye
17 января 2018 в 21:54
0

По состоянию на 2018 год я бы рекомендовал использовать RxJava в Kotlin для получения данных по сети. Ниже приведен простой пример.

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) 
    }
Elye
17 января 2018 в 21:56
0

Вы можете найти полный код на github.com/elye/demo_android_network_evolution

Elye
17 января 2018 в 21:56
0

Если вы хотите посмотреть на общую тенденцию доступа к сети в Android в историческом плане, посетите medium.com/@elye.project/…

avatar
KG6ZVP
20 октября 2017 в 23:50
20

На этот вопрос уже есть много отличных ответов, но с тех пор, как эти ответы были опубликованы, появилось много отличных библиотек. Это предназначено как своего рода руководство для новичков.

Я расскажу о нескольких вариантах использования для выполнения сетевых операций и по решению или по два для каждого.

REST через HTTP

Обычно JSON, но это может быть XML или что-то еще.

Полный доступ к API

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

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)

Модернизация от Square

Это отличный выбор для API с несколькими конечными точками и позволяет объявлять конечные точки REST вместо того, чтобы кодировать их по отдельности, как в других библиотеках, таких как Amazon Ion Java или Volley (веб-сайт: Модернизация ).

Как вы используете его с API финансов?

Файл build.gradle

Добавьте эти строки в свой модуль уровень build.gradle файл:

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

Файл 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);
}

Класс FinancesApiBuilder

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

Класс FinancesFragment фрагмент

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

Если ваш API требует отправки ключа API или другого заголовка, например токена пользователя и т. Д., Retrofit упрощает это (см. этот замечательный ответ на Добавить параметр заголовка в разделе «Модернизация» для подробностей).

Одноразовый доступ к REST API

Предположим, вы создаете приложение для «настроенной погоды», которое ищет местоположение пользователя по GPS, проверяет текущую температуру в этой области и сообщает ему настроение. Приложению этого типа не нужно объявлять конечные точки API; ему просто нужно иметь доступ к одной конечной точке API.

Ионный

Это отличная библиотека для такого типа доступа.

Прочтите, пожалуйста, отличный ответ msysmilu на Как я могу исправить ошибку android.os.NetworkOnMainThreadException?

Загрузить изображения через HTTP

Залп

Volley также можно использовать для REST API, но из-за необходимости более сложной настройки я предпочитаю использовать Retrofit из Square, как указано выше.

Допустим, вы создаете приложение для социальной сети и хотите загрузить фотографии профилей друзей.

Файл build.gradle

Добавьте эту строку в свой модуль уровень build.gradle файл:

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

Файл ImageFetch.java

Volley требует больше настроек, чем модернизация. Вам нужно будет создать такой класс, чтобы настроить RequestQueue, ImageLoader и ImageCache, но это не так уж плохо:

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

Файл user_view_dialog.xml

Добавьте следующее в XML-файл макета, чтобы добавить изображение:

<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"/>

Файл UserViewDialog.java

Добавьте следующий код в метод onCreate (фрагмент, действие) или конструктор (диалог):

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

Пикассо

Picasso - еще одна отличная библиотека от Square. Пожалуйста, посетите наш веб-сайт, чтобы увидеть несколько отличных примеров.

avatar
Sharath kumar
4 сентября 2017 в 10:43
9

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

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

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

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

avatar
Rahul
1 августа 2017 в 17:31
0

Никогда не выполняйте длительную работу над потоком пользовательского интерфейса. Эта длительная работа может заключаться в обмене данными с сервером, чтении / записи файлов и т. Д. Эти задачи должны выполняться в фоновом потоке. Вот почему создаются Service, AsyncTask, Threads. Вы можете отключить StrictMode, и это предотвратит сбой. Но это никогда не рекомендуется.

Я бы посоветовал вам воспользоваться преимуществами StrictMode, по крайней мере, в режиме отладки. Используйте приведенный ниже код, чтобы получить журналы любой проблемы, которая замедляет работу вашего приложения в основном потоке.

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());

Вы можете установить разные штрафы:

penaltyLog() // to print log
penaltyDeath() // This will crash you App(so costly penalty)
penaltyDialog() // Show alert when something went lazy on Main thread

Подробнее о StrictMode здесь: StrictMode | Разработчики Android.

avatar
J.D.1731
10 июля 2017 в 09:06
7

Вы можете использовать Kotlin и Anko.

Kotlin - новый официальный язык для Android . Вы можете узнать об этом подробнее здесь: Kotlin для Android .

Anko - это поддерживаемая библиотека для Kotlin в Android. Некоторая документация находится на странице GitHub.

Решение, которое действительно полезно и содержит всего несколько строк кода, написанных @AntonioLeiva: Использование Anko для запуска фоновых задач с Kotlin в Android (KAD 09) .

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}

Каким бы простым он ни был, NetworkOnMainThread возникает, когда вы запускаете фоновое задание в потоке пользовательского интерфейса, поэтому вам нужно выполнить задание longTask в фоновом режиме. Вы можете сделать это с помощью этого метода и Kotlin с Anko в вашем приложении для Android.

Peter Mortensen
22 июля 2021 в 18:01
2

На странице GitHub: «Anko устарел. Пожалуйста, см. эту страницу для получения дополнительной информации».

avatar
Shinoo Goyal
9 июня 2017 в 05:57
9

RxAndroid - еще одна лучшая альтернатива этой проблеме, которая избавляет нас от хлопот с созданием потоков и последующей публикацией результатов в потоке пользовательского интерфейса Android.

Нам просто нужно указать потоки, в которых должны выполняться задачи, и все будет обрабатываться внутри.

Observable<List<String>> musicShowsObservable = Observable.fromCallable(new Callable<List<String>>() {

  @Override
  public List<String> call() {
    return mRestClient.getFavoriteMusicShows();
  }

});

mMusicShowSubscription = musicShowsObservable
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Observer<List<String>>() {

    @Override
    public void onCompleted() { }

    @Override
    public void onError(Throwable e) { }

    @Override
    public void onNext(List<String> musicShows) {
        listMusicShows(musicShows);
    }
});
  1. Если указать (Schedulers.io()), RxAndroid будет запускать getFavoriteMusicShows() в другом потоке.

  2. Используя AndroidSchedulers.mainThread(), мы хотим наблюдать этот Observable в потоке пользовательского интерфейса, т.е. мы хотим, чтобы наш обратный вызов onNext() вызывался в потоке пользовательского интерфейса.

avatar
Ravindra babu
5 мая 2017 в 20:11
11

Новые решения Thread и AsyncTask уже были объяснены.

AsyncTask в идеале следует использовать для коротких операций. Обычный Thread не рекомендуется для Android.

Посмотрите на альтернативное решение, используя HandlerThread и Handler

HandlerThread

Удобный класс для запуска нового потока с петлителем. Затем петлитель можно использовать для создания классов обработчиков. Обратите внимание, что start() по-прежнему необходимо вызывать.

Обработчик:

Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с MessageQueue потока. Каждый экземпляр Handler связан с одним потоком и очередью сообщений этого потока. Когда вы создаете новый обработчик, он привязывается к потоку / очереди сообщений потока, который его создает - с этого момента он будет доставлять сообщения и исполняемые файлы в эту очередь сообщений и выполнять их по мере выхода из сообщения. очередь.

Решение:

  1. Создать HandlerThread

  2. Позвоните start() на HandlerThread

  3. Создайте Handler, получив Looper из HanlerThread

  4. Вставьте код, связанный с сетевой операцией, в Runnable объект

  5. Отправить Runnable задачу в Handler

Пример фрагмента кода, адрес которого 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);

Плюсы использования этого подхода:

  1. Создание нового Thread/AsyncTask для каждой сетевой операции стоит дорого. Thread/AsyncTask будет уничтожен и воссоздан для следующих сетевых операций. Но с подходом Handler и HandlerThread вы можете передать многие сетевые операции (как выполняемые задачи) одному HandlerThread с помощью Handler.
avatar
Hossain Ahamed
17 марта 2017 в 06:00
2

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

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

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

avatar
aks
2 марта 2017 в 16:16
2

Поскольку Android работает в одном потоке, вам не следует выполнять какие-либо сетевые операции в основном потоке. Есть несколько способов избежать этого.

Используйте следующий способ выполнения сетевой операции

  • Asysnctask : для небольших операций, которые не занимают много времени.
  • Intent Service : для сетевых операций, которые занимают много времени.
  • Используйте пользовательские библиотеки, такие как Volley и Retrofit для обработки сложные сетевые операции

Никогда не используйте StrictMode.setThreadPolicy (policy) , так как это заморозит ваш пользовательский интерфейс и это не очень хорошая идея.

avatar
Himanshu
19 февраля 2017 в 11:31
4

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

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

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

avatar
Mansuu....
16 января 2017 в 04:56
4

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();
}
avatar
Lovekush Vishwakarma
4 октября 2016 в 08:00
4

Как исправить ошибку android.os.NetworkOnMainThreadException

Что такое NetworkOnMainThreadException:

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

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

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

avatar
Alex Shutov
23 июня 2016 в 22:00
9

Есть еще один очень удобный способ решения этой проблемы - использовать возможности параллелизма 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 ().

Существует отличная электронная книга для RxJava.

avatar
bpr10
23 мая 2016 в 09:32
5

Мы также можем использовать 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/

Peter Mortensen
22 июля 2021 в 18:10
0

Вторая ссылка не работает (404).

bpr10
23 июля 2021 в 08:17
0

Спасибо, @PeterMortensen Обновил ссылку на статью.

avatar
BalaramNayak
19 января 2016 в 09:52
1

Исключение NetworkOnMainThread возникает из-за того, что вы вызвали некоторую сетевую операцию в потоке по умолчанию, то есть потоке пользовательского интерфейса. В соответствии с версией Android Android 3 (Honeycomb), что недопустимо, вы должны вызывать сетевую операцию вне основного потока.

Вы можете использовать AsyncTask, IntentService или создать собственный поток и вызвать его внутри метода run. Для получения дополнительной информации посетите Подключение к сети .

avatar
Adnan Abdollah Zaki
15 января 2016 в 16:47
5

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

Запустите свой код в 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
    }
}
avatar
Krishna
18 декабря 2015 в 09:23
6

Вам не разрешено реализовывать сетевые операции в потоке пользовательского интерфейса на 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. Это будет работать как шарм. :)

avatar
RobotCharlie
17 августа 2015 в 01:47
1

Фактически вы можете начать новый поток. У меня была эта проблема раньше, и я решил ее таким образом.

avatar
RevanthKrishnaKumar V.
13 августа 2015 в 08:26
7

Доступ к сетевым ресурсам из основного (UI) потока вызывает это исключение. Чтобы избежать этой проблемы, используйте отдельный поток или AsyncTask для доступа к сетевому ресурсу.

avatar
Nabin
22 июля 2015 в 02:05
16

Проще говоря,

Не выполнять сетевую работу в потоке пользовательского интерфейса

Например, если вы выполняете HTTP-запрос, это сетевое действие.

Решение:

  1. Вы должны создать новую тему
  2. Или используйте класс AsyncTask

Путь:

Поместите все свои работы в

  1. Метод run() нового потока
  2. Или метод doInBackground() класса AsyncTask.

Но:

Когда вы получаете что-то из сетевого ответа и хотите показать это в своем представлении (например, отобразить ответное сообщение в TextView), вам нужно вернуться обратно в поток UI .

Если вы этого не сделаете, вы получите ViewRootImpl$CalledFromWrongThreadException.

Практические инструкции

  1. При использовании AsyncTask обновите представление с помощью метода onPostExecute()
  2. Или вызовите метод runOnUiThread() и обновите представление внутри метода run().
avatar
Ponsuyambu
25 июня 2015 в 07:42
7

В Android сетевые операции не могут выполняться в основном потоке. Вы можете использовать Thread, AsyncTask (краткосрочные задачи), Service (длительные задачи) для выполнения сетевых операций.

avatar
prat3ik-patel
26 февраля 2015 в 05:44
-5

Вам нужно просто добавить следующую строку в файл manifest.xml после тега манифеста

<uses-permission android:name="android.permission.INTERNET"/>

В файле активности добавьте следующий код после оператора привязки:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
ci_
20 марта 2015 в 10:00
2

Обход обнаружения сетевого кода в потоке пользовательского интерфейса - действительно плохой совет, для начала есть причина, по которой он существует.

avatar
msysmilu
17 февраля 2015 в 10:31
10

Хотя выше имеется огромный пул решений, никто не упомянул com.koushikdutta.ion: https://github.com/koush/ion

Это также асинхронный и очень простой в использовании:

Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
   @Override
    public void onCompleted(Exception e, JsonObject result) {
        // do stuff with the result or error
    }
});
avatar
Kacy
13 февраля 2015 в 23:10
8

Это работает. Я просто сделал ответ доктора Луиджи немного проще.

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
avatar
Gurpreet singh
27 января 2015 в 09:56
-3

Используйте приведенный ниже код для выполнения тяжелых задач.

// Your package here


import java.util.List;
import org.apache.http.NameValuePair;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View.OnSystemUiVisibilityChangeListener;

public class AsyncRequest extends AsyncTask<String, Integer, String> {

    Context context;
    ProgressDialog pDialog;

    // Three Constructors
    public AsyncRequest(Activity a, String m, List<NameValuePair> p) {
        context = a;
        method = m;
        parameters = p;
    }

    public AsyncRequest(Activity a) {
        this.caller = (OnAsyncRequestComplete) a;
        context = a;
    }

    public String doInBackground(String... urls) {

        //Perform your task here
        return result;
    }

    public void onPreExecute() {
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Please wait..");
        pDialog.setCancelable(false);
        pDialog.show();
    }

    public void onProgressUpdate(Integer... progress) {
        // You can implement some progressBar and update it in this record.
        //   setProgressPercent(progress[0]);
    }

    public void onPostExecute(String response) {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
        // Get the result here
    }

    protected void onCancelled(String response) {

        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }
}
avatar
Subhalaxmi
21 декабря 2014 в 08:17
3

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

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

Или

используйте Service или AsyncTask для решения этой

Примечание:

Do not change SDK version
Do not use a separate thread

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

Ajay Pandya
9 декабря 2016 в 10:11
0

Для получения дополнительной ссылки не работает, можете ли вы опубликовать некоторые детали как ответ для понимания

avatar
Kumarsunil
12 декабря 2014 в 04:12
-5

Android не позволяет использовать отдельный процесс в основном потоке активности, и HTTP-соединение здесь является независимым потоком. По этой причине вы получаете исключение « android.os.NetworkOnMainThreadException ».

Может возникнуть необходимость проверить фактическое подключение к Интернету, прежде чем показывать веб-просмотр пользователю, потому что, если нет Интернета, веб-представление покажет пользователю ошибку страница не найдена , которые обычно не показываются.

Для проверки доступности Интернета можно использовать команду ping, но в случае Wi-Fi пинг может быть отключен на сервере Wi-Fi, поэтому в этом случае вы используете HTTP-соединение для проверки статуса запроса.

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

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

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
StrictMode.setThreadPolicy(policy);
avatar
Vaishali Sutariya
28 июля 2014 в 10:43
52

Введите свой код внутрь:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();

Или:

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
    }
}
avatar
amardeep
21 июля 2014 в 11:53
23

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

Чтобы избежать этого, мы можем справиться с этим с помощью потоков или исполнителей

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
avatar
Ashwin S Ashok
16 июля 2014 в 06:09
45

Ошибка связана с выполнением длительных операций в основном потоке. Вы можете легко исправить проблему, используя AsynTask или Thread. Вы можете проверить эту библиотеку AsyncHTTPClient для лучшей обработки.

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {

    @Override
    public void onStart() {
        // Called before a request is started
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response) {
        // Called when response HTTP status is "200 OK"
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
        // Called when response HTTP status is "4XX" (for example, 401, 403, 404)
    }

    @Override
    public void onRetry(int retryNo) {
        // Called when request is retried
    }
});
avatar
Novak
24 июня 2014 в 21:32
24

Просто чтобы что-то подробно изложить:

Основной поток - это в основном поток пользовательского интерфейса.

Таким образом, утверждение о том, что вы не можете выполнять сетевые операции в основном потоке, означает, что вы не можете выполнять сетевые операции в потоке пользовательского интерфейса, а это означает, что вы не можете выполнять сетевые операции в блоке *runOnUiThread(new Runnable() { ... }* внутри какого-либо другого потока, либо.

(Я долго ломал голову, пытаясь понять, почему я получаю эту ошибку где-то не в основном потоке. Вот почему; эта ветка помогла; и, надеюсь, этот комментарий поможет кому-то другому.)

avatar
Oleksiy
12 июня 2014 в 03:10
49

Использование Android-аннотаций - это вариант. Это позволит вам просто запустить любой метод в фоновом потоке:

// normal method
private void normal() {
    doSomething(); // do something in background
}

@Background
protected void doSomething() 
    // run your networking code here
}

Обратите внимание, что, хотя он обеспечивает преимущества простоты и удобочитаемости, он имеет свои недостатки.

Oleksiy
19 августа 2015 в 01:30
6

@Gavriel создает дубликаты всего, что вы аннотируете, будь то метод, действие, фрагмент, синглтон и т. Д., Поэтому кода вдвое больше, и его компиляция занимает больше времени. Также могут быть проблемы из-за ошибок в библиотеке. Отладка и поиск ошибок станут более трудными.

avatar
dhiraj kakran
1 марта 2014 в 13:43
26

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

    btnsub.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub

                    //Initialize soap request + add parameters
                    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME1);

                    //Use this to add parameters
                    request.addProperty("pincode", txtpincode.getText().toString());
                    request.addProperty("bg", bloodgroup.getSelectedItem().toString());

                    //Declare the version of the SOAP request
                    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

                    envelope.setOutputSoapObject(request);
                    envelope.dotNet = true;

                    try {
                        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

                        //this is the actual part that will call the webservice
                        androidHttpTransport.call(SOAP_ACTION1, envelope);

                        // Get the SoapResult from the envelope body.
                        SoapObject result = (SoapObject) envelope.getResponse();
                        Log.e("result data", "data" + result);
                        SoapObject root = (SoapObject) result.getProperty(0);
                        // SoapObject s_deals = (SoapObject) root.getProperty(0);
                        // SoapObject s_deals_1 = (SoapObject) s_deals.getProperty(0);
                        //

                        System.out.println("********Count : " + root.getPropertyCount());

                        value = new ArrayList<Detailinfo>();

                        for (int i = 0; i < root.getPropertyCount(); i++) {
                            SoapObject s_deals = (SoapObject) root.getProperty(i);
                            Detailinfo info = new Detailinfo();

                            info.setFirstName(s_deals.getProperty("Firstname").toString());
                            info.setLastName(s_deals.getProperty("Lastname").toString());
                            info.setDOB(s_deals.getProperty("DOB").toString());
                            info.setGender(s_deals.getProperty("Gender").toString());
                            info.setAddress(s_deals.getProperty("Address").toString());
                            info.setCity(s_deals.getProperty("City").toString());
                            info.setState(s_deals.getProperty("State").toString());
                            info.setPinecode(s_deals.getProperty("Pinecode").toString());
                            info.setMobile(s_deals.getProperty("Mobile").toString());
                            info.setEmail(s_deals.getProperty("Email").toString());
                            info.setBloodgroup(s_deals.getProperty("Bloodgroup").toString());
                            info.setAdddate(s_deals.getProperty("Adddate").toString());
                            info.setWaight(s_deals.getProperty("waight").toString());
                            value.add(info);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Intent intent = new Intent(getApplicationContext(), ComposeMail.class);
                    //intent.putParcelableArrayListExtra("valuesList", value);

                    startActivity(intent);
                }
            }).start();
        }
    });
avatar
perry
25 февраля 2014 в 06:23
32

Это вызывается только для приложений, нацеленных на Honeycomb SDK или выше. Приложениям, ориентированным на более ранние версии SDK, разрешено подключение к сети в своих основных потоках цикла событий.

Ошибка - это предупреждение SDK!

avatar
Stevie
22 января 2014 в 13:17
185

У принятого ответа есть несколько существенных недостатков. Не рекомендуется использовать AsyncTask для работы в сети, если вы действительно не знаете, что делаете. Вот некоторые из недостатков:

  • AsyncTask, созданные как нестатические внутренние классы, имеют неявную ссылку на включающий объект Activity, его контекст и всю иерархию View, созданную этим действием. Эта ссылка предотвращает сборку мусора Activity до завершения фоновой работы AsyncTask. Если соединение пользователя медленное и / или загрузка велика, эти краткосрочные утечки памяти могут стать проблемой - например, если ориентация меняется несколько раз (и вы не отменяете выполняемые задачи) или пользователь уходит от Activity.
  • AsyncTask имеет разные характеристики выполнения в зависимости от платформы, на которой он выполняется: до API уровня 4 AsyncTasks выполняются последовательно в одном фоновом потоке; от уровня API 4 до уровня API 10 AsyncTasks выполняются в пуле до 128 потоков; начиная с уровня API 11 и далее AsyncTask выполняется последовательно в одном фоновом потоке (если вы не используете перегруженный метод executeOnExecutor и не предоставляете альтернативный исполнитель). Код, который отлично работает при последовательном запуске в ICS, может сломаться при одновременном выполнении в Gingerbread, например, если у вас есть непреднамеренные зависимости порядка выполнения.

Если вы хотите избежать краткосрочных утечек памяти, иметь четко определенные характеристики выполнения на всех платформах и иметь основу для создания действительно надежной сетевой обработки, вы можете рассмотреть:

  1. Использование библиотеки, которая отлично справляется с этой задачей для вас - есть хорошее сравнение сетевых библиотек в этом вопросе или
  2. Использование вместо этого Service или IntentService, возможно, с PendingIntent для возврата результата через метод Activity onActivityResult.

подход IntentService

Минусы:

  • Больше кода и сложности, чем AsyncTask, но не так много, как вы думаете
  • Будет помещать запросы в очередь и запускать их в одиночном фоновом потоке. Вы можете легко контролировать это, заменив IntentService эквивалентной реализацией Service, например, этой.
  • Эм, я не могу сейчас вспомнить ни о каких других

Плюсы:

  • Устраняет проблему краткосрочной утечки памяти
  • Если ваша деятельность перезапускается во время выполнения сетевых операций, она все равно может получить результат загрузки с помощью своего onActivityResult метода
  • Лучшая платформа, чем AsyncTask, для создания и повторного использования надежного сетевого кода. Пример: если вам нужно выполнить важную загрузку, вы можете сделать это из AsyncTask в Activity, но если пользователь переключает контекст из приложения, чтобы принять телефонный звонок, система может убить приложение до завершения загрузки. менее вероятно убить приложение с активным Service.
  • Если вы используете свою собственную параллельную версию IntentService (например, ту, которую я связал выше), вы можете контролировать уровень параллелизма с помощью Executor.

Обзор реализации

Вы можете легко реализовать IntentService для выполнения загрузок в одном фоновом потоке.

Шаг 1. Создайте IntentService для выполнения загрузки. Вы можете указать ему, что загружать, с помощью Intent дополнений и передать ему PendingIntent, чтобы использовать его для возврата результата в Activity:

import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class DownloadIntentService extends IntentService {

    private static final String TAG = DownloadIntentService.class.getSimpleName();

    public static final String PENDING_RESULT_EXTRA = "pending_result";
    public static final String URL_EXTRA = "url";
    public static final String RSS_RESULT_EXTRA = "url";

    public static final int RESULT_CODE = 0;
    public static final int INVALID_URL_CODE = 1;
    public static final int ERROR_CODE = 2;

    private IllustrativeRSSParser parser;

    public DownloadIntentService() {
        super(TAG);

        // make one and reuse, in the case where more than one intent is queued
        parser = new IllustrativeRSSParser();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
        InputStream in = null;
        try {
            try {
                URL url = new URL(intent.getStringExtra(URL_EXTRA));
                IllustrativeRSS rss = parser.parse(in = url.openStream());

                Intent result = new Intent();
                result.putExtra(RSS_RESULT_EXTRA, rss);

                reply.send(this, RESULT_CODE, result);
            } catch (MalformedURLException exc) {
                reply.send(INVALID_URL_CODE);
            } catch (Exception exc) {
                // could do better by treating the different sax/xml exceptions individually
                reply.send(ERROR_CODE);
            }
        } catch (PendingIntent.CanceledException exc) {
            Log.i(TAG, "reply cancelled", exc);
        }
    }
}

Шаг 2. Зарегистрируйте службу в манифесте:

<service
        android:name=".DownloadIntentService"
        android:exported="false"/>

Шаг 3: вызовите службу из Activity, передав объект PendingResult, который служба будет использовать для возврата результата:

PendingIntent pendingResult = createPendingResult(
    RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);

Шаг 4. Обработка результата в onActivityResult:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
        switch (resultCode) {
            case DownloadIntentService.INVALID_URL_CODE:
                handleInvalidURL();
                break;
            case DownloadIntentService.ERROR_CODE:
                handleError(data);
                break;
            case DownloadIntentService.RESULT_CODE:
                handleRSS(data);
                break;
        }
        handleRSS(data);
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Проект GitHub, содержащий полностью работающий проект Android Studio / Gradle, доступен здесь.

avatar
Dhruv Jindal
14 января 2014 в 06:14
62

Сетевые операции не могут выполняться в основном потоке. Вам необходимо запустить все сетевые задачи в дочернем потоке или реализовать AsyncTask.

Вот как вы выполняете задачу в дочернем потоке:

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
Yousha Aleayoub
12 марта 2016 в 13:18
1

Anonymous Runnable - НЕ лучший способ, поскольку он имеет неявную ссылку на включающий класс и предотвращает его сборку мусора до завершения потока! Кроме того, этот поток будет работать с тем же приоритетом, что и основной поток / США, борясь с методами жизненного цикла и частотой кадров пользовательского интерфейса!

avatar
Kapil Vats
5 января 2014 в 18:28
44

Вы не должны выполнять какие-либо трудоемкие задачи в основном потоке (потоке пользовательского интерфейса), например любые сетевые операции, файловые операции ввода-вывода или операции с базой данных SQLite. Поэтому для такого рода операций вы должны создать рабочий поток, но проблема в том, что вы не можете напрямую выполнять какие-либо операции, связанные с пользовательским интерфейсом, из рабочего потока. Для этого вы должны использовать Handler и передать Message.

Чтобы упростить все это, Android предоставляет различные способы, например AsyncTask, AsyncTaskLoader, CursorLoader или IntentService. Таким образом, вы можете использовать любой из них в соответствии с вашими требованиями.

avatar
henry4343
24 декабря 2013 в 14:33
85

Выполните сетевые действия в другом потоке.

Например:

new Thread(new Runnable(){
    @Override
    public void run() {
        // Do network action in this function
    }
}).start();

И добавьте это в файл AndroidManifest.xml :

<uses-permission android:name="android.permission.INTERNET"/>
avatar
rharvey
17 сентября 2013 в 12:15
28

Для меня это было так:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="10" />

Устройство, на котором я тестировал свое приложение, было 4.1.2, то есть SDK версии 16!

Убедитесь, что целевая версия совпадает с версией вашей целевой библиотеки Android. Если вы не уверены, какая у вас целевая библиотека, щелкните правой кнопкой мыши свой проект -> Путь сборки -> Android , и он должен быть отмечен галочкой.

Также, как уже упоминалось другими, включите правильные разрешения для доступа в Интернет:

<uses-permission android:name="android.permission.INTERNET"/>
Selvin
17 сентября 2013 в 15:36
11

Позвольте мне объяснить вам, что вы здесь делаете: NetworkOnMainThreadException - это Страж, который говорит вам: не стреляйте себе в ногу ... ваше решение: давайте вернемся в прошлое, когда не было Стража - теперь я могу свободно стрелять мне в ногу

FractalBob
25 октября 2013 в 19:36
1

Я тоже применил этот подход, и у меня не было никаких проблем. Guardian иногда бывает слишком привередливым.

avatar
raihan ahmed
5 сентября 2013 в 08:16
50

Это происходит в Android 3.0 и выше. Начиная с Android 3.0 и выше, они ограничили использование сетевых операций (функций, имеющих доступ к Интернету) в основном потоке / потоке пользовательского интерфейса (то, что порождается вашими методами создания и возобновления в действии).

Это сделано для поощрения использования отдельных потоков для сетевых операций. См. AsyncTask для получения дополнительных сведений о том, как правильно выполнять сетевые действия.

avatar
venergiac
18 августа 2013 в 09:18
81
  1. Не использовать strictMode (только в режиме отладки)
  2. Не изменять версию SDK
  3. Не используйте отдельную резьбу

Используйте службу или AsyncTask

См. Также вопрос о переполнении стека:

android.os.NetworkOnMainThreadException отправка сообщения электронной почты от Android

Stevie
22 января 2014 в 08:33
8

Возможно, стоит подчеркнуть, что если вы используете службу, вам все равно нужно будет создать отдельный поток - обратные вызовы службы выполняются в основном потоке. IntentService, с другой стороны, запускает свой метод onHandleIntent в фоновом потоке.

Dage
4 февраля 2014 в 10:41
0

вы не должны использовать AsyncTask для длительных операций! В инструкциях указано максимум 2–3 секунды.

avatar
sivag1
18 июля 2013 в 18:52
43

Верхний ответ спектома работает отлично.

Если вы пишете AsyncTask встроенным и не расширяете как класс, и, кроме того, если есть необходимость получить ответ из AsyncTask, можно использовать метод get() как ниже.

RSSFeed feed = new RetreiveFeedTask().execute(urlToRssFeed).get();

(Из его примера.)

avatar
Dr.Luiji
21 января 2013 в 16:31
483

Я решил эту проблему, используя новый Thread.

Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
        try  {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});

thread.start(); 
user_MGU
8 апреля 2021 в 09:04
0

Просто и гениально !!!

Haisi
3 июня 2021 в 07:42
0

Как бы вы передали ему параметры?

Donald Duck
9 августа 2021 в 10:43
0

Если вам нужно получить доступ к пользовательскому интерфейсу после запроса, вам нужно вернуться к основному потоку в конце, как описано здесь.

avatar
Dipak Keshariya
30 октября 2012 в 10:06
126

Есть два решения этой проблемы.

  1. Не используйте сетевой вызов в основном потоке пользовательского интерфейса. Для этого используйте асинхронную задачу.

  2. Запишите приведенный ниже код в файл MainActivity после setContentView (R.layout.activity_main); :

    if (android.os.Build.VERSION.SDK_INT> 9) { Политика StrictMode.ThreadPolicy = новый StrictMode.ThreadPolicy.Builder (). AllowAll (). Build (); StrictMode.setThreadPolicy (политика); }

И приведенный ниже оператор импорта в ваш файл Java.

import android.os.StrictMode;
Richi González
28 мая 2013 в 07:47
11

Следование второму решению - плохая практика. Асинхронный режим - это способ сделать это правильно . Вы как бы скрываете свою проблему, если меняете политику!

avatar
Piyush-Ask Any Difference
24 октября 2012 в 07:10
73

Вы отключаете строгий режим, используя следующий код:

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = 
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

Это не рекомендуется. : используйте интерфейс AsyncTask.

Полный код для обоих методов

Muhammad Mubashir
6 мая 2013 в 11:23
2

Да, возникнет ошибка ANR. означает, что приложение не отвечает в течение 5 секунд.

shkschneider
29 августа 2013 в 15:01
13

Это действительно плохой ответ. Вы не должны изменять политику потока, но лучше писать код: не выполняйте сетевые операции в основном потоке!

Prakhar1001
15 сентября 2016 в 14:06
0

@Sandeep Вы и другие зрители тоже должны это прочитать. coderhelper.com/a/18335031/3470479

avatar
user1169115
15 февраля 2012 в 06:59
736

Вы должны почти всегда выполнять сетевые операции в потоке или как асинхронную задачу.

Но можно удалить это ограничение, и вы переопределите поведение по умолчанию, если готовы принять последствия.

Добавить:

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

StrictMode.setThreadPolicy(policy);

В вашем классе,

и

Добавьте это разрешение в файл Android manifest.xml :

<uses-permission android:name="android.permission.INTERNET"/>

Последствия:

Ваше приложение (в областях с нестабильным подключением к Интернету) перестанет отвечать и заблокируется, пользователь почувствует медлительность и должен выполнить принудительное уничтожение, и вы рискуете, что диспетчер активности убьет ваше приложение и сообщит пользователю, что приложение остановлено. .

В Android есть несколько полезных советов по правильному программированию для разработки с учетом отзывчивости: NetworkOnMainThreadException | Разработчики Android

MosesK
3 июня 2021 в 09:30
0

Вау, спасибо за это объяснение, которое я теперь понимаю. Я видел приложение, и оно реализовало эту ThreadPolicy в своих java-классах. Я был немного запутан тем, что он делал. Когда сеть была низкой, я видел Последствия, о которых вы говорите.

avatar
Mark Allison
14 июня 2011 в 12:07
150

Невозможно выполнить сетевой ввод-вывод в потоке пользовательского интерфейса на Honeycomb. Технически это возможно в более ранних версиях Android, но это действительно плохая идея, поскольку это приведет к тому, что ваше приложение перестанет отвечать, и может привести к тому, что ОС убьет ваше приложение из-за плохого поведения. Вам нужно будет запустить фоновый процесс или использовать AsyncTask для выполнения сетевой транзакции в фоновом потоке.

На сайте разработчиков Android есть статья о Безболезненной потоковой передаче, которая является хорошим введением в этот вопрос и предоставит вам гораздо более подробный ответ, чем это может быть реально представлено здесь.

>