'android.os.NetworkOnMainThreadException'を修正する方法は?

Jun 14 2011

RssReader用のAndroidプロジェクトの実行中にエラーが発生しました。

コード:

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

この問題を修正するにはどうすればよいですか?

回答

2598 MichaelSpector Jun 14 2011 at 19:15

注:AsyncTaskはAPIレベル30で非推奨になりました。
https://developer.android.com/reference/android/os/AsyncTask

この例外は、アプリケーションがメインスレッドでネットワーク操作を実行しようとしたときにスローされます。でコードを実行します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"/>
708 user1169115 Feb 15 2012 at 13:59

ほとんどの場合、ネットワーク操作はスレッド上で、または非同期タスクとして実行する必要があります。

ただし、結果を受け入れる意思がある場合は、この制限を削除して、デフォルトの動作をオーバーライドすることできます。

追加:

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

443 Dr.Luiji Jan 21 2013 at 23:31

新しいを使用してこの問題を解決しましたThread

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
178 Stevie Jan 22 2014 at 20:17

受け入れられた回答には、いくつかの重大な欠点があります。自分が何をしているかを本当に理解していない限り、ネットワークにAsyncTaskを使用することはお勧めできません。いくつかの欠点は次のとおりです。

  • 非静的内部クラスとして作成されたAsyncTaskには、それを囲むActivityオブジェクト、そのコンテキスト、およびそのアクティビティによって作成されたビュー階層全体への暗黙の参照があります。この参照は、AsyncTaskのバックグラウンド作業が完了するまで、アクティビティがガベージコレクションされるのを防ぎます。ユーザーの接続が遅い場合やダウンロードが大きい場合、これらの短期メモリリークが問題になる可能性があります。たとえば、向きが数回変わる場合(および実行中のタスクをキャンセルしない場合)、またはユーザーアクティビティから移動します。
  • AsyncTaskには、実行するプラットフォームに応じて異なる実行特性があります。APIレベル4より前では、AsyncTaskは単一のバックグラウンドスレッドでシリアルに実行されます。APIレベル4からAPIレベル10まで、AsyncTasksは最大128スレッドのプールで実行されます。APIレベル11以降、AsyncTaskは単一のバックグラウンドスレッドでシリアルに実行されます(オーバーロードされたexecuteOnExecutorメソッドを使用して代替エグゼキューターを指定しない限り)。ICSでシリアルに実行するときに正常に機能するコードは、Gingerbreadで同時に実行すると破損する可能性があります。たとえば、不注意な実行順序の依存関係がある場合などです。

短期的なメモリリークを回避し、すべてのプラットフォームで明確に定義された実行特性を持ち、非常に堅牢なネットワーク処理を構築するための基盤が必要な場合は、次のことを検討してください。

  1. あなたのためにこれの素晴らしい仕事をするライブラリを使用する-この質問のネットワークライブラリの素晴らしい比較があります、または
  2. ServiceまたはのIntentService代わりに、またはを使用しPendingIntentて、アクティビティのonActivityResultメソッドを介して結果を返します。

IntentServiceアプローチ

欠点:

  • AsyncTask思ったほどではありませんが、コードと複雑さは
  • リクエストをキューに入れ、単一のバックグラウンドスレッドで実行します。おそらくこのようなIntentService同等のService実装に置き換えることで、これを簡単に制御できます。
  • ええと、私は今実際に他の人のことを考えることができません

利点:

  • 短期記憶リークの問題を回避します
  • ネットワーク操作の実行中にアクティビティが再開された場合でも、そのonActivityResult方法でダウンロードの結果を受け取ることができます。
  • 堅牢なネットワークコードを構築して再利用するには、AsyncTaskよりも優れたプラットフォームです。例:あなたは、重要なアップロードを行う必要がある場合、あなたはからそれを行うことAsyncTaskActivityはなく、ユーザーの電話を取るためにAPPのうちコンテキストが-切り替えた場合、システムがあり、アップロードが完了する前にアプリを殺します。がアクティブなアプリケーションを強制終了する可能性低くなります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);
}

