Android Studio: Загрузить изображение в облачный [дубликат]

Вы отправляете JSON, как это

$.ajax(url, {
    data : JSON.stringify(myJSObject),
    contentType : 'application/json',
    type : 'POST',
    ...

, если вы передаете объект как settings.data jQuery будет преобразовывать его в параметры запроса и по умолчанию отправлять с помощью приложения типа данных / x-www-form- urlencoded; charset = UTF-8, возможно, не то, что вы хотите

2007
задан Ali Esa Assadi 3 February 2018 в 15:49
поделиться

22 ответа

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

new RetrieveFeedTask().execute(urlToRssFeed);

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

<uses-permission android:name="android.permission.INTERNET"/>
2242
ответ дан Vova Stelmashchuk 15 August 2018 в 18:40
поделиться
  • 1
    Я думаю, здесь стоит отметить, что фрагмент кода выше должен быть подклассом (внутренний класс), предпочтительно частным. Таким образом, когда AsyncTask заканчивается, вы все равно можете манипулировать внутренностями вашего класса. – dyslexicanaboko 22 July 2012 в 06:57
  • 2
    На самом деле я сделал то же самое, что и u, упомянутое выше, но m сталкивается с этой ошибкой java.lang.RuntimeException: не удается создать обработчик внутри потока, который не вызвал Looper.prepare () – Dhruv Tyagi 30 August 2016 в 11:08
  • 3
    Это точно неправильный ответ. Я все время сталкиваюсь с этим в коде людей, и его раздражает, чтобы постоянно исправлять его. AsyncTask не следует использовать для сетевой активности, поскольку он привязан к активности, но не к жизненному циклу активности. Поворот устройства при выполнении этой задачи приведет к сбою и сбою вашего приложения. Используйте IntentService, который вместо этого удаляет данные в базе данных sqlite. – Brill Pappin 9 September 2016 в 19:08
  • 4
    Предупреждение. AsyncTask часто используется для операций сетевой активности, когда этого не должно быть. его жизненный цикл не синхронизируется с деятельностью. Для получения данных вы должны использовать IntentService и базу данных за представлением. – Brill Pappin 5 October 2016 в 21:24
  • 5
    Я настоятельно рекомендую загрузчики AsyncTask для таких случаев. – Roman Gherta 20 September 2017 в 16:51
  • 6
    – Shivam Pokhriyal 5 September 2018 в 05:26

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

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

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

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

46
ответ дан adamse 15 August 2018 в 18:40
поделиться
  • 1
    Да, будет ошибка ANR. означает, что приложение не отвечает за 5 сек. – Muhammad Mubashir 6 May 2013 в 12:23
  • 2
    Это очень плохой ответ. Вы не должны изменять политику потока, но лучше писать код: не делайте сетевые операции в основном потоке! – shkschneider 29 August 2013 в 16:01
  • 3
    Не хорошо, но полезно для POC / Debugging – hB0 5 November 2013 в 17:26
  • 4
    @Sandeep Вы и другие зрители тоже должны это прочитать. stackoverflow.com/a/18335031/3470479 – Prakhar1001 15 September 2016 в 14:06

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

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

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

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

Решение:

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

Путь:

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

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

Но:

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

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

Как?

  1. При использовании AsyncTask, просмотр обновления из метода onPostExecute()
  2. Или вызовите метод runOnUiThread() и обновите внутри метода run().
118
ответ дан Community 15 August 2018 в 18:40
поделиться
  • 1
    использование get() - плохая идея ... это делает AsyncTask & sync & quot; еще раз – Selvin 17 September 2013 в 16:29
  • 2
    Есть ли другой выход из этого? @Selvin – sivag1 20 September 2013 в 21:50
  • 3
    Возможно, стоит подчеркнуть, что если вы используете Сервис, вам все равно нужно создать отдельный поток - обратные вызовы службы выполняются в основном потоке. С другой стороны, IntentService запускает свой метод onHandleIntent в фоновом потоке. – Stevie 22 January 2014 в 10:33
  • 4
    вы не должны использовать AsyncTask для длительных операций! Рекомендации указывают от 2 до 3 секунд макс. – Dage 4 February 2014 в 12:41
  • 5
    Я думаю, вы можете узнать основную тему о результатах. Например, отправьте широковещание в основной поток, включая результат. – Chine Gary 10 February 2015 в 03:35
  • 6
    IntentService - это правильный способ сделать это, а не выкорчевывать, потому что AsyncTask - это именно то, что не нужно делать. – Brill Pappin 10 September 2016 в 14:59
  • 7
    @BrillPappin Я почти полностью согласен и переформулировал, чтобы подчеркнуть недостатки AsyncTask. (Я все еще думаю, что существует небольшое число очень малых , где - если вы действительно знаете, что делаете, - <<>> можно использовать AsyncTask, но принятый ответ «Не указывайте на какие-либо недостатки и слишком популярны для Android». – Stevie 13 March 2017 в 13:56
  • 8
    Вам действительно нужно IllustrativeRSS? Что делать, если вы не работаете с материалами RSS? – Cullub 14 April 2018 в 19:13
  • 9
    Ты спас свой день. благодаря – Piseth Sok 7 August 2018 в 01:36
    **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();
        }
    });
