web-dev-qa-db-ja.com

Android.os.NetworkOnMainThreadExceptionを修正するにはどうすればよいですか?

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

どうすればこの問題を解決できますか?

2199
bejoy george

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

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

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

追加:

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

636
user1169115

私はこの問題を新しいThreadを使って解決しました。

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
381
Dr.Luiji

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

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

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

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

IntentServiceアプローチ

欠点:

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

アップサイド:

  • 短期的なメモリリークの問題を回避
  • ネットワーク操作中にアクティビティを再開すると、onActivityResultメソッドを介してダウンロードの結果を受け取ることができます
  • 堅牢なネットワークコードを構築して再利用するには、AsyncTaskよりも優れたプラットフォームです。例:重要なアップロードを行う必要がある場合は、AsyncTask内のActivityから行うことができますが、ユーザーがアプリからコンテキスト切り替えて電話をかけると、システムmayアップロードが完了する前にアプリを強制終了します。アクティブなServiceを持つアプリケーションを強制終了する可能性は少ない
  • 独自の同時バージョンのIntentService(上記でリンクしたバージョン)を使用する場合、Executorを使用して同時実行のレベルを制御できます。

実装の概要

IntentServiceを実装して、単一のバックグラウンドスレッドでダウンロードを非常に簡単に実行できます。

ステップ1:ダウンロードを実行するIntentServiceを作成します。 Intent extra'sを介してダウンロードするものを指定し、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プロジェクトが利用可能です こちら

150
Stevie

ハニカム のUIスレッドでネットワーク I/O を実行することはできません。技術的には、以前のバージョンのAndroidでは is が可能ですが、アプリが応答しなくなるため、OSがアプリの動作を悪くして殺害する可能性があるため、本当に悪い考えです。バックグラウンドスレッドでネットワークトランザクションを実行するには、バックグラウンドプロセスを実行するか、AsyncTaskを使用する必要があります。

Painless Threading についての記事がAndroidの開発者サイトにあります。これはこれを紹介するもので、実際に提供されるよりもはるかに優れた回答の深さを提供します。

135
Mark Allison
  1. StrictModeを使用しないでください(デバッグモードのみ)。
  2. SDKのバージョンを変更しないでください
  3. 別のスレッドを使わないでください

サービスまたはAsyncTaskを使用

スタックオーバーフローの質問も参照してください。

Androidから電子メールを送信するAndroid.os.NetworkOnMainThreadException

67
venergiac

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

例えば:

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

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

<uses-permission Android:name="Android.permission.INTERNET"/>
61
henry4343

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

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

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

両方のメソッドの完全なコード

52
Sandeep

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

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

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

コードを入れてください。

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

Android Annotations を使用することはオプションです。それはあなたが単にバックグラウンドスレッドで任意のメソッドを実行することを可能にします:

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

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

それは単純さと読みやすさの利点を提供しますが、それには欠点があります。 

40
Oleksiy

これはAndroid 3.0以降で起こります。 Android 3.0以降では、ネットワーク操作(インターネットにアクセスする機能)をメインスレッド/ UIスレッド(アクティビティのcreateメソッドおよびresumeメソッドから生成されるもの)で実行することを制限しました。

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

39
raihan ahmed

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

これらすべてを単純化するために、AndroidにはAsyncTaskAsyncTaskLoaderCursorLoaderIntentServiceなどのさまざまな方法が用意されています。だからあなたはあなたの要求に従ってこれらのどれでも使うことができる。

35
Kapil Vats

このエラーは、メインスレッドで長時間実行されている操作を実行することに起因します。 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
    }
});
34
Ashwin S Ashok

spektomの答え は完璧に動作します。

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

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

(彼の例から)

34
sivag1

これは、 ハニカム SDK以上をターゲットとするアプリケーションに対してのみスローされます。以前のバージョンのSDKをターゲットとするアプリケーションは、メインのイベントループスレッドでネットワーキングを行うことが許可されています。

エラーはSDKの警告です。