完全に機能するAndroid-Studio / Gradleプロジェクトを含むGithubプロジェクトはこちらから入手できます。

147 MarkAllison Jun 14 2011 at 19:07

HoneycombのUIスレッドでネットワークI / Oを実行することはできません。技術的に、以前のバージョンのAndroidでも可能ですが、アプリの応答が停止し、OSがアプリの動作が悪いためにアプリを強制終了する可能性があるため、これは非常に悪い考えです。バックグラウンドプロセスを実行するか、AsyncTaskを使用してバックグラウンドスレッドでネットワークトランザクションを実行する必要があります。

Android開発者サイトにPainlessThreadingに関する記事があります。これは、これについての優れた入門書であり、ここで実際に提供できるよりもはるかに深い答えを提供します。

83 henry4343 Dec 24 2013 at 21:33

別のスレッドでネットワークアクションを実行する

例えば:

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

そしてこれをAndroidManifest.xmlに追加します

<uses-permission android:name="android.permission.INTERNET"/>
79 venergiac Aug 18 2013 at 16:18
  1. strictModeを使用しないでください(デバッグモードでのみ)
  2. SDKのバージョンを変更しないでください
  3. 別のスレッドを使用しないでください

ServiceまたはAsyncTaskを使用する

StackOverflowの質問も参照してください。

android.os.NetworkOnMainThreadExceptionAndroidからメールを送信する

71 Piyush-AskAnyDifference Oct 24 2012 at 14:10

次のコードを使用して、厳密モードを無効にします。

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

これはお勧めしませんAsyncTaskインターフェースを使用してください。

両方の方法の完全なコード

58 DhruvJindal Jan 14 2014 at 13:14

ネットワークベースの操作は、メインスレッドでは実行できません。すべてのネットワークベースのタスクを子スレッドで実行するか、AsyncTaskを実装する必要があります。

これは、子スレッドでタスクを実行する方法です。

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
51 VaishaliSutariya Jul 28 2014 at 17:43

コードを中に入れます:

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
    }
}
49 raihanahmed Sep 05 2013 at 15:16

これはAndroid3.0以降で発生します。Android 3.0以降では、ネットワーク操作(インターネットにアクセスする関数)の使用がメインスレッド/ UIスレッド(アクティビティの作成時および再開時のメソッドから生成されるもの)での実行が制限されています。

これは、ネットワーク操作に個別のスレッドを使用することを推奨するためです。ネットワークアクティビティを正しい方法で実行する方法の詳細については、AsyncTaskを参照してください。

48 Oleksiy Jun 12 2014 at 10:10

Androidアノテーションの使用はオプションです。これにより、バックグラウンドスレッドで任意のメソッドを簡単に実行できます。

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

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

シンプルさと読みやすさの利点はありますが、欠点があることに注意してください。

44 AshwinSAshok Jul 16 2014 at 13:09

このエラーは、メインスレッドで長時間実行されている操作を実行していることが原因です。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
    }
});
43 KapilVats Jan 06 2014 at 01:28

ネットワーク操作、ファイルI / O、SQLiteデータベース操作など、メインスレッド(UIスレッド)で時間のかかるタスクを実行しないでください。したがって、この種の操作では、ワーカースレッドを作成する必要がありますが、問題は、ワーカースレッドからUI関連の操作を直接実行できないことです。そのためには、を使用Handlerして渡す必要がありMessageます。

これらすべてのものを簡素化するために、Androidはのような、さまざまな方法を提供しAsyncTaskAsyncTaskLoaderCursorLoaderまたはIntentService。したがって、要件に応じてこれらのいずれかを使用できます。

42 sivag1 Jul 19 2013 at 01:52

spektomのトップアンサーは完璧に機能します。

AsyncTaskインラインを記述していて、クラスとして拡張していない場合、さらにAsyncTask、から応答を取得する必要がある場合は、get()次のメソッドを使用できます。

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

