2614

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

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

4

64 に答える 64

2647

注:AsyncTaskはAPIレベル30で非推奨になりました
。Android開発者

この例外は、アプリケーションがメインスレッドでネットワーク操作を実行しようとしたときにスローされます。でコードを実行します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"/>
于 2011-06-14T12:15:05.223 に答える
748

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

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

追加:

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

StrictMode.setThreadPolicy(policy);

あなたのクラスでは、

Androidのmanifest.xmlファイルに次の権限を追加します。

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

結果:

アプリは(インターネット接続が不安定な領域では)応答しなくなり、ロックされ、ユーザーは速度の低下を認識して強制的に強制終了する必要があります。また、アクティビティマネージャーがアプリを強制終了し、アプリが停止したことをユーザーに通知するリスクがあります。

Androidには、応答性を設計するための優れたプログラミング手法に関するいくつかの優れたヒントがあります 。Android開発者

于 2012-02-15T06:59:50.027 に答える
492

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

Thread thread = new Thread(new Runnable() {

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

thread.start(); 
于 2013-01-21T16:31:35.090 に答える
187

受け入れられた回答には、いくつかの重大な欠点があります。自分が何をしているのかを本当に理解していない限り、ネットワークに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ユーザーがアプリから切り替えて電話をかけると、アップロードが完了する前にシステムアプリを強制終了する場合があります。アクティブなアプリケーションを強制終了する可能性は低くなり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 reuse, 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);
}

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

于 2014-01-22T13:17:32.277 に答える
150

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

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

于 2011-06-14T12:07:51.613 に答える
128

この問題には2つの解決策があります。

  1. メインUIスレッドでネットワーク呼び出しを使用しないでください。そのために非同期タスクを使用します。

  2. setContentView(R.layout.activity_main);の後に、以下のコードをMainActivityファイルに書き込みます。:

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

そして、以下のimportステートメントをJavaファイルにインポートします。

import android.os.StrictMode;
于 2012-10-30T10:06:32.587 に答える
90

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

例えば:

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

そして、これをファイルAndroidManifest.xmlに追加します。

<uses-permission android:name="android.permission.INTERNET"/>
于 2013-12-24T14:33:08.510 に答える
81
  1. strictModeを使用しないでください(デバッグモードのみ)
  2. SDKのバージョンを変更しないでください
  3. 別のスレッドを使用しないでください

ServiceまたはAsyncTaskを使用する

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

android.os.NetworkOnMainThreadExceptionAndroidからのメールの送信

于 2013-08-18T09:18:48.467 に答える
74

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

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

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

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

于 2012-10-24T07:10:03.367 に答える
62

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

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

new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            // Your implementation goes here
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}).start();
于 2014-01-14T06:14:13.900 に答える
52

コードを中に入れます:

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
    }
}
于 2014-07-28T10:43:13.117 に答える
50

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

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

于 2013-09-05T08:16:34.440 に答える
49

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

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

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

シンプルさと読みやすさのメリットはありますが、デメリットがあることに注意してください。

于 2014-06-12T03:10:54.360 に答える
45

このエラーは、メインスレッドで長時間実行されている操作が原因で発生します。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
    }
});
于 2014-07-16T06:09:37.833 に答える
44

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

これらすべてを簡素化するために、Androidには、、、、などのさまざまな方法が用意されてAsyncTaskいます。したがって、要件に応じてこれらのいずれかを使用できます。AsyncTaskLoaderCursorLoaderIntentService

于 2014-01-05T18:28:38.127 に答える
43

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

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

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

(彼の例から。)

于 2013-07-18T18:52:22.977 に答える
32

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

エラーはSDKの警告です!

于 2014-02-25T06:23:51.290 に答える
28

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

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

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

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

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

<uses-permission android:name="android.permission.INTERNET"/>
于 2013-09-17T12:15:21.133 に答える
26

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

    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();
        }
    });
于 2014-03-01T13:43:59.780 に答える
24

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

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

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

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

于 2014-06-24T21:32:53.947 に答える
23

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

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

Executors.newSingleThreadExecutor().submit(new Runnable() {
    @Override
    public void run() {
        // You can perform your task here.
    }
});
于 2014-07-21T11:53:20.923 に答える
20

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

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

HTTP上のREST

