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

2467
bejoy george 2011-06-15 02:02.

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

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

30 answers

2598
Michael Spector 2011-06-15 02: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 2012-02-15 20: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 2013-01-22 06: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 2014-01-23 03: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
Mark Allison 2011-06-15 02:07.

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

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

83
henry4343 2013-12-25 04: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 2013-08-18 23:18.
  1. strictModeを使用しないでください(デバッグモードでのみ)
  2. SDKのバージョンを変更しないでください
  3. 別のスレッドを使用しないでください

ServiceまたはAsyncTaskを使用する

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

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

71
Piyush-Ask Any Difference 2012-10-24 21:10.

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

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

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

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

58
Dhruv Jindal 2014-01-14 20:14.

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

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

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
51
Vaishali Sutariya 2014-07-29 00: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
raihan ahmed 2013-09-05 22:16.

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

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

48
Oleksiy 2014-06-12 17:10.

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

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

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

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

44
Ashwin S Ashok 2014-07-16 20: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
Kapil Vats 2014-01-06 08:28.

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

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

42
sivag1 2013-07-19 08:52.

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

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

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

(彼の例から。)

32
perry 2014-02-25 20:23.

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

エラーはSDKの警告です!

28
rharvey 2013-09-18 02:15.

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

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

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

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

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

<uses-permission android:name="android.permission.INTERNET"/>
25
dhiraj kakran 2014-03-02 03: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 2014-06-25 11:32.

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

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

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

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

22
amardeep 2014-07-22 01:53.

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

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

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
19
KG6ZVP 2017-10-21 13: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 2015-07-22 16:05.

簡単に言えば、

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

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

解決:

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

仕方:

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

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

だが:

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

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

方法?

  1. AsyncTaskの使用中に、onPostExecute()メソッドからビューを更新します
  2. またはrunOnUiThread()メソッドを呼び出して、run()メソッド内のビューを更新します。
12
yoAlex5 2018-03-18 05: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
Ravindra babu 2017-05-06 10: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 2015-02-18 00: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
Alex Shutov 2016-06-24 12: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
Shinoo Goyal 2017-06-09 19: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
Sharath kumar 2017-09-05 00: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 2015-02-14 13:10.

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

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
7
Ponsuyambu Velladurai 2015-06-25 21:42.

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

Related questions

MORE COOL STUFF

「水曜日」シーズン1の中心には大きなミステリーがあります

「水曜日」シーズン1の中心には大きなミステリーがあります

Netflixの「水曜日」は、典型的な10代のドラマ以上のものであり、実際、シーズン1にはその中心に大きなミステリーがあります.

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ケイト・ミドルトンは、州の夕食会と州の訪問中にカミラ・パーカー・ボウルズからスポットライトを奪いたくなかった、と専門家は言う.

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンが、オリビア・ワイルドが彼女とハリー・スタイルズとの間の「難しい」が「非常に友好的」な分割を恒久的にすることを望んでいる理由を見つけてください.

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする 

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする&nbsp;

エリザベス女王の死後、ケイト・ミドルトンが舞台裏で「非常に困難な時期」を過ごしていたと伝えられている理由を調べてください.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

Total War:Warhammer:Kotakuレビュー

Total War:Warhammer:Kotakuレビュー

私はこのゲームを嫌う準備ができていました。先週の前に、Total War:Warhammerについての私の考えがありました:それでもここに私は、私の手にある完成品であり、私は変わった男です。

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

スタンディングロックスー族のメンバーと水の保護者は、ノースダコタ州のスタンディングロックにあるオセティサコウィンキャンプを去ります。(Twitter経由のCNNスクリーンショット)火と煙がスカイラインを覆い、スタンディングロックスー族のメンバーと水の保護者が、聖なるものを守りながら建てた家、オセティサコウィン(セブンカウンシルファイアーズ)キャンプから行進し、太鼓を打ち、歌い、祈りました。ダコタアクセスパイプラインとしても知られる「ブラックスネーク」からの土地。

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

写真:APシアーズとKマートは、イヴァンカ・トランプのトランプホームアイテムのコレクションも、誰も購入したくないために削除しました。シアーズとKマートの両方の親会社であるシアーズホールディングスは、土曜日のABCニュースへの声明で、彼らが気にかけていると辛抱強く説明しましたトランプラインを売り続けるにはお金を稼ぐことについてあまりにも多く。

ポテトチップスでたった10分でスペインのトルティーヤを作る

ポテトチップスでたった10分でスペインのトルティーヤを作る

伝統的なスペインのトルティーヤは通常、オリーブオイルで柔らかくなるまで調理されたポテトから始まります(30分以上かかる場合があります)が、ケトルで調理されたポテトチップスの助けを借りてわずか10分でテーブルに置くことができます。上のビデオはすべてがバラバラにならないように裏返す方法を含め、レシピ全体を説明しますが、必要なのは4〜5個の卵と3カップのケトルチップスだけです。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

ホームオフィスのセットアップ術を極めよう!AppExert の開発者は、家族全員が一緒にいる場合でも、在宅勤務の技術を習得しています。祖父や曽祖父が共同家族で暮らしていた頃の記憶がよみがえりました。

2022 年、私たちのデジタル ライフはどこで終わり、「リアル ライフ」はどこから始まるのでしょうか?

20 年前のタイムトラベラーでさえ、日常生活におけるデジタルおよびインターネットベースのサービスの重要性に驚くことでしょう。MySpace、eBay、Napster などのプラットフォームは、高速化に焦点を合わせた世界がどのようなものになるかを示してくれました。

ニューロマーケティングの秘密科学

ニューロマーケティングの秘密科学

マーケティング担当者が人間の欲望を操作するために使用する、最先端の (気味が悪いと言う人もいます) メソッドを探ります。カートをいっぱいにして 3 桁の領収書を持って店を出る前に、ほんの数点の商品を買いに行ったことはありませんか? あなたは一人じゃない。

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

私たちが住んでいる世界を確実に理解するには、データが必要です。ただし、空間参照がない場合、このデータは地理的コンテキストがないと役に立たなくなる可能性があります。

Language