'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

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

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

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

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

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

グッドジョブ、ESPN

グッドジョブ、ESPN

今日のホワイトハウスの記者会見で、報道官のサラ・ハッカビー・サンダースは、スポーツセンターのホストであるイェメル・ヒルのドナルド・トランプに関する最近のツイートについてコメントするよう求められ、大統領と彼の政策を白人至上主義者として説明した。ヒルは彼女のつぶやきのためにESPNによって公に叱責されました。

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

基本的に頭のあらゆる部分から髪の毛を整えたり、ブロードライしたり、まっすぐにしたり、脱毛したりする必要がある場合は、このレミントンゴールドボックスが最適です。今日だけ、Amazonは、すでに人気のあるShortcut Pro Self-HaircutKitやPearlPro Ceramic Flat Ironのように、グルーミングをはるかに簡単にするヘアツールをマークダウンしています。

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

トゥパックシャクール(ティムモーゼンフェルダー/ゲッティイメージズ); マヤアンジェロウ(マーティンゴッドウィン/ゲッティイメージズ)移動、テイラースウィフト。ケンドールとカイリーは、必要な数の座席を持っています。

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

写真:Tesla Motorsフロリダに住んでいて、Tesla Model S、Model X 60、またはModel 60Dを使用している場合、車の自律性は50 km(約30マイル)高くなります。これは失敗ではなく、ハリケーンイルマによる避難作業を容易にするために会社自身が命じた自治権の一時的な延長です。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language