通常はJSONですが、XMLなどの場合もあります。

フルAPIアクセス

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

http://api.example.com/stocks                       // ResponseWrapper<String> object containing a
                                                    // list of strings 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に最適であり、Amazon Ion JavaVolley(Webサイト:Retrofit)などの他のライブラリのように個別にコーディングする代わりに、RESTエンドポイントを宣言できます。

財務APIでどのように使用しますか?

ファイルbuild.gradle

次の行をモジュールレベルのbuild.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を使用するとこれが簡単になります(詳細については、Retrofitにヘッダーパラメーターを追加するためのこのすばらしい回答を参照してください)。

1回限りのRESTAPIアクセス

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

イオン

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

「android.os.NetworkOnMainThreadException」を修正するにはどうすればよいですか?に対するmsysmiluのすばらしい回答をお読みください。。

HTTP経由で画像を読み込む

ボレー

VolleyはRESTAPIにも使用できますが、セットアップがより複雑になるため、上記のようにSquareのRetrofitを使用することをお勧めします。

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

ファイルbuild.gradle

次の行をモジュールレベルのbuild.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());

ピカソ

Picassoは、Squareのもう1つの優れたライブラリです。いくつかの素晴らしい例については、Webサイトを参照してください。

于 2017-10-20T23:50:07.767 に答える
16

簡単に言えば、

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

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

解決:

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

仕方:

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

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

だが:

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

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

方法

  1. AsyncTaskを使用しているときに、onPostExecute()メソッドからビューを更新します
  2. または、メソッドを呼び出して、runOnUiThread()メソッド内のビューを更新しますrun()
于 2015-07-22T02:05:44.033 に答える
14

コードの一部を別のスレッドに移動して、をオフロードし、ANRmain threadNetworkOnMainThreadException 、IllegalStateExceptionが発生しないようにすることができます(たとえば、UIが長期間ロックされる可能性があるため、メインスレッドのデータベースにアクセスできません)。

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

JavaスレッドまたはAndroidHandlerThread

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

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

AsyncTask(APIレベル30で非推奨)

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

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

【エグゼキュータフレームワーク】

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

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

FutureTask

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

AsyncTaskLoaders

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

IntentService

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

JobScheduler

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

RxJava

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

コルーチン(Kotlin)

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

詳細はこちらこちらこちら、こちらをご覧ください

于 2018-03-17T15:58:49.810 に答える
11

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

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

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

HandlerThread

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

ハンドラ:

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

解決:

  1. 作成HandlerThread

  2. 呼びかけるstart()_HandlerThread

  3. からHandler取得して作成LooperHanlerThread

  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ますHandler
于 2017-05-05T20:11:56.267 に答える
10

上記には巨大なソリューションプールがありますが、誰も言及していませんcom.koushikdutta.ionhttps ://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
    }
});
于 2015-02-17T10:31:31.067 に答える
9

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

new Thread() {
    @Override
    public void run() {
        try {
            //Your code goes here
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
于 2015-02-13T23:10:17.853 に答える
9

この問題に取り組むための別の非常に便利な方法があります-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()スケジューラーのサポートが含まれます。

RxJava用の優れた電子書籍があります。

于 2016-06-23T22:00:02.920 に答える
9

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()コールバックを呼び出す必要があります。

于 2017-06-09T05:57:25.223 に答える
9

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

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

于 2017-09-04T10:43:19.090 に答える
8

Kotlin

Kotlinを使用している場合は、コルーチンを使用できます。

fun doSomeNetworkStuff() {
    GlobalScope.launch(Dispatchers.IO) {
        // ...
    }
}
于 2020-08-14T14:19:43.133 に答える
7

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

于 2015-06-25T07:42:59.583 に答える
7

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

于 2015-08-13T08:26:14.747 に答える
7

KotlinAnkoのどちらかを使用できます。

KotlinはAndroidの新しい公用語です。詳細については、 KotlinforAndroidをご覧ください 。

Ankoは、AndroidでサポートされているKotlinのライブラリです。一部のドキュメントはGitHubページにあります。

本当に便利で、@ AntonioLeivaによって記述されたコードが数行しかないソリューション: AndroidでKotlinを使用してAnkoを使用してバックグラウンドタスクを実行する(KAD 09)

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

単純なことですがNetworkOnMainThread、UIスレッドでバックグラウンドジョブを実行すると発生するため、longTaskジョブをバックグラウンドで実行する必要があります。これは、Androidアプリでこの方法とKotlinwithAnkoを使用して行うことができます。

于 2017-07-10T09:06:55.807 に答える
6

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

例:次の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マニフェストファイルにインターネット権限を追加することを忘れないでください。それは魅力のように機能します。:)

于 2015-12-18T09:23:21.713 に答える
6

Androidでは、ネットワーク操作をメインスレッドで実行することはできません。ThreadAsyncTask(短時間実行タスク)、 (長時間実行タスク)を使用Serviceしてネットワーク操作を行うことができます。android.os.NetworkOnMainThreadExceptionアプリケーションがメインスレッドでネットワーク操作を実行しようとするとスローされます。タスクに5秒以上かかった場合は、強制終了します。

でコードを実行しますAsyncTask

class FeedTask 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
    }
}

