Как исправить ошибку 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

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


person bejoy george    schedule 14.06.2011    source источник
comment
Чтобы быть в курсе, сначала прочтите о сетевых запросах в Android, а затем я бы порекомендовал изучить Volley.   -  person Anuj Sharma    schedule 23.01.2014
comment
Вам нужно запускать интернет-действия в потоке, отдельном от основного (UI) потока.   -  person Naveed Ahmad    schedule 30.10.2014
comment
Из-за ошибки в предыдущих версиях Android система не помечала запись в сокет TCP в основном потоке как нарушение строгого режима. Android 7.0 исправляет эту ошибку. Приложения, демонстрирующие такое поведение, теперь выдают исключение android.os.NetworkOnMainThreadException. - Значит, некоторые из нас до недавнего времени не добивались этого! developer.android.com/about/versions/nougat/   -  person Jay    schedule 20.11.2017


Ответы (64)


ПРИМЕЧАНИЕ. 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"/>
person Michael Spector    schedule 14.06.2011
comment
Таким образом, выполнение сетевых операций в основном потоке проблематично только в Android, а не в стандартном Java-коде (код написан на Java, но не для приложения Android). ?? - person y_159; 14.06.2021
comment
Таким образом, выполнение сетевых операций в основном потоке проблематично только в Android, а не в стандартном Java-коде (код написан на Java, но не для приложения Android). ?? - person y_159; 14.06.2021

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

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

Добавлять:

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

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

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
person Dr.Luiji    schedule 21.01.2013
comment
Просто и гениально !!! - person user_MGU; 08.04.2021
comment
Как бы вы передали этому параматеры? - person Haisi; 03.06.2021

У принятого ответа есть существенные недостатки. Не рекомендуется использовать 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, чтобы вернуть результат через метод onActivityResult Activity.

IntentService approach

Минусы:

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

Плюсы:

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

Implementation summary

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

Шаг 1. Создайте IntentService для выполнения загрузки. Вы можете указать ему, что загружать, с помощью Intent extras, и передать ему 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, доступен здесь.

person Stevie    schedule 22.01.2014

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

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

person Mark Allison    schedule 14.06.2011

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

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

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

    если (android.os.Build.VERSION.SDK_INT ›9) {StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder (). allowAll (). build (); StrictMode.setThreadPolicy (политика); }

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

import android.os.StrictMode;
person Dipak Keshariya    schedule 30.10.2012
comment
Следование второму решению - плохая практика. Асинхронный режим - это способ сделать это правильно. Вы как бы скрываете свою проблему, если меняете политику! - person Richi González; 28.05.2013

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

Например:

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

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

<uses-permission android:name="android.permission.INTERNET"/>
person henry4343    schedule 24.12.2013

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

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

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

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

person venergiac    schedule 18.08.2013
comment
Возможно, стоит подчеркнуть, что если вы используете службу, вам все равно нужно будет создать отдельный поток - обратные вызовы службы выполняются в основном потоке. IntentService, с другой стороны, запускает свой метод onHandleIntent в фоновом потоке. - person Stevie; 22.01.2014
comment
вы не должны использовать AsyncTask для длительных операций! В инструкциях указано максимум 2–3 секунды. - person Dage; 04.02.2014

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

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

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

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

person Piyush-Ask Any Difference    schedule 24.10.2012
comment
Да, возникнет ошибка ANR. означает, что приложение не отвечает в течение 5 секунд. - person Muhammad Mubashir; 06.05.2013
comment
Это действительно плохой ответ. Вы не должны изменять политику потока, но лучше писать код: не выполняйте сетевые операции в основном потоке! - person shkschneider; 29.08.2013
comment
@Sandeep Вы и другие зрители тоже должны это прочитать. stackoverflow.com/a/18335031/3470479 - person Prakhar1001; 15.09.2016

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

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

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
person Dhruv Jindal    schedule 14.01.2014
comment
Anonymous Runnable - НЕ лучший способ, поскольку он имеет неявную ссылку на включающий класс и предотвращает его сборку мусора до завершения потока! Кроме того, этот поток будет работать с тем же приоритетом, что и основной поток / США, борясь с методами жизненного цикла и частотой кадров пользовательского интерфейса! - person Yousha Aleayoub; 12.03.2016

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

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

