88

インスタンスの状態を保存する方法や、画面の回転中にアクティビティが破壊された場合の対処方法について、よく読んでいます。

多くの可能性があるようですが、AsyncTask の結果を取得するのに最適な方法はわかりません。

私は単に再び開始され、アクティビティのメソッドを呼び出すいくつかの AsyncTasks を持っていますisFinishing()。アクティビティが終了している場合、それらは何も更新しません。

問題は、失敗または成功する可能性のある Web サービスへの要求を行う 1 つのタスクがあり、タスクを再起動するとユーザーに経済的損失が生じることです。

これをどのように解決しますか?考えられる解決策の長所と短所は何ですか?

4

13 に答える 13

46

code.google.com/p/shelvesAsyncTaskで、私がs と向きの変更を処理する方法を確認できます。これにはさまざまな方法がありますが、このアプリで選択したのは、現在実行中のタスクをキャンセルし、その状態を保存して、新しいタスクが作成されたときに保存された状態で新しいタスクを開始することです。それは簡単で、うまく機能し、ボーナスとして、ユーザーがアプリを離れたときにタスクを停止します。Activity

を使用して新しいものonRetainNonConfigurationInstance()に渡すこともできます (ただし、この方法で前のものを漏らさないように注意してください)。AsyncTaskActivityActivity

于 2010-04-12T18:57:54.867 に答える
10

これは、Android に関して私が見た中で最も興味深い質問です!!! 実際、私は過去数か月間、すでに解決策を探していました。まだ解決していません。

単純にオーバーライドすることに注意してください

android:configChanges="keyboardHidden|orientation"

ものが足りない。

AsyncTask の実行中にユーザーが電話を受けた場合を考えてみましょう。リクエストはサーバーによってすでに処理されているため、AsyncTask は応答を待っています。この時点で、電話アプリがフォアグラウンドになったばかりなので、アプリはバックグラウンドになります。OS はバックグラウンドにあるため、アクティビティを強制終了する可能性があります。

于 2010-04-12T18:22:50.873 に答える
7

私の最初の提案は、実際に画面の回転時にアクティビティをリセットする必要があることを確認することです (デフォルトの動作)。ローテーションで問題が発生するたびに、この属性を<activity>AndroidManifest.xml のタグに追加しましたが、問題ありませんでした。

android:configChanges="keyboardHidden|orientation"

それは奇妙に見えますが、それがあなたのメソッドに何を渡すonConfigurationChanged()か、あなたがそれを提供しない場合、レイアウトを再測定する以外に何もしません。 .

于 2010-04-12T09:25:14.907 に答える
6

Android が提供する Singleton で現在の AsyncTask への参照を常に保持しないのはなぜですか?

PreExecute またはビルダーでタスクが開始されるたびに、以下を定義します。

((Application) getApplication()).setCurrentTask(asyncTask);

それが終了するたびに、それを null に設定します。

そうすれば、特定のロジックに応じて onCreate や onResume などを実行できる参照が常に得られます。

this.asyncTaskReference = ((Application) getApplication()).getCurrentTask();

null の場合、現在何も実行されていないことがわかります。

:-)

于 2011-04-19T18:13:29.253 に答える
3

onRetainNonConfigurationInstance私の見解では、現在の Activity オブジェクトから切り離し、向きの変更後に新しい Activity オブジェクトにバインドすることで、asynctask を保存する方が良いでしょう。ここで、AsyncTask と ProgressDialog を使用する方法の非常に優れた例を見つけました。

于 2012-07-05T08:16:59.510 に答える
3

Pro android 4。著者は、あなたが使用すべき良い方法を提案していますweak reference

弱い参考書

于 2012-03-22T04:21:07.330 に答える
2

Android : バックグラウンド処理/構成変更による非同期操作

バックグラウンド プロセス中に非同期操作の状態を維持するには、フラグメントを利用できます。

次の手順を参照してください。

ステップ 1: ヘッダーなしのフラグメントを作成し、たとえばバックグラウンド タスクを作成し、その中にプライベート非同期タスク クラスを追加します。

ステップ 2 (オプションのステップ): アクティビティの上にローディング カーソルを置きたい場合は、以下のコードを使用します。

ステップ 3: メイン アクティビティで、ステップ 1 で定義した BackgroundTaskCallbacks インターフェイスを実装します。