または

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

これはお勧めしません。

ただし、デバッグの目的で、次のコードを使用して厳密モードを無効にすることもできます。

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy =
        new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
于 2020-02-11T10:28:02.603 に答える
6

Androidは、メインスレッドで長時間実行される操作を実行することを許可していません。

したがって、別のスレッドを使用して、必要に応じて結果をメインスレッドに投稿するだけです。

new Thread(new Runnable() {
        @Override
        public void run() {
            /*
            // Run operation here
            */
            // After getting the result
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Post the result to the main thread
                }
            });
        }
    }).start();
于 2021-02-21T08:54:49.910 に答える
5

この例外は、アプリケーションがメインスレッドでネットワーク操作を実行しようとしたときにスローされます。タスクに5秒以上かかった場合は、強制終了します。

でコードを実行します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
    }
}
于 2016-01-15T16:47:54.673 に答える
5

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/

于 2016-05-23T09:32:15.610 に答える
5

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

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

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

于 2017-02-19T11:31:11.097 に答える
5

GoogleはAndroid11でAndroidAsyncTaskAPIを非推奨にしました。

mainアクティビティの外部でスレッドクラスを作成した場合でも、mainで呼び出すだけで、同じエラーが発生します。呼び出しは実行可能なスレッド内にある必要がありますが、バックグラウンドで実行する非同期コードまたは後でここで実行する非同期コードが必要な場合は、KotlinとJavaの両方の代替コードを確認できます。

*https://stackoverflow.com/questions/58767733/android-asynctask-api-deprecating-in-android-11-what-are-the-alternatives*

私のために特に働いたのは、上記のリンクにある実行可能なスレッドのJava8実装に対するmayank1513による回答でした。コードは次のとおりです。

new Thread(() -> {
        // do background stuff here
        runOnUiThread(()->{
            // OnPostExecute stuff here
        });
    }).start();

ただし、最初にコードのある部分でスレッドを定義し、次のように別の場所でスレッドを開始することができます。

スレッド定義

Thread thread = new Thread(() -> {
            // do background stuff here
            runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        });

スレッド呼び出し

thread.start();

これにより、廃止されたAsyncTaskを見るという頭痛の種が軽減されることを願っています。

于 2020-10-15T14:56:34.990 に答える
4

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

NetworkOnMainThreadExceptionとは何ですか:

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

それを修正する方法:

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

于 2016-10-04T08:00:51.103 に答える
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();
}
于 2017-01-16T04:56:58.680 に答える
4

を使用してバックグラウンドスレッドでこれを行う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");

Kotlin

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

kotlinに電話する

MyNetworkTask().execute(url)
于 2019-06-10T04:50:55.837 に答える
4

私も同様の問題を抱えていました。私はあなたのアクティビティのoncreateメソッドで以下を使用しました。

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

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

注意点は、100ミリ秒を超えるネットワーク要求にこれを使用すると、顕著なUIフリーズが発生し、ANR(アプリケーションが応答しない)が発生する可能性があることに注意してください。

于 2019-08-18T17:27:01.277 に答える
3

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

後に追加しoncreate StrictMode.enableDefaults();て解決しました。

または

Serviceまたはを使用AsyncTaskしてこれを解決します

ノート:

Do not change SDK version
Do not use a separate thread

詳細については、これを確認してください