13
ответ дан dhiraj kakran 15 August 2018 в 18:40
поделиться

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

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

Добавить:

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

StrictMode.setThreadPolicy(policy); 

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

и

ДОБАВЛЯЕТ это разрешение в android Файл manifest.xml:

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

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

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

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

558
ответ дан EpicPandaForce 15 August 2018 в 18:40
поделиться
  • 1
    Это очень плохая идея. решение состоит в том, чтобы избежать сетевого ввода-вывода в основном потоке (как показывает принятый ответ). – MByD 14 May 2012 в 15:10
  • 2
    С этим вы только скрываете свою реальную проблему. – Alex 18 June 2012 в 07:44
  • 3
    @TwistedUmbrella AsyncTask не добавляет страницу кода, она добавляет 6 строк (объявление класса, аннотирование переопределения, объявление doInBackground, 2 закрывающие скобки и вызов execute()). С другой стороны, даже один выбор из сайта, как вы упоминаете, приводит к значительному отставанию в пользовательском интерфейсе. Не ленитесь. – Zoltán 4 September 2012 в 10:39
  • 4
    @TwistedUmbrella Не будь глупым. Вот как делаются плохие приложения. Будь то загрузка текстового файла или галереи изображений, вы должны следовать лучшим практикам. И запуск сетевого ввода-вывода в основном потоке не является лучшей практикой. – States 1 November 2012 в 03:23
  • 5
    Upvoted. Этот ответ правильный, и для многих программистов, которые не являются ни наивными, ни глупыми, но для которых просто требуется СИНХРОННЫЙ (т. Е. Этот должен заблокировать приложение ), это именно то, что нужно. Я более чем счастлив, что Android выбрал исключение по умолчанию (IMHO это очень «полезная» вещь!), Но я также рад сказать «спасибо», но - это на самом деле то, что я намеревался », и переопределить его. – Adam 1 May 2013 в 07:48

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

Пример:

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

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

<uses-permission android:name="android.permission.INTERNET"/>
51
ответ дан jose920405 15 August 2018 в 18:40
поделиться
  • 1
    Но как мы можем узнать, когда поток заканчивается в этом, чтобы мы могли выполнить следующий набор задач в потоке пользовательского интерфейса? AsyncTask предоставляет возможность для этого. Есть ли способ сделать то же самое с использованием runnable threads? – Piyush Soni 5 January 2014 в 01:30
  • 2
    Он будет обрабатывать ваш код шаг за шагом, поэтому в конце кода закончится, вам нужно использовать обработчик обратно в поток пользовательского интерфейса – henry4343 5 January 2014 в 04:18
  • 3
    [Д0] mobileorchard.com/… – henry4343 6 January 2014 в 02:50
  • 4
    Вы можете использовать службу асинхронной задачи или намерения, потому что она выполняется в рабочем потоке. – Chetan Chaudhari 19 April 2017 в 20:05

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

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
6
ответ дан Kacy 15 August 2018 в 18:40
поделиться

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

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

ReST over 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)

Retrofit from Square

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

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

build.gradle

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

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

FinancesApi.java

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

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

FinancesApiBuilder

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