class BackgroundTask extends Fragment {
public BackgroundTask() {

}

// Add a static interface 

static interface BackgroundTaskCallbacks {
    void onPreExecute();

    void onCancelled();

    void onPostExecute();

    void doInBackground();
}

private BackgroundTaskCallbacks callbacks;
private PerformAsyncOpeation asyncOperation;
private boolean isRunning;
private final String TAG = BackgroundTask.class.getSimpleName();

/**
 * Start the async operation.
 */
public void start() {
    Log.d(TAG, "********* BACKGROUND TASK START OPERATION ENTER *********");
    if (!isRunning) {
        asyncOperation = new PerformAsyncOpeation();
        asyncOperation.execute();
        isRunning = true;
    }
    Log.d(TAG, "********* BACKGROUND TASK START OPERATION EXIT *********");
}

/**
 * Cancel the background task.
 */
public void cancel() {
    Log.d(TAG, "********* BACKGROUND TASK CANCEL OPERATION ENTER *********");
    if (isRunning) {
        asyncOperation.cancel(false);
        asyncOperation = null;
        isRunning = false;
    }
    Log.d(TAG, "********* BACKGROUND TASK CANCEL OPERATION EXIT *********");
}

/**
 * Returns the current state of the background task.
 */
public boolean isRunning() {
    return isRunning;
}

/**
 * Android passes us a reference to the newly created Activity by calling
 * this method after each configuration change.
 */
public void onAttach(Activity activity) {
    Log.d(TAG, "********* BACKGROUND TASK ON ATTACH ENTER *********");
    super.onAttach(activity);
    if (!(activity instanceof BackgroundTaskCallbacks)) {
        throw new IllegalStateException(
                "Activity must implement the LoginCallbacks interface.");
    }

    // Hold a reference to the parent Activity so we can report back the
    // task's
    // current progress and results.
    callbacks = (BackgroundTaskCallbacks) activity;
    Log.d(TAG, "********* BACKGROUND TASK ON ATTACH EXIT *********");
}

public void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "********* BACKGROUND TASK ON CREATE ENTER *********");
    super.onCreate(savedInstanceState);
    // Retain this fragment across configuration changes.
    setRetainInstance(true);
    Log.d(TAG, "********* BACKGROUND TASK ON CREATE EXIT *********");
}

public void onDetach() {
    super.onDetach();
    callbacks = null;
}

private class PerformAsyncOpeation extends AsyncTask<Void, Void, Void> {
    protected void onPreExecute() {
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON PRE EXECUTE ENTER *********");
        if (callbacks != null) {
            callbacks.onPreExecute();
        }
        isRunning = true;
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON PRE EXECUTE EXIT *********");
    }

    protected Void doInBackground(Void... params) {
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > DO IN BACKGROUND ENTER *********");
        if (callbacks != null) {
            callbacks.doInBackground();
        }
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > DO IN BACKGROUND EXIT *********");
        return null;
    }

    protected void onCancelled() {
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON CANCEL ENTER *********");
        if (callbacks != null) {
            callbacks.onCancelled();
        }
        isRunning = false;
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON CANCEL EXIT *********");
    }

    protected void onPostExecute(Void ignore) {
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON POST EXECUTE ENTER *********");
        if (callbacks != null) {
            callbacks.onPostExecute();
        }
        isRunning = false;
        Log.d(TAG,
                "********* BACKGROUND TASK :-> ASYNC OPERATION :- > ON POST EXECUTE EXIT *********");
    }
}

public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);
}

public void onStart() {
    super.onStart();
}

public void onResume() {
    super.onResume();
}

public void onPause() {
    super.onPause();
}

public void onStop() {
    super.onStop();
}

public class ProgressIndicator extends Dialog {

public ProgressIndicator(Context context, int theme) {
    super(context, theme);
}

private ProgressBar progressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.progress_indicator);
    this.setCancelable(false);
    progressBar = (ProgressBar) findViewById(R.id.progressBar);
    progressBar.getIndeterminateDrawable().setColorFilter(R.color.DarkBlue, android.graphics.PorterDuff.Mode.SCREEN);
}

@Override
public void show() {
    super.show();
}

@Override
public void dismiss() {
    super.dismiss();
}

@Override
public void cancel() {
    super.cancel();
}