Or:

class DemoTask extends AsyncTask<Void, Void, Void> {

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

    protected void onPostExecute(Void result) {
        // TODO: do something with the feed
    }
}
person Vaishali Sutariya    schedule 28.07.2014

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

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

person raihan ahmed    schedule 05.09.2013

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

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

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

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

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

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

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

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

person Kapil Vats    schedule 05.01.2014

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

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

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

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

person sivag1    schedule 18.07.2013

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

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

person perry    schedule 25.02.2014

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

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

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

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

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

<uses-permission android:name="android.permission.INTERNET"/>
person rharvey    schedule 17.09.2013
comment
Позвольте мне объяснить вам, что вы здесь делаете: NetworkOnMainThreadException Страж, который говорит вам: не стреляйте себе в ногу ... ваше решение: давайте вернемся в прошлое, когда не было Стража - теперь я могу стрелять в моя нога свободно - person Selvin; 17.09.2013
comment
Я тоже использовал этот подход, и у меня не было никаких проблем. Иногда Guardian бывает слишком привередливым. - person FractalBob; 25.10.2013

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

    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();
        }
    });
person dhiraj kakran    schedule 01.03.2014

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

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

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

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

person Novak    schedule 24.06.2014

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

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

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

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

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

REST over HTTP

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

Full API Access

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

Retrofit from Square

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

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

File build.gradle

Добавьте эти строки в файл module level 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

File FinancesApi.java

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

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

Class FinancesApiBuilder

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

Class FinancesFragment snippet

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

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

One-off REST API access

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

Ion

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

Прочтите отличный ответ msysmilu на Как исправить 'android.os.NetworkOnMainThreadException'?.

Load images via HTTP

Volley

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

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

File build.gradle

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

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

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

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

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

Picasso

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

person KG6ZVP    schedule 20.10.2017


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

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

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

JobScheduler

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

RxJava

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

Coroutines (Kotlin)

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

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

person yoAlex5    schedule 17.03.2018

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

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

Взгляните на альтернативное решение, используя HandlerThread и Обработчик

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.
person Ravindra babu    schedule 05.05.2017


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

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

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

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

Runnable runnable;
Handler newHandler;

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

И чтобы остановить использование потока:

newHandler.removeCallbacks(runnable);

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

person Sharath kumar    schedule 04.09.2017

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

person Shinoo Goyal    schedule 09.06.2017

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

person Alex Shutov    schedule 23.06.2016

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

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

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

person Ponsuyambu    schedule 25.06.2015

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

person RevanthKrishnaKumar V.    schedule 13.08.2015

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

person J.D.1731    schedule 10.07.2017
comment
Со страницы GitHub: Anko устарел. Дополнительную информацию см. На этой странице. - person Peter Mortensen; 22.07.2021

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

person Krishna    schedule 18.12.2015

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

Or

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);
}
person Rahul    schedule 11.02.2020

Котлин

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

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}
person El Sushiboi    schedule 14.08.2020

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

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

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

Что такое NetworkOnMainThreadException:

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

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

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

person Lovekush Vishwakarma    schedule 04.10.2016

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

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

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

person Himanshu    schedule 19.02.2017

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

    new AsyncTask<Void,String,String>(){

        @Override
        protected Void doInBackground(Void... params) {
            // Perform your network operation.
            // Get JSON or XML string from the server.
            // Store in a local variable (say response) and return.
            return response;
        }

        protected void onPostExecute(String results){
            // Response returned by doInBackGround() will be received
            // by onPostExecute(String results).
            // Now manipulate your jason/xml String(results).
        }

    }.execute();
}
person Mansuu....    schedule 16.01.2017

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

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

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

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

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

