Android SDK AsyncTask doInBackgroundが実行されていません(サブクラス)


90

2012年2月15日の時点では、これがうまく機能しない理由や理由がまだわかりません。ソリューションに最も近いのは、従来のスレッドアプローチを使用することですが、なぜAndroid SDKで機能しない(と思われる)クラスを含めるのでしょうか。

Evenin 'SO!

私はAsyncTaskサブクラスを持っています:

// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener

これは次のように実行されます。

xmlAsync xmlThread = new xmlAsync();

xmlThread.execute("http://www.nothing.com");

今、このサブクラスは小さなエラーに遭遇しました。以前はいくつかのxml解析を行いましたが、doInBackground()が呼び出されていないことに気付いたときは、行ごとに削除し、最終的には次のようになりました。

@Override
protected Void doInBackground(String... params) 
{
    Log.v(TAG, "doInBackground");
        return null;
}

これは、何らかの理由で何も記録しませんでした。しかし、私はこれを追加しました:

@Override
protected void onPreExecute() 
{
        Log.v(TAG, "onPreExecute");
        super.onPreExecute();
}

スレッドを実行すると、その行は実際にログに記録されます。したがって、どういうわけかonPreExecute()が呼び出されますが、doInBackground()は呼び出されません。別のAsyncTaskを同時にバックグラウンドで実行していますが、これは問題なく動作します。

私は現在、北極に近いエミュレーター、SDKバージョン15、Eclipse、Mac OS X 10.7.2でアプリを実行しています。

編集:

@Override
    protected void onProgressUpdate(RSSItem... values) {

        if(values[0] == null)
        {
                            // activity function which merely creates a dialog
            showInputError();
        }
        else
        {

            Log.v(TAG, "adding "+values[0].toString());
            _tableManager.addRSSItem(values[0]);
        }


        super.onProgressUpdate(values);
    }

_tableManager.addRSSItem()は、アクティビティのコンテキストで初期化されたSQLiteDatabaseに多かれ少なかれ行を追加します。publishProgress()は、インターフェースParseListenerのコールバックによって呼び出されます。しかし、doInBackground()でlog.v以外は何もしなかったので、最初にこれを起動する必要もないことに気付きました。

編集2:

さて、完全に明確にするために、これはもう1つのAsyncTaskであり、同じアクティビティで実行され、完全に正常に動作します。

private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
    Integer prevCount;
    boolean run;

    @Override
    protected void onPreExecute() {
        run = true;
        super.onPreExecute();
    }

    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        run = true;
        prevCount = 0;

        while(run)
        {
            ArrayList<RSSItem> items = _tableManager.getAllItems();

            if(items != null)
            {
                if(items.size() > prevCount)
                {
                    Log.v("db Thread", "Found new item(s)!");
                    prevCount = items.size();

                    RSSItem[] itemsArray = new RSSItem[items.size()];

                    publishProgress(items.toArray(itemsArray));
                }
            }               

            SystemClock.sleep(5000);
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(RSSItem... values) {

        ArrayList<RSSItem> list = new ArrayList<RSSItem>();

        for(int i = 0; i < values.length; i++)
        {
            list.add(i, values[i]);
        }

        setItemsAndUpdateList(list);

        super.onProgressUpdate(values);
    }

    @Override
    protected void onCancelled() {
        run = false;

        super.onCancelled();
    }
}

編集3:

ため息、ごめんなさい。しかし、これがタスクの初期化です。

xmlAsync _xmlParseThread;
dbAsync _dbLookup;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

_dbLookup = new dbAsync();
_dbLookup.execute();

_xmlParseThread = new xmlAsync();       
_xmlParseThread.execute("http://www.nothing.com", null);
}

タスクが完了する前にアクティビティが終了している可能性はありますか?
ポールニコノウィッチ

ありそうもない。その場合、私の別のスレッドは正しく実行されませんか?そして、私は現在1つの活動のみを行っています。
SeruK、2012