public class MyActivity extends FragmentActivity implements BackgroundTaskCallbacks,{

private static final String KEY_CURRENT_PROGRESS = "current_progress";

ProgressIndicator progressIndicator = null;

private final static String TAG = MyActivity.class.getSimpleName();

private BackgroundTask task = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(//"set your layout here");
    initialize your views and widget here .............



    FragmentManager fm = getSupportFragmentManager();
    task = (BackgroundTask) fm.findFragmentByTag("login");

    // If the Fragment is non-null, then it is currently being
    // retained across a configuration change.
    if (task == null) {
        task = new BackgroundTask();
        fm.beginTransaction().add(task, "login").commit();
    }

    // Restore saved state
    if (savedInstanceState != null) {
        Log.i(TAG, "KEY_CURRENT_PROGRESS_VALUE ON CREATE :: "
                + task.isRunning());
        if (task.isRunning()) {
            progressIndicator = new ProgressIndicator(this,
                    R.style.TransparentDialog);
            if (progressIndicator != null) {
                progressIndicator.show();
            }
        }
    }
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    // save the current state of your operation here by saying this 

    super.onSaveInstanceState(outState);
    Log.i(TAG, "KEY_CURRENT_PROGRESS_VALUE ON SAVE INSTANCE :: "
            + task.isRunning());
    outState.putBoolean(KEY_CURRENT_PROGRESS, task.isRunning());
    if (progressIndicator != null) {
        progressIndicator.dismiss();
        progressIndicator.cancel();
    }
    progressIndicator = null;
}


private void performOperation() {

            if (!task.isRunning() && progressIndicator == null) {
                progressIndicator = new ProgressIndicator(this,
                        R.style.TransparentDialog);
                progressIndicator.show();
            }
            if (task.isRunning()) {
                task.cancel();
            } else {
                task.start();
            }
        }


@Override
protected void onDestroy() {
    super.onDestroy();
    if (progressIndicator != null) {
        progressIndicator.dismiss();
        progressIndicator.cancel();
    }
    progressIndicator = null;
}

@Override
public void onPreExecute() {
    Log.i(TAG, "CALLING ON PRE EXECUTE");
}

@Override
public void onCancelled() {
    Log.i(TAG, "CALLING ON CANCELLED");
    if (progressIndicator != null) {
        progressIndicator.dismiss();
        progressIndicator.cancel();

}

public void onPostExecute() {
    Log.i(TAG, "CALLING ON POST EXECUTE");
    if (progressIndicator != null) {
        progressIndicator.dismiss();
        progressIndicator.cancel();
        progressIndicator = null;
    }
}

@Override
public void doInBackground() {
    // put your code here for background operation
}

}

于 2013-08-23T10:58:20.180 に答える
1

この投稿を見てください。この投稿では、AsyncTask が実行時間の長い操作を実行し、画面の回転が 1 つのサンプル アプリケーションで発生したときにメモリ リークを発生させます。サンプル アプリはソース フォージで入手できます

于 2013-08-07T06:33:09.450 に答える
1

考慮すべきことの 1 つは、AsyncTask の結果を、タスクを開始したアクティビティだけが利用できるようにするかどうかです。はいの場合、Romain Guy の回答が最適です。アプリケーションの他のアクティビティで使用できる必要がある場合は、onPostExecuteを使用できますLocalBroadcastManager

LocalBroadcastManager.getInstance(getContext()).sendBroadcast(new Intent("finished"));

また、アクティビティの一時停止中にブロードキャストが送信されたときに、アクティビティが状況を正しく処理することを確認する必要があります。

于 2012-12-17T14:43:05.150 に答える
0
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    final AddTask task = mAddTask;
    if (task != null && task.getStatus() != UserTask.Status.FINISHED) {
        final String bookId = task.getBookId();
        task.cancel(true);

        if (bookId != null) {
            outState.putBoolean(STATE_ADD_IN_PROGRESS, true);
            outState.putString(STATE_ADD_BOOK, bookId);
        }

        mAddTask = null;
    }
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    if (savedInstanceState.getBoolean(STATE_ADD_IN_PROGRESS)) {
        final String id = savedInstanceState.getString(STATE_ADD_BOOK);
        if (!BooksManager.bookExists(getContentResolver(), id)) {
            mAddTask = (AddTask) new AddTask().execute(id);
        }
    }
}
于 2016-11-09T12:03:10.607 に答える