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

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

30 ответов


это исключение возникает, когда приложение пытается выполнить сетевую операцию в своем основном потоке. Запустите код в 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);

Не забудьте добавить это :

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

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

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

добавить:

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

StrictMode.setThreadPolicy(policy); 

в классе

и

добавьте это разрешение в манифест android.xml-файл:

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

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

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

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


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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 

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

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


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

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

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

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

IntentService подходи!--44-->

вниз-стороны:

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

вверх-стороны:

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

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

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

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

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

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

public class DownloadIntentService extends IntentService {

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

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

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

    private IllustrativeRSSParser parser;

    public DownloadIntentService() {
        super(TAG);

        // make one and 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: вызовите службу из действия, передав объект 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 здесь.


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

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

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

android.ОС.NetworkOnMainThreadException отправка электронной почты с Android


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

Например:

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

и добавьте это в AndroidManifest.в XML

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

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

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

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

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


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

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

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

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

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

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

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

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

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


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

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


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

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


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

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

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

(на его примере.)


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

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

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


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

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

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

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

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

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

просто, чтобы четко сформулировать что-то:

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

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

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


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

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

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

    **Use like this in Your Activity**

    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 inten=new Intent(getApplicationContext(),ComposeMail.class);
            //intent.putParcelableArrayListExtra("valuesList", value);

            startActivity(inten);



                }
            }).start();
        }
    });

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

НЕ ВЫПОЛНЯЙТЕ СЕТЕВУЮ РАБОТУ В ПОТОКЕ ПОЛЬЗОВАТЕЛЬСКОГО ИНТЕРФЕЙСА

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

устранение:

  1. вы должны создать новый поток
  2. или использовать класс AsyncTask

путь:

положите все ваши работы внутрь

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

но:

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

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

как?

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

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

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

отдых через HTTP

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

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

давайте вы пишете приложение, которое позволяет пользователям отслеживать цены на акции, процентные ставки и currecy курсов. Вы найдете API Json, который выглядит примерно так:
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 с несколькими конечными точками и позволяет объявлять остальные конечные точки вместо того, чтобы кодировать их индивидуально, как с другими библиотеками, такими как ion или Volley. (вебсайт: http://square.github.io/retrofit/)

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

построить.Gradle в

добавьте эти строки в buid уровня модуля.Gradle в:

implementation 'com.squareup.retrofit2:retrofit:2.3.0' //retrofit library, current as of September 21, 2017
implementation 'com.squareup.retrofit2:converter-gson:2.3.0' //gson serialization and deserialization support for retrofit, version must match retrofit version

FinancesApi.java

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

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

FinancesApiBuilder

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

фрагмент фрагмента FinancesFragment

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

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

One off ReST API access

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

Иона

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

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

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

волейбол

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

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

построить.Gradle в

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

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

ImageFetch.java

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

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

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

user_view_dialog.в XML

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

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

UserViewDialog.java

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

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

Пикассо

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


хотя выше есть огромный пул решений, никто не упомянул 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
    }
});

это работает. Только что сделал доктор Luiji ответ немного проще.

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

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


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


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


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

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

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

HandlerThread

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

обработчик:

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

устранение:

  1. создать HandlerThread

  2. вызов start() on 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 для каждой сетевой операции является дорогостоящим. The Thread/AsyncTask будет уничтожен и воссоздан для следующих сетевых операций. Но с Handler и HandlerThread подход, вы можете отправить много сетевых операций (как выполняемые задачи) в один HandlerThread С помощью Handler.

вам не разрешено выполнять сетевые операции в UI-потоке на Android. Вам придется использовать класс AsyncTask для выполнения сетевых операций, таких как отправка запроса API, загрузка изображения с URL-адреса и т. д. и используя методы обратного вызова AsyncTask, вы можете получить результат в onPostExecute 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. Это сработает как заклинание. :)


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

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

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

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

здесь отличная Электронная книга для rx-java.