FinancesFragment snippet

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

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

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

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

Ion

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

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

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

Волейбол

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

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

build.gradle

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

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

ImageFetch.java

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

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

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

user_view_dialog.xml

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

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

UserViewDialog.java

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

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

Picasso

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

10
ответ дан kiamlaluno 15 August 2018 в 18:40
поделиться
  • 1
    это должен быть лучший ответ, чем оригинальный, поскольку он упрощает реализацию сетей на Android в современном мире 2017 года, и большинство приложений реального мира используют очень хорошие библиотеки, подобные этим. – Rakibul Haq 28 November 2017 в 12:46

Хотя выше есть огромный пул решений, никто не упомянул 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
    }
});
9
ответ дан msysmilu 15 August 2018 в 18:40
поделиться

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

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

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

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

19
ответ дан Novak 15 August 2018 в 18:40
поделиться

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

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

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

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

36
ответ дан Oleksiy 15 August 2018 в 18:40
поделиться
  • 1
    каковы недостатки? – Gavriel 15 August 2015 в 20:00
  • 2
    @Gavriel создает дубликаты всего, что вы комментируете, будь то метод, активность, фрагмент, singleton и т. Д., Поэтому кода в два раза больше, и для его компиляции требуется больше времени. Также могут возникнуть некоторые проблемы из-за ошибок в библиотеке. Отладка и поиск ошибок станут более сложными. – Oleksiy 19 August 2015 в 01:30

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

Существует отличная книга g0 для rx-java .

124
ответ дан Peter Mortensen 15 August 2018 в 18:40
поделиться
  • 1
    Позвольте мне объяснить вам, что вы здесь делаете: NetworkOnMainThreadException - Хранитель, который говорит вам: не стреляйте в свою собственную ногу ... ваше решение: вернемся к прошлому, когда не было Хранителя - теперь я могу стрелять в мою ногу свободно – Selvin 17 September 2013 в 16:36
  • 2
    Я тоже принял этот подход и не испытывал никаких проблем. Иногда Хранитель слишком суетлив. – FractalBob 25 October 2013 в 20:36
  • 3
    Второй вариант лучше первого для api выше 11 – Rohit Goswami 28 July 2014 в 11:52
  • 4
    Анонимный Runnable - это не лучший способ, так как он имеет неявную ссылку на класс-оболочку и не позволяет ему быть GC ed до тех пор, пока поток не завершится! Также этот поток будет работать с тем же приоритетом, что и основной / US-поток, борющийся с методами жизненного цикла и частотой кадров пользовательского интерфейса! – Yousha Aleayoub 12 March 2016 в 14:18
  • 5
    прочитайте комментарий в разделе: stackoverflow.com/a/21107128/1429432 – Yousha Aleayoub 12 March 2016 в 14:19
  • 6
    довольно обширный подход, который он должен был запланировать самостоятельно, и я не знаю, почему мы должны, если он уже является вариантом на стороне Android? – Prakhar1001 15 September 2016 в 14:10
  • 7
    Async Работает в большинстве случаев – Ajay Pandya 9 December 2016 в 11:15

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

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

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

HandlerThread

Handy класс для запуска нового потока, который имеет петлитель. Затем петлитель можно использовать для создания классов обработчиков. Обратите внимание, что еще нужно вызвать 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.
6
ответ дан Ravindra babu 15 August 2018 в 18:40
поделиться

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
348
ответ дан V-rund Puro-hit 15 August 2018 в 18:40
поделиться
  • 1
    Вместо создания нового потока каждый раз, когда вы хотите выполнить сетевую операцию, вы также можете использовать службу одного потока. – Alex Lockwood 27 January 2013 в 20:06
  • 2
    Простой, но опасный. Анонимный Runnable имеет неявную ссылку на охватывающий класс (например, ваш Activity или Fragment), предотвращая его сбор мусора до тех пор, пока поток не завершится. Вы должны, по крайней мере, установить приоритет для Process.BACKGROUND, иначе этот поток будет работать с тем же приоритетом, что и поток main / ui, борющийся с методами жизненного цикла и частотой кадров ui (следите за предупреждениями в журнале от хореографа). – Stevie 19 June 2014 в 13:39
  • 3
    @Stevie, как установить приоритет? ни runnble, ни исполнительный сервис не имеют такого метода setter – J. K. 31 May 2015 в 13:26
  • 4
    @ J.K. Поставьте свой ExecutorService с помощью пользовательского ThreadFactory и вызовите Thread.setPriority в потоке перед его возвратом. – Stevie 1 June 2015 в 19:14
  • 5
    Установление приоритета для чего-то, что предназначено для выполнения сетевого вызова (который будет блокироваться), кажется излишним. – john16384 27 January 2016 в 14:09

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

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

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

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