2
私のアプリにも同じ問題があります-doInBackgroundが呼び出されないか、非常に長い遅延で呼び出されます。これが私の限られた観察です:まったく同じコードがAndroid 2.3.3スマートフォンとAndroid 2.3.3エミュレーターで問題なく動作しますが、Android 4.0.3タブレットとAndroid 4.xxエミュレーターの束でこの問題があります。この問題が新しいバージョンのAndroidで導入されたと結論するのは非常に魅力的です。
香港

申し訳ありませんが、この問題はアクティビティの2番目のAsyncTaskでのみ発生することを忘れていました。最初のAsyncTaskは常に正常に動作します。
香港

ホン、マシューの答えを試しましたか?私はほとんどAndroidゲームのATMを利用していないので、しばらくの間それを使用していないので、彼の答えが実際に機能するかどうかはわかりません。それがあなたのためにならないのであれば、おそらく彼の答えを受け入れるのが私にとって悪かったのかもしれません...
SeruK

回答:


107

Matthieuのソリューションはほとんどの場合問題なく機能しますが、問題に直面する場合もあります。ここまたはAndersGöranssonのようなWebから提供される多くのリンクを掘り下げない限りの説明の。ここで他のいくつかの読み取りを要約し、executeOnExecutorがまだシングルスレッドで動作している場合の解決策をすばやく説明しようとしています...

AsyncTask().execute();Androidのバージョンによって動作が変更されました。前ドーナツ (アンドロイド:1.6 API:4)タスクはから、シリアルに実行されたドーナツジンジャーブレッド (アンドロイド:2.3 API:9)のタスクが並列て実行。以来、ハニカム (アンドロイド:3.0 API:11)実行はシーケンシャルに戻しました。AsyncTask().executeOnExecutor(Executor)ただし、新しいメソッドが並列実行のために追加されました。

順次処理では、すべての非同期タスクが単一のスレッドで実行されるため、前のタスクが終了するまで待機する必要があります。コードをすぐに実行する必要がある場合は、タスクを別々のスレッドで並列処理する必要があります。

AsyncTaskでは、シリアル実行はドーナツバージョンとHoneycombバージョン間で使用できませんが、パラレル実行はドーナツより前では使用できません。

ドーナツ後の並列処理の場合:ビルドバージョンを確認し、それに基づいて.execute()または.executeOnExecutor()メソッドを使用します。次のコードが役立ちます...

AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask code goes here
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
    myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
    myTask.execute();

NOTE:関数.executeOnExecutor()targetSdkVersion、プロジェクトがHONEYCOMB_MR1(Android:2.1 API:7)以下であるかどうかをチェックし、エグゼキューターを強制しますTHREAD_POOL_EXECUTOR(Honeycombの後でタスクを順次実行します)。
を定義していない場合targetSdkVersionminSdkVersionは自動的にと見なされますtargetSdkVersion
したがって、Post HoneycombでAsyncTaskを並行して実行する場合、targetSdkVersion空のままにすることはできません。


1
とても良い答えです。Matthieu'sは間違っていませんが、重要な情報をたくさん追加したので、これは受け入れます。
SeruK 14

@Nasheありがとうございます。それは本当にとても役に立ちます。私はこれと同じ問題で3日間戦っていました。ありがとうございました:)

私の日を救った!この答えが見つけやすくなりますように。
zjk 2014年

4
@Nasheさん、私の問題は少し厄介です。今日まで、私はAsyncTaskで.execute()メソッドを使用しており、コードは完全に機能していました。しかし、今日、問題が発生しました-コントロールがdoInBackground()メソッドに入りません。あなたが提供するソリューションは機能していますが、ソリューションなしでは以前はどのように機能していたのか困惑しています。以前と同じデバイスのセットを使用しています。
Ravi Sisodia、2014年