28
perry

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

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

私のアプリをテストしていたデバイスは4.1.2で、これはSDKバージョン16です。

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

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

<uses-permission Android:name="Android.permission.INTERNET"/>
23
rharvey

何かを明示的に綴るために:

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

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

(私のメインスレッド以外のどこかでこのエラーが発生している理由を突き止めようとしていたのは、長い間頭が痛い瞬間でした。このスレッドが助けになりました。

21
Novak

この例外は、実行中のタスクが長すぎる時間を要する場合、メインスレッド上で実行された重いタスクによって発生します。

これを避けるために、 threads または executors を使用して処理できます。

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

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

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

ReST over HTTP

典型的にはJson、XMLまたは他の何かにすることができます

完全なAPIアクセス

ユーザーが株価、金利、為替レートを追跡できるアプリを書いているとしましょう。次のようなJson APIを見つけます。

http://api.example.com/stocks                       //ResponseWrapper<String> object containing a list of Srings with ticker symbols
http://api.example.com/stocks/$symbol               //Stock object
http://api.example.com/stocks/$symbol/prices        //PriceHistory<Stock> object
http://api.example.com/currencies                   //ResponseWrapper<String> object containing a list of currency abbreviation
http://api.example.com/currencies/$currency         //Currency object
http://api.example.com/currencies/$id1/values/$id2  //PriceHistory<Currency> object comparing the prices of the first currency (id1) to the second (id2)

広場からの改装

これは、複数のエンドポイントを持つ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回限りのReST APIアクセス

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

イオン

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

Msysmiluのすばらしい答えを読んでください( https://stackoverflow.com/a/28559884/1024412

HTTP経由で画像を読み込む

ボレー

VolleyはReST APIにも使用できますが、より複雑なセットアップが必要なため、上記のように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メソッド(フラグメント、アクティビティ)またはコンストラクター(ダイアログ)に追加します。

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
KG6ZVP

あなたの活動にこれを使ってください

    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();
        }
    });
15
dhiraj kakran

簡単に言えば、

UIスレッドでネットワーク作業をしない

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

解決策:

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

方法:

すべての作品を中に入れる

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

しかし、:

あなたがネットワークレスポンスから何かを得て、それをあなたのビューに表示したいとき(TextViewのレスポンスメッセージの表示のように)、あなたは UIに戻る必要があります thread。

そうしなければ、ViewRootImpl$CalledFromWrongThreadExceptionが手に入ります。

どうやって?

  1. AsyncTaskを使用しながら、onPostExecute()メソッドからビューを更新します。
  2. または call runOnUiThread() methodを実行し、run()メソッド内でビューを更新します。
14
Nabin

上記には巨大なソリューションプールがありますが、誰も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
    }
});
10
msysmilu

新しいThreadAsyncTask のソリューションはすでに説明されています。

AsyncTaskは理想的には短い操作に使われるべきです。通常のThreadはAndroidには向いていません。 

HandlerThread および Handler を使用して別の解決策を見てください。

HandlerThread

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

ハンドラ:

Handlerを使用すると、スレッドのMessageQueueに関連付けられているMessageオブジェクトとRunnableオブジェクトを送信して処理できます。各Handlerインスタンスは、単一のスレッドとそのスレッドのメッセージキューに関連付けられています。新しいHandlerを作成すると、それはそれを作成しているスレッドのスレッド/メッセージキューにバインドされます。それ以降、メッセージとランナブルはそのメッセージキューに配信され、メッセージから出てきたら実行しますキュー。

溶液:

  1. HandlerThreadを作成する

  2. HandlerThreadに対してstart()を呼び出す

  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は次のネットワーク操作のために破棄され再作成されます。しかし、HandlerHandlerThreadのアプローチでは、HandlerThreadを使用することで、(Runnableタスクとして)多数のネットワーク操作を単一のHandlerに送信できます。 
8
Ravindra babu

