it-swarm.com.ru

Как я могу исправить Android.os.NetworkOnMainThreadException?

Я получил ошибку при запуске моего проекта 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

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

2137
bejoy george

Это исключение выдается, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Запустите ваш код в 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"/>
2367
michael

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

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

Добавлять:

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

StrictMode.setThreadPolicy(policy); 

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

а также

ДОБАВЬТЕ это разрешение в файл Android manifest.xml:

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

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

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

У Android есть несколько полезных советов по хорошим методам программирования для быстрого реагирования: http://developer.Android.com/reference/Android/os/NetworkOnMainThreadException.html

604
user1169115

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
381
Dr.Luiji

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

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

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

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

IntentService подход

Down-сторона:

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

Up-сторон:

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

137
Stevie

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

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

135
Mark Allison
  1. Не используйте строгий режим (только в режиме отладки)
  2. Не меняйте версию SDK
  3. Не используйте отдельный поток

Использовать сервис или AsyncTask

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

Android.os.NetworkOnMainThreadException отправка электронного письма с Android

67
venergiac

Делать сетевые действия в другом потоке

Например:

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

И добавьте это в AndroidManifest.xml 

<uses-permission Android:name="Android.permission.INTERNET"/>
61
henry4343

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

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

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

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

52
Sandeep

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

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

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

Поместите ваш код внутри:

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
    }
}
43
Vaishali Sutariya

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

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

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

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

40
Oleksiy

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

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

39
raihan ahmed

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

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

35
Kapil Vats

Ошибка связана с выполнением длительных операций в главном потоке. Вы можете легко устранить проблему, используя 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
    }
});
34
Ashwin S Ashok

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

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

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

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

34
sivag1

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

Ошибка является предупреждением SDK!

28
perry

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

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

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

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

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

<uses-permission Android:name="Android.permission.INTERNET"/>
23
rharvey

Просто, чтобы объяснить что-то явно:

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

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

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

21
Novak

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

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

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
19
amardeep

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

    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();
        }
    });
15
dhiraj kakran

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

НЕ ИСПОЛЬЗУЙТЕ СЕТЬ В РЕЗЬБЕ UI

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

Решение:

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

Путь:

Положите все свои работы внутри

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

Но:

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

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

Как?

  1. При использовании AsyncTask обновите представление из метода onPostExecute()
  2. Или вызов runOnUiThread() метод и представление обновления внутри метода run().
14
Nabin

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

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

ReST через HTTP

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

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

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

http://api.example.com/stocks                       //ResponseWrapper<String> object containing a list of Srings 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)

Дооснащение от площади

Это отличный выбор для API с несколькими конечными точками и позволяет объявлять конечные точки ReST вместо того, чтобы кодировать их по отдельности, как в других библиотеках, таких как ion или Volley. (веб-сайт: http://square.github.io/retrofit/ )

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

build.gradle

Добавьте эти строки на уровень вашего модуля buid.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 snippet

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

Если вашему API требуется отправить ключ API или другой заголовок, например, токен пользователя и т.д., Retrofit сделает это легко (подробности см. В этом удивительном ответе: https://stackoverflow.com/a/42899766/ 1024412 ).

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

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

Ион

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

Пожалуйста, прочитайте отличный ответ msysmilu ( https://stackoverflow.com/a/28559884/1024412 )

Загрузка изображений через HTTP

Залп

Volley также можно использовать для API ReST, но из-за более сложной настройки я предпочитаю использовать Retrofit from Square, как указано выше ( http://square.github.io/retrofit/ )

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

build.gradle

Добавьте эту строку на уровень вашего модуля buid.gradle:

implementation 'com.Android.volley:volley:1.0.0'

ImageFetch.Java

Залп требует больше настроек, чем модификация. Вам нужно будет создать такой класс, чтобы настроить 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 (Fragment, Activity) или конструктор (Dialog):

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

Пикассо

Еще одна отличная библиотека с площади. Пожалуйста, посмотрите на сайт несколько замечательных примеров: http://square.github.io/picasso/

12
KG6ZVP

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

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

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

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

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

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

HandlerThread

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

Обработчик:

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

Решение:

  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
8
Ravindra babu

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

7
RevanthKrishnaKumar V.

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

7
Ponsuyambu Velladurai

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

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

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() вызывался в потоке пользовательского интерфейса.

7
Shinoo Goyal

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

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

Java Thread или Android HandlerThread

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

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

AsyncTask

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

Реализация пула потоков ThreadPoolExecutor , ScheduledThreadPoolExecutor ...

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

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

FutureTask

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

AsyncTaskLoaders

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

IntentService

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

JobScheduler

По сути, вам нужно создать Службу и создать задание, используя JobInfo.Builder, в котором указаны ваши критерии, когда следует запускать Службу.

RxJava

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

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

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

Узнайте больше здесь:
8 способов сделать асинхронную обработку в Android и считать
Эволюция доступа к сети Android
Использование пула потоков в Android

6
yoAlex5

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

6
Krishna

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

Вы можете использовать KOTLIN и ANKO

Kotlin - это новый официальный язык для Android подробнее об этом вы можете узнать здесь https://kotlinlang.org/docs/tutorials/kotlin-Android.html

Anko поддерживает библиотеку для Kotlin в Android, некоторые документы здесь https://github.com/Kotlin/anko

Решение, которое действительно полезно и имеет всего несколько строк кода, написанного @AntonioLeiva https://antonioleiva.com/anko-background-kotlin-Android/

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

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

5
J.D.1731

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

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

Или же

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

Замечания:

Do not change SDK version
Do not use a separate thread

Для более, проверьте это .

4
Subhalaxmi Nayak

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

Запустите ваш код в 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
    }
}
4
Adnan Abdollah Zaki

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

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

3
bpr10

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

Заставить сделать задачу в главном потоке вот так

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

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

3
Anonymous

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

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

Но лучшей практикой будет использование AsyncTask.

3
Himanshu

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

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

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

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

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

3
Lovekush Vishwakarma

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

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

1
BalaramNayak

Сделайте это в фоновом потоке, используя AsycTask

Джава

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)
1
Vipul Prajapati

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

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

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

1
Hossain Ahamed

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

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

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

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

1
aks

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

1
rObOtAndChalie

Котлин версия

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)
0
Sazzad Hissain Khan

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

 class YoutActivity : AppCompatActivity, CoroutineScope {

      override fun onCreate(...) {
         launch {  yourHeavyMethod() }
      }

      suspend fun yourHeavyMethod() {
         async{ yourNetworkCall() }.await()
         ...
         ...
      }

 } 

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

0
Santanu Sur

С 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) 
    }
0
Elye

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

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

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

0
Ashok Kumar

Никогда не выполняйте длительную работу в потоке пользовательского интерфейса, этой длительной работой может быть взаимодействие с сервером, чтение/запись в файл и т.д. Эти задачи должны выполняться в фоновом потоке, поэтому создаются 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

Существует так много о https://developer.Android.com/reference/Android/os/StrictMode.html

0
Rahul

Если вы работаете в kotlin и anko, вы можете добавить 

 doAsync {
   method()
}
0
Devix