なぜこれがこの方法であるべきですか?なぜ期待どおりに機能しないのですか?:(
ニコライR

160

この回答をチェックアウトする必要があります:https : //stackoverflow.com/a/10406894/347565とそれに含まれるGoogleグループへのリンク。

私はあなたと同じような問題を抱えていましたが、なぜそれが機能しないのかはまだわかりませんが、次のようにコードを変更して問題は解決しました:

ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() { ... };
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
else
    my_task.execute((Void[])null);

私はこの投稿を振り返るのが非常に苦手でした。私はプロジェクトから離れて久しい。人々はそれがうまくいくと言っているようですので、私はこれを答えとして受け入れます。
SeruK

これはちょうど今私のために働いたが、私は理由を理解したいです。それはそれが停止する前に実行でうまく機能していました。私がやっていることの1つは、同じasynctaskのonPostExecute内で新しいasynctaskを開始することです(つまり、再帰的に呼び出しています)おそらく問題に関連していますか?
steveh 2013

:私は、これはあなたが必要とするすべての説明与えるべきだと思うcommonsware.com/blog/2012/04/20/...
マチュー

1
@Matthieu:サー、私は本当にあなたに十分に感謝することはできません!!! 私は何時間もこの問題に頭を悩ませていました。あなたの解決策はすべてを魅力のように機能させました!素晴らしい回答をありがとうございました。私は複数の賛成票を与えたいと思います!!
Swayam 2013


9

これを行うには、次の2つの方法があります。

方法1

if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13
  {
      asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
else // Below Api Level 13
  {
      asyncTask.execute();
  }

方法1が機能しない場合は、方法2を試してください。

方法2

int mCorePoolSize = 60;
int mMaximumPoolSize = 80;
int mKeepAliveTime = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);

これがお役に立てば幸いです。


super dudeその動作しますが、AsyncTask.THREAD_POOL_EXECUTORを使用している次の非同期タスクが失敗しているので、プロジェクト全体でCustomExecutorを変更する必要があると思います:(
kumar

@vinu、私はあなたがAsyncTaskを実行するための一般的な非同期タスクと一般的な方法を使用することをお勧めします。これがお役に立てば幸いです。
Hiren Patel 2016

2
こんにちは。ありがとう!
Justin Ebby 2017年

6

私は同じ問題を抱えていました:最初の1つで「execute」を呼び出した後、2番目のAsyncTaskを実行できません:doInBackgroundは最初の1つに対してのみ呼び出されます。

これは、このチェックなぜ起こるか答えるための答え(SDKによって異なる振る舞いを)

ただし、あなたの場合、この障害はexecuteOnExecutor(3.0から利用可能になり、4.0.3を使用して動作しました)を使用して回避できますが、スレッドプールのサイズとキューイングの制限に注意してください。

あなたはこのようなことを試すことができます:

xmlAsync _xmlParseThread;
dbAsync _dbLookup;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

_dbLookup = new dbAsync();
_dbLookup.execute();

_xmlParseThread = new xmlAsync();       
_xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
 ,"http://www.nothing.com", null);
}

あなたの更新の質問について:それはドキュメントで説明されています 基本的には、インターリファレンスのようなマルチスレッドから生じる可能性のあるすべての問題を回避するために...


5

私が知りたいことの1つは、問題が実際に修正される可能性があるということです。それは、クラスのインスタンスをインスタンス化し、execute()メソッドを呼び出す場所です。AsyncTaskのドキュメントを読んだ場合、これらの操作は両方ともメインUIスレッドで行う必要があります。オブジェクトを作成して他のスレッドから実行を呼び出している場合、onPreExecuteが起動する可能性があります。ここでは100%確実ではありませんが、バックグラウンドスレッドは作成および実行されません。

AsyncTaskのインスタンスをバックグラウンドスレッドから作成している場合、またはメインのUIスレッドで実行されていないその他の操作を実行している場合は、Activity.runOnUiThread(Runnable)メソッドの使用を検討できます。

このメソッドを呼び出すには、実行中のアクティビティのインスタンスにアクセスする必要がありますが、UIスレッドで実行されていない他のコードからUIスレッドでコードを実行できるようになります。

それが理にかなっていると思います。さらにお手伝いできるかどうかお知らせください。

デビッド


あなたの回答にこのスレッドを追加すると興味深い回答があります。stackoverflow.com/questions/4080808/…
manjusg