メイン(UI)スレッドからネットワークリソースにアクセスすると、この例外が発生します。この問題を回避するには、ネットワークリソースへのアクセスに別のスレッドまたはAsyncTaskを使用してください。

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

これはうまくいきます。ルイジ博士の答えをもう少し簡単にしたところです。

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

RxAndroidは、この問題に対するもう1つの優れた代替手段であり、スレッドを作成してから結果をAndroid UIスレッドに投稿するという面倒な作業から私たちを救います。

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を観察したい、すなわち、onNext()コールバックをUIスレッドで呼び出すようにします。

7
Shinoo Goyal

コードの一部を別のスレッドに移動してmain threadをオフロードし、 _ anr _NetworkOnMainThreadExceptionIllegalStateException を回避することができます。長期間UIをロックする可能性があります。 

状況に応じて選択すべきアプローチがいくつかあります。

Java スレッド Android HandlerThread

Javaスレッドは1回限りの使用のみで、そのrunメソッドの実行後に停止します。

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

AsyncTask

AsyncTask は、 Thread および Handler の周りのヘルパークラスになるように設計されており、一般的なスレッド化フレームワークを構成するものではありません。 AsyncTasksは理想的には短い操作(せいぜい数秒)のために使用されるべきです。スレッドを長期間実行し続ける必要があるならば、Java.util.concurrentパッケージによって提供されるような様々なAPIを使うことが強く推奨されます。 エグゼキュータ ThreadPoolExecutor および FutureTask

スレッドプールの実装 ThreadPoolExecutorScheduledThreadPoolExecutor ...

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

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

フューチャータスク

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

AsyncTaskLoaders

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

IntentService

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

JobScheduler

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

RxJava

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

コルーチン (Kotlin)

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

もっと読む
Androidで非同期処理を行いカウントする8つの方法
Androidネットワークアクセスの進化
Androidでスレッドプールを使用する

6
yoAlex5

Android上のUIスレッドにネットワーク操作を実装することは許可されていません。 AsyncTaskクラスを使用して、APIリクエストの送信、URLからの画像のダウンロードなどのネットワーク関連の操作を実行する必要があります。AsyncTaskのコールバックメソッドを使用すると、onPostExecuteメソッドになり、UIスレッドに入ります。 WebサービスなどのデータをUIに追加できます。

例:URLから画像をダウンロードしたいとします。 https://www.samplewebsite.com/sampleimage.jpg

AsyncTaskを使用した解決策:はそれぞれです。

    public class MyDownloader extends AsyncTask<String,Void,Bitmap>
    {
        @Override
        protected void onPreExecute() {
            // Show progress dialog
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //Populate Ui
            super.onPostExecute(bitmap);
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            // Open URL connection read bitmaps and return form here
            return result;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            // Show progress update
            super.onProgressUpdate(values);
        }


    }
}

注:Androidマニフェストファイルにインターネット権限を追加することを忘れないでください。それは魅力のように働くでしょう。 :)

6
Krishna

この問題に取り組むためのもう一つの非常に便利な方法があります - 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用の優れた電子ブック があります。

6
Alex Shutov

KOTLINANKOのどちらでも使用できます。 

KotlinAndroidの新しい公用語です。詳細はこちら https://kotlinlang.org/docs/tutorials/kotlin-Android.html

Anko AndroidでKotlin用のライブラリをサポートしました。いくつかのドキュメントはこちら https://github.com/Kotlin/anko

本当に便利で@AntonioLeiva https://antonioleiva.com/anko-background-kotlin-Android/ によって書かれた数行のコードしか持っていない解決策

doAsync {
    var result = runLongTask()
    uiThread {
        toast(result)
    }
}

それは単純です、NetworkOnMainThreadUI Threadでバックグラウンドジョブを実行したときに発生するので、あなたがしなければならないことの1つはバックグラウンドでlongTask jobを実行することです。あなたはあなたのAndroidアプリでAnkoでこのメソッドとKotlinを使ってこれを行うことができます。

5
J.D.1731

私はこの問題を簡単な方法で解決しました...