于 2014-12-21T08:17:47.360 に答える
3

開発者から-android :

AsyncTasksは、理想的には短い操作(最大で数秒)に使用する必要があります。

使用するnewCachedThreadPoolのは良いことです。newSingleThreadExecutorまた、、などの他のオプションを検討することもできますnewFixedThreadPool

    ExecutorService myExecutor = Executors.newCachedThreadPool();
    myExecutor.execute(new Runnable() {
        @Override
        public void run() {
            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);
        }
    });

ThreadPoolExecutorは、このプロセスを簡単にするためのヘルパークラスです。このクラスは、スレッドのグループの作成を管理し、それらの優先順位を設定し、それらのスレッド間で作業がどのように分散されるかを管理します。ワークロードが増減すると、クラスは、ワークロードに適応するために、より多くのスレッドをスピンアップまたは破棄します。

Androidスレッドの詳細については、こちらをご覧ください

于 2020-01-01T14:52:10.283 に答える
2

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

ネットワーク操作を実行するには、次の方法を使用します

  • Asysnctask:時間のかからない小さな操作用。
  • インテントサービス:時間がかかるネットワーク運用に。
  • 複雑なネットワーク操作を処理するには、 VolleyRetrofitなどのカスタムライブラリを使用します

StrictMode.setThreadPolicy(policy)は絶対に使用しないでください。UIがフリーズし、まったくお勧めできません。

于 2017-03-02T16:16:14.040 に答える
2

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

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

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

于 2017-03-17T06:00:44.263 に答える
2

KotlinとAnkoで作業している場合は、を追加できます。

doAsync {
    method()
}
于 2018-12-10T22:09:37.817 に答える
2

Kotlinコルーチンを使用できます:

 class YoutActivity : AppCompatActivity, CoroutineScope {
      
      override fun onCreate(...) {
         launch {  yourHeavyMethod() }
      }

      suspend fun yourHeavyMethod() {
         with(Dispatchers.IO){ yourNetworkCall() }
         ...
         ...
      }
 } 

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

于 2019-03-01T17:37:35.380 に答える
2

これらの回答は、インターネット上のサーバーに接続し、一般に非同期タスクを処理するためのより現代的な方法を使用するように更新する必要があります。

たとえば、GoogleDriveAPIサンプルでタスクが使用されている例を見つけることできます。この場合も同じように使用する必要があります。OPの元のコードを使用して、このアプローチを示します。

まず、オフメインスレッドエグゼキュータを定義する必要があり、それを1回だけ行う必要があります。

private val mExecutor: Executor = Executors.newSingleThreadExecutor()

次に、メインスレッドから実行されるそのエグゼキュータでロジックを処理します

Tasks.call (mExecutor, Callable<String> {

        val url = URL(urlToRssFeed)
        val factory = SAXParserFactory.newInstance()
        val parser = factory.newSAXParser()
        val xmlreader = parser.getXMLReader()
        val theRSSHandler = RssHandler()
        xmlreader.setContentHandler(theRSSHandler)
        val is = InputSource(url.openStream())
        xmlreader.parse(is)
        theRSSHandler.getFeed()

        // Complete processing and return a String or other object.
        // E.g., you could return Boolean indicating a success or failure.
        return@Callable someResult
}).continueWith{
    // it.result here is what your asynchronous task has returned
    processResult(it.result)
}

continueWith句は、非同期タスクが完了した後に実行され、it.resultを介してタスクによって返された値にアクセスできるようになります。

于 2020-03-14T00:11:57.440 に答える
1

実際に新しいスレッドを開始できます。私は以前にこの問題を抱えていましたが、この方法で解決しました。

于 2015-08-17T01:47:28.940 に答える
1

NetworkOnMainThread例外は、デフォルトのスレッド、つまりUIスレッドでネットワーク操作を呼び出したために発生します。許可されていないAndroidバージョンAndroid3 (Honeycomb)に従って、メインスレッドの外部でネットワーク操作を呼び出す必要があります。

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

于 2016-01-19T09:52:56.550 に答える
1

Android Jetpackが導入されました。これにより、 Android 8.1(Oreo)WorkManagerでのバックグラウンドサービス制限の問題と、Android 5.0(Lollipop)より前のAlarmManagerおよびLolipopより上のJobSchedulerの使用が修正されます。

