9

私とほぼ同じ質問をいくつか見ましたが、私の疑問をすべて満たす完全な答えを見つけることができませんでした。それで、ここにいます。次のAsyncTaskようなクラスを拡張する内部クラスのアクティビティがあるとします。

public class MyActivity extends Activity {            
    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { 
        protected Bitmap doInBackground(String... urls) {
            return DownloadImage(urls[0]); 
        }
        protected void onPostExecute(Bitmap result) {
            ImageView img = (ImageView) findViewById(R.id.img); 
            img.setImageBitmap(result);
        }  
    }

    @Override
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main);
        new DownloadImageTask().execute("http://mysite.com/image.png")
    }
}

がバックグラウンドで実行されている間にアクティビティが一時停止または破棄されたと仮定します(2つのケースは異なる場合があります) DownloadImageTask。次に、DownloadImageTaskアクティビティUIスレッドで実行されるのメソッドをトリガーして、DownloadImageTaskアクティビティのメソッドにアクセスしようとする場合があります(これは内部クラスであるためfindViewByID、以下の例の呼び出しのように、一時停止または破棄されたアクティビティを使用して、外部クラスのメソッドとインスタンス変数にアクセスできます。黙って失敗しますか?例外は発生しますか?何か問題が発生したことがユーザーに通知されますか?

run-on-UIメソッドが呼び出されたときに起動スレッド(この場合はアクティビティ)がまだ生きていることに注意する必要がある場合、どうすればそれを?内から実行できますAsyncTaskか?

これが重複した質問であると思われる場合は申し訳ありませんが、この質問はもう少し明確で、誰かがより詳細に回答できる可能性があります

4

2 に答える 2

3

このタスクを検討してください (R.id.test はアクティビティのレイアウトで有効なビューを参照します):

public class LongTaskTest extends AsyncTask<Void, Void, Void>{
    private WeakReference<Activity> mActivity;
    public LongTaskTest(Activity a){
        mActivity = new WeakReference<Activity>(a);
    }
    @Override protected Void doInBackground(Void... params) {
        LogUtil.d("LongTaskTest.doInBackground()");
        SystemClock.sleep(5*60*1000);
        LogUtil.d("mActivity.get()==null " + (mActivity.get()==null));
        LogUtil.d("mActivity.get().findViewById(R.id.frame)==null " + (mActivity.get().findViewById(R.id.test)==null));
        return null;
    }
}

アクティビティの onCreate からこのタスクを次のように実行すると:

public class Main extends Activity {
    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        setContentView(R.layout.testlayout);
        new LongTaskTest(this).execute();
        finish();
    }
}

バックグラウンド スレッドをどれだけ長くスリープさせても、ログには常に次のように表示されます。

LongTaskTest.doInBackground()
mActivity.get()==null false
mActivity.get().findViewById(R.id.frame)==null false

つまり、アクティビティとそのビューは存続しているように見えます (DDMS を介して手動で GC を発行したとしても)。もっと時間があればメモリダンプを見てみたいと思いますが、それ以外の場合は、なぜそうなのかはよくわかりません...しかし、あなたの質問に答えると、次のようになります。

  • 静かに失敗しますか?いいえ
  • 例外は発生しますか?いいえ
  • 何か問題が発生したことがユーザーに通知されますか? いいえ
于 2012-09-04T16:10:18.690 に答える
2

doInBackground() メソッドはワーカー/バックグラウンド スレッドで実行されるため、アクティビティが破棄された (つまり、メイン スレッドが破棄された) 場合でも、doInBackground() は実行を続けます。メイン/UI スレッドで実行される onPostExecute() メソッドの実行には「問題」があり、関連のないデータが実行される可能性がありますが、ユーザーに例外は表示されません。したがって、アクティビティが存在しなくなったときに AsyncTask を実行する理由がないため、アクティビティが破棄されたときに AsyncTask をキャンセルすることをお勧めします。コンポーネント/アクティビティが破棄された場合でも、ネットワークから何かを継続的にダウンロードしたい場合は、android サービスを使用します。ありがとう。

于 2015-04-18T10:21:33.283 に答える