oncreateStrictMode.enableDefaults();の後に追加してこれを解決しました。

または

これを解決するにはServiceまたはAsyncTaskを使用してください。

注意:

Do not change SDK version
Do not use a separate thread

詳しくは これをチェックしてください

4

この例外は、アプリケーションがメインスレッド上でネットワーク操作を実行しようとしたときにスローされます。

コードをAsyncTaskで実行します。

class RetrieveFeedTask extends AsyncTask<String, Void, Boolean> {

    protected RSSFeed doInBackground(String... urls) {
       // TODO: Connect
    }

    protected void onPostExecute(RSSFeed feed) {
        // TODO: Check this.exception
        // TODO: Do something with the feed
    }
}
4

メインスレッドでネットワーク操作が実行されると、Android.os.NetworkOnMainThreadExceptionがスローされます。この例外を削除するには、AsyncTaskでこれを実行することをお勧めします。このように書いてください。

    new AsyncTask<Void,String,String>(){

        @Override
        protected Void doInBackground(Void... params) {
            // Perform your network operation.
            // Get JSON or XML string from the server.
            // Store in a local variable (say response) and return.
            return response;
        }

        protected void onPostExecute(String results){
            // Response returned by doInBackGround() will be received
            // by onPostExecute(String results).
            // Now manipulate your jason/xml String(results).
        }

    }.execute();
}
3
Mansuu....

RxJavaを使ってネットワーク操作をバックグラウンドスレッドに移動することもできます。そしてそれはかなり簡単です。

webService.doSomething(someData)
          .subscribeOn(Schedulers.newThread())-- This for background thread
          .observeOn(AndroidSchedulers.mainThread()) -- for callback on UI              
          .subscribe(result -> resultText.setText("It worked!"),
              e -> handleError(e));

あなたはRxJavaでもっとたくさんのことをすることができます。ここにRxJavaのためのリンクがあります。お気軽にお問い合わせください。 

AndroidのRxJava非同期タスク

http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-Android-patterns/ /

3
bpr10

メインスレッドは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);

詳しくはこちらをご覧ください。Painless threading

3
Anonymous

以下のコードを使用して厳密モードを使用してこの問題を解決することもできます。これはこの問題を解決するための代替手段でもあります。

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

しかし、ベストプラクティスはAsyncTaskを使用することです。

3
Himanshu

Android.os.NetworkOnMainThreadExceptionを修正する方法

NetworkOnMainThreadExceptionとは何ですか?

Androidでは、UIスレッド(メインスレッド)に対して行う必要があるすべてのUI操作。メインスレッドでバックグラウンド操作または何らかのネットワーク操作を実行すると、この例外が発生してアプリが応答しなくなる恐れがあります。

それを修正する方法:

この問題を回避するには、asyncTaskを使用するなど、バックグラウンド操作またはネットワーク操作に別のスレッドを使用し、Volley、AsyncHttpなどのネットワーク操作にライブラリを使用する必要があります。

NetworkOnMainThread例外は、デフォルトのスレッド、つまりUIスレッドで何らかのネットワーク操作を呼び出したために発生します。 許可されていないAndroidのバージョン Android 3 (ハニカム)によると、メインスレッドの外部でネットワーク操作を呼び出す必要があります。

AsyncTask、IntentServiceを使用するか、独自のスレッドを作成してrunメソッド内で呼び出すことができます。詳細については、ネットワークへの接続を参照してください。

1
BalaramNayak

AsycTaskを使ってバックグラウンドスレッドでこれを行います。

Java

class NetworkThread extends AsyncTask<String, Void, String> {

    protected Void doInBackground(String... arg0) {
        //Your implementation
    }

    protected void onPostExecute(String result) {
        // TODO: do something with the feed
    }
}

必要な場所に電話をかける

new NetworkThread().execute("Your URL here");

コトリン