(彼の例から。)

32 perry Feb 25 2014 at 13:23

これは、HoneycombSDK以降を対象とするアプリケーションに対してのみスローされます。以前のSDKバージョンを対象とするアプリケーションは、メインイベントループスレッドでネットワーキングを行うことができます。

エラーはSDKの警告です!

28 rharvey Sep 17 2013 at 19:15

私にとってそれはこれでした:

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

私がアプリをテストしていたデバイスは、SDKバージョン16である4.1.2でした!

ターゲットバージョンがAndroidターゲットライブラリと同じであることを確認してください。ターゲットライブラリが何かわからない場合は、プロジェクト->ビルドパス-> Androidを右クリックすると、チェックマークが付いているはずです。

また、他の人が言及しているように、インターネットにアクセスするための正しいアクセス許可を含めます。

<uses-permission android:name="android.permission.INTERNET"/>
25 dhirajkakran Mar 01 2014 at 20:43

あなたの活動でこれを使用してください

    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();
        }
    });
23 Novak Jun 25 2014 at 04:32

何かを明確に綴るだけです:

メインスレッドは基本的にUIスレッドです。

つまり、メインスレッドでネットワーク操作を実行できないということは、UIスレッドでネットワーク操作を実行できないこと*runOnUiThread(new Runnable() { ... }*を意味します。つまり、他のスレッド内ブロックでもネットワーク操作を実行できません

(メインスレッド以外の場所でエラーが発生した理由を理解しようとして、頭を悩ませる長い瞬間がありました。これが理由です。このスレッドが役に立ちました。このコメントが他の誰かに役立つことを願っています。)

22 amardeep Jul 21 2014 at 18:53

この例外は、実行タスクに時間がかかりすぎる場合にメインスレッドで実行される重いタスクが原因で発生します。

これを回避するために、スレッドまたは実行者を使用して処理できます

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
19 KG6ZVP Oct 21 2017 at 06:50

この質問にはすでに多くの素晴らしい答えがありますが、それらの答えが投稿されて以来、多くの素晴らしい図書館が出てきました。これは一種の初心者ガイドとして意図されています。

ネットワーク操作を実行するためのいくつかのユースケースとそれぞれに1つか2つのソリューションについて説明します。

HTTPを介したReST

通常、JsonはXMLまたはその他のものにすることができます

フルAPIアクセス

ユーザーが株価、金利、為替レートを追跡できるアプリを作成しているとします。次のようなJsonAPIが見つかります。

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などの他のライブラリのように個別にコーディングする代わりに、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スニペット

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

1回限りのReSTAPIアクセス

ユーザーのGPS位置を検索し、そのエリアの現在の気温をチェックして気分を伝える「気分天気」アプリを作成しているとします。このタイプのアプリは、APIエンドポイントを宣言する必要はありません。1つのAPIエンドポイントにアクセスできる必要があります。

イオン

これは、このタイプのアクセスに最適なライブラリです。

msysmiluの素晴らしい答えを読んでください(https://stackoverflow.com/a/28559884/1024412)

HTTP経由で画像を読み込む

ボレー

VolleyはReSTAPIにも使用できますが、セットアップがより複雑になるため、上記のようにSquareのRetrofitを使用することをお勧めします(http://square.github.io/retrofit/)

ソーシャルネットワーキングアプリを作成していて、友達のプロフィール写真を読み込みたいとします。

build.gradle

次の行をモジュールレベルのbuid.gradleに追加します。

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

ImageFetch.java

ボレーはレトロフィットよりも多くのセットアップが必要です。RequestQueue、ImageLoader、およびImageCacheをセットアップするには、次のようなクラスを作成する必要がありますが、それほど悪くはありません。

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

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

user_view_dialog.xml

画像を追加するには、レイアウトxmlファイルに以下を追加します。

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

UserViewDialog.java

次のコードをonCreateメソッド(Fragment、Activity)またはコンストラクター(Dialog)に追加します。

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

ピカソ

Squareのもう1つの優れたライブラリ。いくつかの素晴らしい例については、サイトを参照してください。http://square.github.io/picasso/

16 Nabin Jul 22 2015 at 09:05

簡単に言えば、

UIスレッドでネットワーク作業を行わないでください

たとえば、HTTPリクエストを実行する場合、それはネットワークアクションです。

解決:

  1. 新しいスレッドを作成する必要があります
  2. または、AsyncTaskクラスを使用します

仕方:

すべての作品を中に入れてください

  1. run() 新しいスレッドの方法
  2. または doInBackground()AsyncTaskクラスのメソッド。

だが:

ネットワーク応答から何かを取得し、それをビューに表示したい場合(TextViewでの応答メッセージの表示など)、UIスレッドに戻る必要があります。

あなたがそれをしなければ、あなたは得るでしょうViewRootImpl$CalledFromWrongThreadException

方法?

  1. AsyncTaskの使用中に、onPostExecute()メソッドからビューを更新します
  2. または、runOnUiThread()メソッドを呼び出して、run()メソッド内のビューを更新します。
12 yoAlex5 Mar 17 2018 at 22:58

あなたはオフロードするために別のスレッドにあなたのコードの一部を移動することができるmain threadと避けるANR、NetworkOnMainThreadException、IllegalStateExceptionが(例えば缶、それは潜在的に長時間のUIをロックする可能性があるため、メインスレッドではないアクセスデータベース)。

状況に応じて選択する必要があるいくつかのアプローチがあります

JavaスレッドまたはAndroidHandlerThread

Javaスレッドは1回限りの使用であり、runメソッドの実行後に終了します。

HandlerThreadは、ルーパーを持つ新しいスレッドを開始するための便利なクラスです。

AsyncTask

AsyncTaskは、スレッドハンドラーの周りのヘルパークラスになるように設計されており、一般的なスレッドフレームワークを構成しません。AsyncTasksは、理想的には短い操作(最大で数秒)に使用する必要があります。スレッドを長期間実行し続ける必要がある場合は、java.util.concurrentパッケージによって提供されるさまざまなAPIを使用することを強くお勧めします。ExecutorThreadPoolExecutorおよびFutureTask

メインスレッドはUIコンポーネントを独占しているため、一部のビューにアクセスすることはできません。そのため、ハンドラーが助けになっています。

スレッドプールの実装ThreadPoolExecutor、ScheduledThreadPoolExecutor .. ..

スレッドプールを細かく制御するExecutorServiceを実装するThreadPoolExecutorクラス(コアプールサイズ、最大プールサイズ、キープアライブ時間など)

ScheduledThreadPoolExecutor-ThreadPoolExecutorを拡張するクラス。所定の遅延後または定期的にタスクをスケジュールできます。

FutureTask

FutureTaskは非同期処理を実行しますが、結果の準備ができていないか、処理が完了していない場合、get()を呼び出すとスレッドがブロックされます

AsyncTaskLoaders

AsyncTaskLoadersは、AsyncTaskに固有の多くの問題を解決します。

IntentService

これは、Androidで長時間実行される処理の事実上の選択です。良い例は、大きなファイルをアップロードまたはダウンロードすることです。ユーザーがアプリを終了しても、アップロードとダウンロードが続行される場合があります。これらのタスクの実行中にユーザーがアプリを使用できないようにする必要はありません。

JobScheduler

事実上、サービスを作成し、いつサービスを実行するかの基準を指定するJobInfo.Builderを使用してジョブを作成する必要があります。

RxJava

監視可能なシーケンスを使用して非同期およびイベントベースのプログラムを作成するためのライブラリ。

コルーチン(Kotlin)

その主な要点は、非同期コードを同期のように見せることです

続きを読むここ、ここ、ここ、ここ

11 Ravindrababu May 06 2017 at 03:11

新しいソリューションThreadとAsyncTaskソリューションについてはすでに説明しました。

AsyncTask理想的には短い操作に使用する必要があります。通常ThreadはAndroidには適していません。

HandlerThreadとHandlerを使用した代替ソリューションをご覧ください

HandlerThread

ルーパーを持つ新しいスレッドを開始するための便利なクラス。その後、ルーパーを使用してハンドラークラスを作成できます。start()まだ呼び出す必要があることに注意してください。

ハンドラ:

ハンドラーを使用すると、スレッドのMessageQueueに関連付けられたMessageオブジェクトとRunnableオブジェクトを送信および処理できます。各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アプローチ、あなたは、単一の(Runnableをタスクなど)の多くのネットワーク操作を提出することができますHandlerThread使用してHandler
10 msysmilu Feb 17 2015 at 17:31

上記には巨大なソリューションプールがありますが、誰も言及していません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 AlexShutov Jun 24 2016 at 05:00

この問題に取り組むための別の非常に便利な方法があります-rxJavaの並行性機能を使用します。バックグラウンドで任意のタスクを実行し、非常に便利な方法で結果をメインスレッドに投稿できるため、これらの結果は処理チェーンに渡されます。

最初に検証された回答のアドバイスは、AsynTaskを使用することです。はい、これは解決策ですが、新しいツールが出回っているため、最近では廃止されています。

String getUrl() {
    return "SomeUrl";
}

private Object makeCallParseResponse(String url) {
    return null;
    //
}

private void processResponse(Object o) {

}

getUrlメソッドはURLアドレスを提供し、メインスレッドで実行されます。

makeCallParseResponse(..)-実際の作業を行います

processResponse(..)-メインスレッドで結果を処理します。

非同期実行のコードは次のようになります。

rx.Observable.defer(new Func0<rx.Observable<String>>() {
    @Override
    public rx.Observable<String> call() {
        return rx.Observable.just(getUrl());
    }
})
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.io())
    .map(new Func1<String, Object>() {
        @Override
        public Object call(final String s) {
            return makeCallParseResponse(s);
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
             processResponse(o);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            // Process error here, it will be posted on
            // the main thread
        }
    });

AsyncTaskと比較すると、このメソッドでは、スケジューラーを任意の回数切り替えることができます(たとえば、あるスケジューラーでデータをフェッチし、別のスケジューラーでそれらのデータを処理します(たとえば、Scheduler.computation())。独自のスケジューラーを定義することもできます。

このライブラリを使用するには、build.gradleファイルに次の行を含めます。

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

最後の依存関係には、.mainThread()スケジューラーのサポートが含まれます。

rx-java用の優れた電子ブックがあります。

9 ShinooGoyal Jun 09 2017 at 12:57

RxAndroidはこの問題のもう1つの優れた代替手段であり、スレッドを作成して結果をAndroidUIスレッドに投稿する手間を省きます。タスクを実行する必要があるスレッドを指定するだけで、すべてが内部で処理されます。

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スレッドでこのObservableを監視する必要があります。つまり、UIスレッドでonNext()コールバックを呼び出す必要があります。

9 Sharathkumar Sep 04 2017 at 17:43

メインスレッドはUIスレッドであり、ユーザーの操作をブロックする可能性のある操作をメインスレッドで実行することはできません。これは2つの方法で解決できます。

このようにメインスレッドでタスクを実行するように強制します

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

または、単純なハンドラーを作成し、必要に応じてメインスレッドを更新します。

Runnable runnable;
Handler newHandler;

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

そして、スレッドの使用を停止するには:

newHandler.removeCallbacks(runnable);

詳細については、これをチェックしてください:痛みのないスレッド

8 Kacy Feb 14 2015 at 06:10

これは機能します。ルイジ博士の答えをもう少し簡単にしました。

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
7 PonsuyambuVelladurai Jun 25 2015 at 14:42

Androidでは、ネットワーク操作をメインスレッドで実行することはできません。Thread、AsyncTask(短時間実行タスク)、Service(長時間実行タスク)を使用して、ネットワーク操作を実行できます。