素晴らしい答えをありがとう!これは、AsyncTask-beginnerの一般的な問題である可能性があるため、これを引き上げました。悲しいかな、これはこの問題に対する正しい答えではありません。両方のクラスは、メインUIスレッドで実行されているアクティビティのonCreate()でインスタンス化されます。私はこのプロジェクトで1つの活動だけを持っています。
SeruK、2012

@manjusg私はずっとAsyncTaskが不安定であることと何か関係があるとずっと考えてきました、おそらくいくつかが同時に実行されている場合はさらに多くなります。もしそうなら、なぜですか?
SeruK、2012

私はSOが3回連続で投稿することに関してどのようなポリシーを持っているのか本当にわかりませんが、他のスレッドでこれを見つけました... foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html "AsyncTaskはハードコードされた制限が10要素の静的内部作業キュー。」これは何かを証明するかもしれませんが、AsyncTaskサブクラスのインスタンスが2つあるだけです!結局のところ、最終的には大量の解析が行われるため、通常のスレッド化メソッドの使用は避けたいと思います。
SeruK、2012

2

Androidは残忍です。私はこれを信じることができません、日から今日まで変化するフレーキーな実装。ある日は1つのスレッド、次の5はもう1つのスレッドです。

とにかく、ここでは、在庫のAsyncTaskの代替品がほぼ一杯です。必要に応じてAsyncTaskと呼ぶこともできますが、混乱を避けるために、呼び出されたThreadedAsyncTaskを使用します。execute()は最後なので、executeではなくexecuteStart()を呼び出す必要があります。

/**
 * @author Kevin Kowalewski
 *
 */
public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { 
    public AsyncTask<Params, Progress, Result> executeStart(Params... params){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
            return executePostHoneycomb(params);
        }else{
            return super.execute(params);
        }
    }


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params){
        return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); 
    }
}

待ってください、Androidのいくつかのバージョンは非同期操作を1つのスレッドに制限していると言っていませんか?それは信じられないほど愚かなことでしょう。(私はしばらくの間Androidゲームから離れていました。:))
SeruK 2013年

はい、Android 3.0以降では、AsyncTask.THREAD_POOL_EXECUTORを使用しない場合は、1つのスレッドプールしか取得できません。2つのAsyncTaskで試してみて、自分のdoInBackgroundでスリープするだけです。Android AsyncTaskのドキュメントから:「HONEYCOMBから開始すると、タスクは単一のスレッドで実行され、並列実行によって引き起こされる一般的なアプリケーションエラーを回避します。」
Kevin Parker

1

これは本当にスレッドに遅れる可能性があることは知っていますが、それが後のAndroidエミュレーターで機能しない理由があります。asynctaskが導入されたとき、androidは一度に1つしか実行できず、しばらくしてから、どのバージョンかわからないため、一度に複数のasynctaskを実行できました。これにより、多くのアプリで問題が発生したため、Honeycomb +では、一度に1つのasynctaskを実行できます。スレッドプールを手動で変更しない限り。それが人々のために1つまたは2つのことを片付けることを願っています


0

そのSDKだと思います。同じ問題があり、ターゲットSDKを15から11に変更した後、すべてが完全に機能します。

sdk15では、AsyncTask.StatusがRUNNINGであっても、doInBackgroundが呼び出されることはありません。私はそれがuiスレッドと関係があると思います。


現在、テストする時間がないので、否定も確認もできません。私が言えることは、私がSDK 15を使用していたということだけです。
SeruK、2012

0

Matthieuの回答に基づいて、アプリケーションのコードの重複を回避するために、SDKバージョンに応じて正しく実行するヘルパークラスを以下に示しAsyncTaskます。

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;

public class AsyncTaskExecutor<Params, Progress, Result> {

  @SuppressLint("NewApi")
  public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
      return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    }  else{
      return asyncTask.execute(params);
    }
  }

}

使用例:

public class MyTask extends AsyncTask<Void, Void, List<String>> {

...

final MyTask myTask = new MyTask();
new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.