バックグラウンドスレッドでタスクを実行するために使用WorkManagerしてください。ユーザーがアプリを閉じた後も実行を継続します。

于 2019-11-06T04:52:44.607 に答える
1

値を返すネットワークアクセス関数を次のようなサスペンド関数に変換しました。


suspend fun isInternetReachable(): Boolean {
  ...
  ...
  return result
}

次に、これに合うように関数を使用していた場所を変更しました。

...
Globalscope.async{
  ...
  result = isInternetReachable()
  ...
}
...
于 2021-04-04T23:52:04.760 に答える
0

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) 
    }
于 2018-01-17T21:54:56.417 に答える
0

さまざまなオプション:

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

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

于 2018-05-10T09:24:39.887 に答える
0

Kotlinバージョン

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)
于 2019-06-01T07:41:03.440 に答える
0

OkHttp、、、およびを使用しFutureた簡単なソリューションを次に示します。ExecutorServiceCallable

final OkHttpClient httpClient = new OkHttpClient();
final ExecutorService executor = newFixedThreadPool(3);

final Request request = new Request.Builder().url("http://example.com").build();

Response response = executor.submit(new Callable<Response>() {
   public Response call() throws IOException {
      return httpClient.newCall(request).execute();
   }
}).get();
于 2021-01-25T10:12:47.793 に答える
-1

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

StrictMode少なくともデバッグモードでは、を利用することをお勧めします。以下のコードを使用して、メインスレッドでアプリの速度を低下させる問題のログを取得します。

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

詳細はStrictModeこちら:StrictMode | Android開発者

于 2017-08-01T17:31:34.680 に答える
-3

以下のコードを使用して、重いタスクを実行します。

// Your package here


import java.util.List;
import org.apache.http.NameValuePair;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View.OnSystemUiVisibilityChangeListener;

public class AsyncRequest extends AsyncTask<String, Integer, String> {

    Context context;
    ProgressDialog pDialog;

    // Three Constructors
    public AsyncRequest(Activity a, String m, List<NameValuePair> p) {
        context = a;
        method = m;
        parameters = p;
    }

    public AsyncRequest(Activity a) {
        this.caller = (OnAsyncRequestComplete) a;
        context = a;
    }

    public String doInBackground(String... urls) {

        //Perform your task here
        return result;
    }

    public void onPreExecute() {
        pDialog = new ProgressDialog(context);
        pDialog.setMessage("Please wait..");
        pDialog.setCancelable(false);
        pDialog.show();
    }

    public void onProgressUpdate(Integer... progress) {
        // You can implement some progressBar and update it in this record.
        //   setProgressPercent(progress[0]);
    }

    public void onPostExecute(String response) {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
        // Get the result here
    }

    protected void onCancelled(String response) {

        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }
}
于 2015-01-27T09:56:43.643 に答える
-4

マニフェストタグの後に、ファイルmanifest.xmlの次の行を追加するだけです。

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

また、アクティビティファイルで、バインディングステートメントの後に次のコードを追加します。

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}
于 2015-02-26T05:44:37.343 に答える
-5

Androidでは、メインアクティビティスレッドへの個別のプロセスは許可されていません。ここでは、HTTP接続は独立したスレッドです。これが、「android.os.NetworkOnMainThreadException」が発生する理由です。

ユーザーにWebビューを表示する前に、実際のインターネット接続を確認する必要がある場合があります。インターネットがない場合、Webビューにはページが見つからないというエラーがユーザーに表示されますが、通常は何を表示するかはわかりません。 。

インターネットの可用性を確認するためにpingコマンドを使用できますが、Wi-Fiの場合はWi-Fiサーバーでpingを無効にできるため、この場合はHTTP接続を使用してリクエストのステータスを確認します。

これは、ユーザーにWebビューを表示する前に独自のWebビューURLリンクを確認する場合に適切なアプローチになる可能性があります。この場合、Androidの厳密モードを使用できますが、必要がないため、すべてのポリシーを許可しないでください。

厳密モードのネットワーク許可ポリシーのみを指定する必要があります。以下の行をコードに追加するだけで、このエラーは発生しません。

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
StrictMode.setThreadPolicy(policy);
于 2014-12-12T04:12:21.547 に答える