person Richard Kamere    schedule 18.08.2019
comment
@RichardKamere из официальной документации для StrictMode, вы можете проверить, что «StrictMode - это инструмент разработчика, который обнаруживает вещи, которые вы могли сделать случайно, и обращает на них ваше внимание, чтобы вы могли их исправить» и «никогда не оставляйте StrictMode включенным в распространяемых приложениях. в Google Play ». Проверить здесь - person Shubham Suryawanshi; 13.09.2019
comment
Это поможет в целях тестирования, но не может рассматриваться как решение, используйте вместо этого асинхронную задачу. - person Jorgesys; 29.10.2019
comment
@Zun, а что, если я хочу не проверять интернет-соединение на сервере API? - person shareef; 10.03.2020

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

https://stablekernel.com/article/replace-asynctask-and-asynctaskloader-with-rx-observable-rxjava-android-patterns/

person bpr10    schedule 23.05.2016
comment
Вторая ссылка не работает (404). - person Peter Mortensen; 22.07.2021
comment
Спасибо, @PeterMortensen Обновил ссылку на статью. - person bpr10; 23.07.2021

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

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

Or

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

Примечание:

Do not change SDK version
Do not use a separate thread

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

person Subhalaxmi    schedule 21.12.2014
comment
Для получения дополнительной ссылки не работает, можете ли вы опубликовать некоторые подробности как ответ для понимания - person Ajay Pandya; 09.12.2016

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

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

person majurageerthan    schedule 01.01.2020

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

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

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

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

person aks    schedule 02.03.2017

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

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

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

person Hossain Ahamed    schedule 17.03.2017

Если вы работаете в Kotlin и Anko, вы можете добавить:

doAsync {
    method()
}
person Devix    schedule 10.12.2018
comment
Анко устарел - person EpicPandaForce; 31.12.2019
comment

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

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

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

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

person Santanu Sur    schedule 01.03.2019

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

Например, вы можете найти примеры использования задач в пример API Google Диска. То же самое следует использовать и в этом случае. Я буду использовать исходный код 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.

person Oleg Gryb    schedule 14.03.2020

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

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

*https://stackoverflow.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.

person Shay Ribera    schedule 15.10.2020

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

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

person BalaramNayak    schedule 19.01.2016

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

person RobotCharlie    schedule 17.08.2015

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();
person Sunny Gupta    schedule 21.02.2021

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


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

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

...
Globalscope.async{
  ...
  result = isInternetReachable()
  ...
}
...
person nyxee    schedule 04.04.2021

Android Jetpack представлен _ 1_, что устраняет проблему ограничения фоновой службы в Android 8.1 (Oreo) и использование диспетчера аварийных сигналов ниже Android 5.0 (Lollipop) и JobScheduler выше Lolipop.

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

person Jinesh Francis    schedule 06.11.2019
comment
Есть только один фоновый поток или их несколько (в данном контексте)? - person Peter Mortensen; 22.07.2021

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

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)
person Sazzad Hissain Khan    schedule 01.06.2019

Вот простое решение с использованием 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();
person neu242    schedule 25.01.2021
comment
Получение ошибки: System.err: java.util.concurrent.ExecutionException: javax.net.ssl.SSLException: невозможно проанализировать заголовок пакета TLS - person Arpan Saini; 06.02.2021
comment
@ArpanSaini Работает ли ваш точный URL с помощью curl или в браузере? Может быть, переключиться с https на http (или наоборот) и посмотреть, работает ли? - person neu242; 08.02.2021

С 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) 
    }
person Elye    schedule 17.01.2018
comment
Вы можете найти полный код на странице github.com/elye/demo_android_network_evolution. - person Elye; 18.01.2018
comment
Если вы хотите взглянуть на общую тенденцию доступа к сети в Android с исторической точки зрения, ознакомьтесь с medium.com/@elye.project/ - person Elye; 18.01.2018

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

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

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

person Ashok Kumar    schedule 10.05.2018

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

person Rahul    schedule 01.08.2017

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

// 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();
        }
    }
}
person Gurpreet singh    schedule 27.01.2015

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);
person Kumarsunil    schedule 12.12.2014

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

<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);
}
person prat3ik-patel    schedule 26.02.2015
comment
Обход обнаружения сетевого кода в потоке пользовательского интерфейса - действительно плохой совет, для начала есть причина, по которой он существует. - person ci_; 20.03.2015