118
ответ дан Community 15 August 2018 в 18:40
поделиться
  • 1
    использование get() - плохая идея ... это делает AsyncTask & sync & quot; еще раз – Selvin 17 September 2013 в 16:29
  • 2
    Есть ли другой выход из этого? @Selvin – sivag1 20 September 2013 в 21:50
  • 3
    Возможно, стоит подчеркнуть, что если вы используете Сервис, вам все равно нужно создать отдельный поток - обратные вызовы службы выполняются в основном потоке. С другой стороны, IntentService запускает свой метод onHandleIntent в фоновом потоке. – Stevie 22 January 2014 в 10:33
  • 4
    вы не должны использовать AsyncTask для длительных операций! Рекомендации указывают от 2 до 3 секунд макс. – Dage 4 February 2014 в 12:41
  • 5
    Я думаю, вы можете узнать основную тему о результатах. Например, отправьте широковещание в основной поток, включая результат. – Chine Gary 10 February 2015 в 03:35
  • 6
    IntentService - это правильный способ сделать это, а не выкорчевывать, потому что AsyncTask - это именно то, что не нужно делать. – Brill Pappin 10 September 2016 в 14:59
  • 7
    @BrillPappin Я почти полностью согласен и переформулировал, чтобы подчеркнуть недостатки AsyncTask. (Я все еще думаю, что существует небольшое число очень малых , где - если вы действительно знаете, что делаете, - <<>> можно использовать AsyncTask, но принятый ответ «Не указывайте на какие-либо недостатки и слишком популярны для Android». – Stevie 13 March 2017 в 13:56
  • 8
    Вам действительно нужно IllustrativeRSS? Что делать, если вы не работаете с материалами RSS? – Cullub 14 April 2018 в 19:13

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

124
ответ дан Peter Mortensen 15 August 2018 в 18:40
поделиться
  • 1
    Позвольте мне объяснить вам, что вы здесь делаете: NetworkOnMainThreadException - Хранитель, который говорит вам: не стреляйте в свою собственную ногу ... ваше решение: вернемся к прошлому, когда не было Хранителя - теперь я могу стрелять в мою ногу свободно – Selvin 17 September 2013 в 16:36
  • 2
    Я тоже принял этот подход и не испытывал никаких проблем. Иногда Хранитель слишком суетлив. – FractalBob 25 October 2013 в 20:36
  • 3
    Второй вариант лучше первого для api выше 11 – Rohit Goswami 28 July 2014 в 11:52
  • 4
    Анонимный Runnable - это не лучший способ, так как он имеет неявную ссылку на класс-оболочку и не позволяет ему быть GC ed до тех пор, пока поток не завершится! Также этот поток будет работать с тем же приоритетом, что и основной / US-поток, борющийся с методами жизненного цикла и частотой кадров пользовательского интерфейса! – Yousha Aleayoub 12 March 2016 в 14:18
  • 5
    прочитайте комментарий в разделе: stackoverflow.com/a/21107128/1429432 – Yousha Aleayoub 12 March 2016 в 14:19
  • 6
    Async Работает в большинстве случаев – Ajay Pandya 9 December 2016 в 11:15

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 в потоке UI, т. е. хотим, чтобы наш обратный вызов onNext() вызывался в потоке пользовательского интерфейса
6
ответ дан Ravindra babu 15 August 2018 в 18:40
поделиться
121
ответ дан Community 5 September 2018 в 17:51
поделиться
126
ответ дан Peter Mortensen 5 September 2018 в 17:51
поделиться
121
ответ дан Community 5 September 2018 в 17:52
поделиться
126
ответ дан Peter Mortensen 5 September 2018 в 17:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: