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

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

2086
задан 14 июня '11 в 15:02
источник поделиться
51 ответ
  • 1
  • 2

Это исключение возникает, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Запустите свой код в 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"/>
2320
ответ дан 14 июня '11 в 15:15
источник

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

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

Добавить

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

587
ответ дан 15 февр. '12 в 9:59
источник

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
373
ответ дан 21 янв. '13 в 19:31
источник

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

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

132
ответ дан 14 июня '11 в 15:07
источник

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

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

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

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

Подход IntentService

Вниз стороны:

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

Up-сторон:

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

Резюме реализации

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

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

132
ответ дан 22 янв. '14 в 16:17
источник
  • Не используйте strictMode (только в режиме отладки)
  • Не изменяйте версию SDK
  • Не используйте отдельный поток

Использовать службу или AsyncTask

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

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

64
ответ дан 18 авг. '13 в 12:18
источник

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

Пример:

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

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

<uses-permission android:name="android.permission.INTERNET"/>
57
ответ дан 24 дек. '13 в 17:33
источник

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

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

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

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

50
ответ дан 24 окт. '12 в 10:10
источник

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

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

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
44
ответ дан 14 янв. '14 в 9:14
источник

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

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
    }
}
41
ответ дан 28 июля '14 в 13:43
источник

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

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

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

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

39
ответ дан 12 июня '14 в 6:10
источник

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

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

38
ответ дан 05 сент. '13 в 11:16
источник

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

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

34
ответ дан 05 янв. '14 в 21:28
источник

Верхний ответ spektom работает идеально.

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

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

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

33
ответ дан 18 июля '13 в 21:52
источник

Ошибка связана с выполнением длительных операций в основном потоке. Вы можете легко устранить проблему, используя 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
    }
});
33
ответ дан 16 июля '14 в 9:09
источник

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

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

27
ответ дан 25 февр. '14 в 9:23
источник

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

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

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

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

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

<uses-permission android:name="android.permission.INTERNET"/>
23
ответ дан 17 сент. '13 в 15:15
источник

Просто для того, чтобы четко сказать что-то:

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

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

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

21
ответ дан 25 июня '14 в 0:32
источник

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

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

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
19
ответ дан 21 июля '14 в 14:53
источник

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

    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
ответ дан 01 марта '14 в 16:43
источник

Говоря простыми словами,

НЕ ДЕЛАЙТЕ СЕТЕВЫЕ РАБОТЫ В РЕЖИМЕ UI

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

Решение:

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

Путь:

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

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

Но:

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

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

Как?

  1. При использовании AsyncTask обновите представление из onPostExecute()
  2. Или вызовите runOnUiThread() и обновите представление внутри метода run().
14
ответ дан 22 июля '15 в 5:05
источник

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

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

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

Фундамент Фрагмент

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 делает это проще (подробнее см. Этот удивительный ответ: qaru.site/questions/23057/...).

Один доступ к API-интерфейсу ReST

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

ион

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

Пожалуйста, прочитайте msysmilu отличный ответ (qaru.site/questions/206/...)

Загружать изображения через 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

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

public class ImageFetch {
    private static ImageLoader imageLoader = null;
    private static RequestQueue imageQueue = null;

    public static ImageLoader getImageLoader(Context ctx){
        if(imageLoader == null){
            if(imageQueue == null){
                imageQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            imageLoader = new ImageLoader(imageQueue, new ImageLoader.ImageCache() {
                Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }
                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }
        return imageLoader;
    }
}

user_view_dialog.xml

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

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/profile_picture"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    app:srcCompat="@android:drawable/spinner_background"/>

UserViewDialog.java

Добавьте следующий код в метод onCreate (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
ответ дан 21 окт. '17 в 2:50
источник

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

Он также асинхронный и очень простой:

Ion.with(context)
.load("http://example.com/thing.json")
.asJsonObject()
.setCallback(new FutureCallback<JsonObject>() {
   @Override
    public void onCompleted(Exception e, JsonObject result) {
        // do stuff with the result or error
    }
});
10
ответ дан 17 февр. '15 в 13:31
источник

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

7
ответ дан 13 авг. '15 в 11:26
источник

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

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
7
ответ дан 14 февр. '15 в 2:10
источник

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);
    }
});
  • Определив (Schedulers.io()), RxAndroid будет запускать getFavoriteMusicShows() в другом потоке.

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

7
ответ дан 09 июня '17 в 8:57
источник

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

7
ответ дан 25 июня '15 в 10:42
источник

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

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

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

HandlerThread

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

Handler:

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

Решение:

  • Создать HandlerThread

  • Вызов start() on HandlerThread

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

  • Вставьте код, связанный с вашей сетью, в Runnable object

  • Отправьте задачу 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);

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

  • Создание нового Thread/AsyncTask для каждой сетевой операции дорого. Thread/AsyncTask будет уничтожен и воссоздан для следующих сетевых операций. Но с подходом Handler и HandlerThread вы можете отправить множество сетевых операций (как выполняемых задач) на один HandlerThread с помощью Handler.
7
ответ дан 05 мая '17 в 23:11
источник

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

Пример. Предположим, вы хотите загрузить изображение с 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
ответ дан 18 дек. '15 в 12:23
источник

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

Первый проверенный ответ - использование 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
ответ дан 24 июня '16 в 1:00
источник
  • 1
  • 2

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