web-dev-qa-db-ja.com

AsyncTask doInBackgroundが実行されません

AsyncTaskクラスに問題があります。 4つまたは5つのタスクを作成した後、タスクが機能しなくなったようです。

私は2つの活動をしています。 ImageActivityと呼ばれる2番目のアクティビティを開始するボタンのみを保持するMainActivity。

ImageActivityは非常に簡単です。レイアウトを設定するonCreateを取得し、インターネットから画像をロードする新しいAsyncTaskを開始します。これは最初の数回は問題なく動作します。しかし、それが突然機能しなくなります。 onPreExecuteメソッドは毎回実行されますが、doInBackgroundメソッドは実行されません。スリープループでdoInBackgroundを単純化しようとしましたが、同じことが起こります。 onDestroyメソッドでasynctaskがキャンセルされ、nullに設定されているため、この動作を理解できません。したがって、新しいImageActivityを開始するたびに、新しいAsyncTaskも作成します。

ImageActivityとタスクを再作成するには、戻るボタンを押して、MainActivityのボタンをクリックします。

アイデアはありますか?私はこれに本当に苦労しています。

更新:ImageActivityを開始するコード(ボタンonClickListener内)

Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setClassName(this, ImageActivity.class.getName());
startActivity(intent);

上記のコードはこのアクティビティを開始します

    public class ImageActivity extends Activity {

    private AsyncTask<Void, Void, Void> task;

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        task = new AsyncTask<Void, Void, Void>() {

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

            @Override
            protected Void doInBackground(Void... params)
            {
                Log.d(TAG, "doInBackground() -- Here is the download");
                // downloadBitmap("http://mydomain.com/image.jpg")
                return null;
            }

            @Override
            protected void onPostExecute(Void res)
            {
                Log.d(TAG, "onPostExecute()");
                if(isCancelled()){
                    return;
                }
            }
        }.execute();
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        task.cancel(true);
    }
}

更新:

従来のThreadsメソッドとrunOnUiThreadメソッドの組み合わせを使用してテストしましたが、うまく機能しているようです。現在、スレッドは毎回実行されます。

34
Vidar Vestnes

AsyncTaskを削除し、runOnUiThreadと組み合わせる代わりに従来のスレッドを使用すると、動作するようです。しかし、AsyncTaskがそれほど「不安定」である理由はまだわかりません。

ここに私のために働くコードがあります:

public class ImageActivity extends Activity {

    private Thread worker;

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        worker = new Thread(new Runnable(){

            private void updateUI(final List<Object> list)
            {
                if(worker.isInterrupted()){
                    return;
                }
                runOnUiThread(new Runnable(){

                    @Override
                    public void run()
                    {
                        // Update view and remove loading spinner etc...
                    }
                });
            }

            private List<Object> download()
            {
                // Simulate download
                SystemClock.sleep(1000);
                return new ArrayList<Object>();
            }

            @Override
            public void run()
            {
                Log.d(TAG, "Thread run()");
                updateUI(download());
            }

        });
        worker.start(); }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        worker.interrupt();
    }
}
24
Vidar Vestnes

私は同様の問題に遭遇しました。 SDK 11までは、複数のAsynctasksを並行して実行することはできません。チェック 詳細はこちら

7
ericwjr

私もこの問題に遭遇しました。 AsyncTask.executeを使用する場合、タスクはシリアルキューで実行されます(Android 4.3ソースから):

最初に導入されたとき、AsyncTasksは単一のバックグラウンドスレッドでシリアルに実行されました。 DONUTから、これはスレッドのプールに変更され、複数のタスクを並行して操作できるようになりました。 HONEYCOMB以降、タスクは単一のスレッドで実行され、並列実行による一般的なアプリケーションエラーを回避します。

これは私が見た動作と一致しています。 AsyncTaskdoInBackgroundにダイアログをポップアップし、ダイアログが閉じるまでブロックしました。ダイアログを完了するには、独自のAsyncTaskが必要でした。元のAsyncTaskがまだブロックされているため、ダイアログのAsyncTask.doInBackgroundメソッドは実行されませんでした。

解決策は、別のAsyncTaskで2番目のExecutorを実行することです。

6
Heath Borders

Traceviewを使用して調査するか、スレッドダンプを取得します。私の推測では、AsyncTaskスレッドの1つがダウンロードを停止しています。

AsyncTaskには小さなスレッドプールがあるため、タスクの1つがハングすると、スレッドプールがブロックされる可能性があります。

実行できる簡単なテストを次に示します。4.3では、実行できる並行スレッドは5つしかありません。 1つのスレッドが終了すると、他のスレッドが起動します。

  private void testAsyncTasks() {

        for (int i = 1; i <= 10; i++) {
              final int tid = i;
              new AsyncTask<Integer, Void, Void>() {
                    protected void onPreExecute() {
                          Log.d("ASYNCTASK", "Pre execute for task : " + tid);
                    };

                    @Override
                    protected Void doInBackground(Integer... args) {
                          int taskid = args[0];
                          long started = SystemClock.elapsedRealtime();
                          Log.d("ASYNCTASK", "Executing task: " + taskid + " at " + started);
                          for (int j = 1; j <= 20; j++) {
                                Log.d("ASYNCTASK", "   task " + taskid + ", time=" + (SystemClock.elapsedRealtime() - started));
                                SystemClock.sleep(1000);
                          }
                          return null;
                    }

                    protected void onPostExecute(Void result) {
                          Log.d("ASYNCTASK", "Post execute for task : " + tid);
                    };
              }.execute(i);

        }
  }
1
DustinB

私が信じる問題は、重いイメージのダウンロードタスクにあります。非同期タスクをキャンセルしても、イメージのダウンロードは引き続き実行され、ダウンロードが完了するまで非同期タスクは終了しません。ダウンロードの進行中にAyncTaskのisCancelled()メソッドを確認し、タスクがキャンセルされた場合はダウンロードを強制終了することができます。

参照用に、cancel()メソッドのドキュメントを次に示します。このタスクの実行をキャンセルしようとします。タスクが既に完了している場合、キャンセルされている場合、または他の理由でキャンセルできなかった場合、この試行は失敗します。成功し、キャンセルが呼び出されたときにこのタスクが開始されていない場合、このタスクは実行されません。タスクがすでに開始されている場合、mayInterruptIfRunningパラメーターは、タスクを停止しようとしてこのタスクを実行しているスレッドを中断する必要があるかどうかを決定します。このメソッドを呼び出すと、doInBackground(Object [])が返された後にonCancelled(Object)がUIスレッドで呼び出されます。このメソッドを呼び出すと、onPostExecute(Object)が呼び出されないことが保証されます。このメソッドを呼び出した後、isCancelled()によってdoInBackground(Object [])から定期的に返される値をチェックして、タスクをできるだけ早く終了する必要があります。

0
habib

Androidのハウスキーピングスレッドはシステムによって管理されているため、心配する必要はありません。

画像のダウンロード方法も投稿してください。 onDestroy()メソッドでスレッドをキャンセルしないようにしましたか?画像をUIスレッドにどのように返しますか?

0

私にもこれがありました、開始しない本当の理由はありません。私はadbを再起動した後、それが再び機能することに気づきました。これがなぜかはわかりませんが、私にとってはうまくいきました

0
Alex