internal class MyNetworkTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {
        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds
         } catch (e: Exception) {
            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

コトリンを呼び出す

MyNetworkTask().execute(url)
1
Vipul Prajapati

メインスレッドやUIスレッドでネットワークを呼び出すことはできません。あなたがネットワークを呼び出したい場合はAndroid上で2つのオプションがあります -

  1. Asynctaskを呼び出します。これにより、ネットワーク操作を処理するためのバックグラウンドスレッドが1つ実行されます。
  2. ネットワーク操作を処理するために独自の実行可能スレッドを作成できます。

個人的にはasynctaskが好きです。詳細については このリンク を参照してください。

1
Hossain Ahamed

Androidはシングルスレッドで動作しているので、メインスレッドでネットワーク操作をしないでください。これを回避するにはさまざまな方法があります。

以下の方法でネットワーク操作を行います。

  • Asysnctask :あまり時間がかからない小さな操作の場合。
  • インテントサービス :ネットワークの運用に時間がかかる。
  • 複雑なネットワーク操作を処理するには、 Volley および Retrofit のようなカスタムライブラリを使用してください。

StrictMode.setThreadPolicy(policy) を使用しないでください。URIがフリーズし、まったく良い考えではありません。

1
aks

あなたは実際に新しいThreadを始めることができます、私は以前にこの問題を抱えていて、この方法でそれを解決しました。

1
rObOtAndChalie

コトリン版

internal class RetrieveFeedTask : AsyncTask<String, Void, RSSFeed>() {

    override fun doInBackground(vararg urls: String): RSSFeed? {

        try {
             // download
             // prepare RSSFeeds
             return RSSFeeds

         } catch (e: Exception) {

            //handle exception
            return null
        }
    }

    override fun onPostExecute(feed: RSSFeed) {
        // TODO: check this.exception
        // TODO: do something with the feed
    }
}

例を呼び出す、

RetrieveFeedTask().execute(url)
0

あなたはKotlin-coroutinesを使うことができます

 class YoutActivity : AppCompatActivity, CoroutineScope {

      override fun onCreate(...) {
         launch {  yourHeavyMethod() }
      }

      suspend fun yourHeavyMethod() {
         async{ yourNetworkCall() }.await()
         ...
         ...
      }

 } 

これ /ガイドに従うことができます。 

0
Santanu Sur

同様の問題がありました。あなたのアクティビティのoncreateメソッドで以下を使用しました。

//allow strict mode
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

そしてそれはうまくいきました。

0
Richard Kamere

2018年の時点で、私はKotlinでRxJavaを使ってネットワークを取得することをお勧めします。簡単な例を以下に示します。

Single.fromCallable {
        // Your Network Fetching Code
        Network.fetchHttp(url) 
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe {
        // What you need to do with your result on the view 
        result -> view.updateScreen(result) 
    }
0
Elye

さまざまなオプション

  1. 通常のJava実行可能スレッドを使用してネットワークタスクを処理し、runOnUIThread()を使用してUIを更新することができます。

  2. ネットワークレスポンスを取得した後にUIを更新したい場合は、intentservice/asyncタスクを使用できます。

0
Ashok Kumar

UIスレッドでは決して長時間の作業をしないでください。その長時間の作業はサーバーとの通信、ファイルの読み取り/書き込みなどです。これらのタスクはバックグラウンドスレッドで行う必要があるので、ServiceAsyncTaskThreadsが作成されました。クラッシュを防ぐためにStrictModeを無効にすることはできますが、お勧めできません。 

デバッグモードでStrictMode少なくともを利用することをお勧めします。メインスレッドであなたのAppを遅くする問題のログを取得するために以下のコードを使用してください。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());

あなたは別のペナルティを設定することができます -

penaltyLog() // to print log
penaltyDeath() // This will crash you App(so costly penalty)
penaltyDialog() // Show alert when something went lazy on Main thread

https://developer.Android.com/reference/Android/os/StrictMode.html についての多くがあります

0
Rahul

あなたがコトリンとアンコで働いているならば、あなたは加えることができます 

 doAsync {
   method()
}
0
Devix