Дождитесь выполнения AsyncTask с ProgressDialog

У меня есть метод public void writeEntry(Activity ctx, Entry entry), который получает некоторые данные и должен вызывать собственный метод, выполнение которого занимает больше времени.
Поэтому я создал AsyncTask, который обрабатывает ProgressDialog и родной метод. Он отлично работает в собственной Activity для тестирования, в этой Activity я использовал интерфейс обратного вызова и так далее.

В моем случае у меня есть описанный выше метод, и мне нужно выполнить AsyncTask. Выполнение не может быть в этом методе, потому что это не останавливает дальнейшее выполнение.
Мне нужен результат от собственного метода, прежде чем я смогу продолжить выполнение.
Есть ли возможность дождаться < em>AsyncTask до завершения? Метод wait() не подходит, потому что поток пользовательского интерфейса тоже будет ждать, поэтому смысл ProgressDialog будет потерян.

Могу ли я использовать метод runOnUiThread() из заданных параметров или это единственное решение для запуска собственной Activity?


person CSchulz    schedule 17.06.2011    source источник
comment
там, где? Меня смущает описание деятельности. Не могли бы вы написать имена, а не использовать их, чтобы мы знали, сколько различных действий мы рассматриваем, в противном случае просто дайте соответствующие коды в своем вопросе :)   -  person TeaCupApp    schedule 18.06.2011
comment
Я отредактировал вопрос. Надеюсь, теперь все понятно. В общем есть только основная Activity, которая вызывает метод writeEntry().   -  person CSchulz    schedule 18.06.2011
comment
Я пытался понять это. Итак, в основном у вас есть метод wrtieEntry, который выполняет AsyncTask, но выполнение этого кода (writeEntry) продолжается. Но вы хотите, чтобы этот код ждал, пока асинхронная задача завершит свою работу. Я прав?   -  person TeaCupApp    schedule 18.06.2011
comment
Да, ты прав. Я думаю, что AsyncTask для этого не подходит.   -  person CSchulz    schedule 18.06.2011
comment
Ну, вся концепция наличия AsyncTask заключается в том, чтобы ваш текущий поток работал и выполнял какой-то процесс в фоновом режиме. Что я предложу, так это в моем ответе;)   -  person TeaCupApp    schedule 18.06.2011


Ответы (2)


так что постараюсь объяснить как смогу

Начните свой тяжелый процесс внутри AsyncTask, но любой код, который вы хотите выполнить после завершения AsyncTask, поместите его в отдельный общедоступный метод. Теперь, когда вы закончите свой тяжелый процесс, вызовите этот отдельно созданный метод в onPostExecute().

Таким образом, псевдокод будет выглядеть следующим образом:

class main extends Activity {

    class Something extends AsyncTask<String, Integer, String> {

        protected void onPreExecute() {
            // Start your progress bar...
        }

        protected String doInBackground(String... params) {
            // Do your heavy stuff...
            return null;
        }

        protected void onPostExecute(String result) {
            // close your progress dialog and than call method which has
            // code you are wishing to execute after AsyncTask.
        }
    }

}

Надеюсь, это поможет,

Удачи!

person TeaCupApp    schedule 18.06.2011
comment
Как я могу дождаться с этим фрагментом кода результата AsyncTask без зависания потока пользовательского интерфейса? - person CSchulz; 18.06.2011

Моим первым решением было использовать методы обратного вызова с реализацией интерфейса, см. пример https://stackoverflow.com/a/6396376/390177.

Поболтав некоторое время в чате Android, я узнал, что есть более практичное решение.
Вы можете использовать IntentService в сочетании с PendingIntent.
Связь реализуется с помощью Intent.
Если вы хотите использовать ProgressDialog, вам нужна для него собственная Activity, которая зарегистрируйте, например, BroadcastReciever, и IntentService отправит ему фактический статус для каждой трансляции.

Но давайте начнем сейчас.
Сначала мы создаем Activity, содержащую ProgressDialog и зарегистрированный BroadcastReceiver. BroadcastReceiver прослушивает сообщения об обновлении и завершении диалога.

Для Activity нам нужен макет...

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:background="#80000000">
</LinearLayout>

... и соответствующий код:

public class ProgressActivity extends Activity {
    /**
     * ProgressDialog which is shown
     */
    private ProgressDialog progessDialog_g;

    /**
     * Instance of the BroadcastReceiver
     */
    private BroadcastReceiver receiver_g;

    /**
     * Identifier for the different settings of the ProgressDialog
     */
    public static final String PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR = "pbar_horizontal_bar";
    public static final String PROGRESS_DIALOG_BOOL_CANCELABLE = "pbar_horizontal_cancelable";
    public static final String PROGRESS_DIALOG_STR_MESSAGE = "pbar_message";
    public static final String PROGRESS_DIALOG_INT_MAX = "pbar_max_bar";
    public static final String PROGRESS_DIALOG_INT_VALUE = "pbar_value";
    protected static final int PROGRESS_DIALOG_INT_MAX_VALUE = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        setContentView(R.layout.progress);

        progessDialog_g = new ProgressDialog(this);

        // Reads and sets the settings for the ProgressDialog
        Intent i = getIntent();
        progessDialog_g.setCancelable(i.getBooleanExtra(
                PROGRESS_DIALOG_BOOL_CANCELABLE, false));
        if (i.getBooleanExtra(
                PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, false)) {
            progessDialog_g.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        } else {
            progessDialog_g.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        }
        progessDialog_g
                .setMessage(i
                        .getStringExtra(PROGRESS_DIALOG_STR_MESSAGE));
        progessDialog_g.setMax(i.getIntExtra(
                PROGRESS_DIALOG_INT_MAX, 100));

        // Create the IntentFilter for the different broadcast messages
        IntentFilter iFilter =
                new IntentFilter(
                        ExampleProgressService.PROGRESS_DIALOG_BROADCAST_INIT);
        iFilter.addAction(ExampleProgressService.PROGRESS_DIALOG_BROADCAST_UPDATE);
        iFilter.addAction(ExampleProgressService.PROGRESS_DIALOG_BROADCAST_FINISH);

        // Creates the BroadcastReceiver
        receiver_g = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent){
                Log.d(DefaultPreferences.DEBUG_PREFIX + "ProgressActivity",
                        intent.getAction());

                if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_INIT
                        .equals(intent.getAction())) {
                    // Sets the ProgressDialog style
                    if (intent
                            .getBooleanExtra(
                                    PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR,
                                    false)) {
                        progessDialog_g
                                .setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                    } else {
                        progessDialog_g
                                .setProgressStyle(ProgressDialog.STYLE_SPINNER);
                    }

                    // Shows the ProgressDialog    
                    progessDialog_g.show();
                } else if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_UPDATE
                        .equals(intent.getAction())) {
                    // Updates the ProgressDialog
                    int value =
                            intent.getIntExtra(
                                    PROGRESS_DIALOG_INT_VALUE,
                                    -1);
                    if (value != -1) {
                        progessDialog_g.setProgress(value);
                    }
                } else if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_FINISH
                        .equals(intent.getAction())) {
                    // Finishs the ProgressDialog
                    progessDialog_g.cancel();
                    finish();
                }
            }
        };

        // Registers the BroadcastReceiver
        registerReceiver(receiver_g, iFilter);
    }

    @Override
    protected void onDestroy(){
        unregisterReceiver(receiver_g);
        super.onDestroy();
    }
}

Теперь мы хотим использовать Activity, поэтому давайте начнем с ее вызова:

final Intent i = new Intent(parentActivity, <packages>.ProgressActivity);
i.putExtra(ProgressActivity.PROGRESS_DIALOG_BOOL_CANCELABLE, cancelable_g);
i.putExtra(ProgressActivity.PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, showProgress_g);
i.putExtra(ProgressActivity.PROGRESS_DIALOG_STR_MESSAGE, message_g);
i.putExtra(ProgressActivity.PROGRESS_DIALOG_INT_MAX, ProgressActivity.PROGRESS_DIALOG_INT_MAX_VALUE);

parentActivity.startActivity(i);

Итак, у нас есть работающая ProgressActivity, которая ожидает различных трансляций. Но сначала нам нужен IntentService, который отправляет широковещательные сообщения.
Итак, приступим:

public class ExampleProgressService extends IntentService {
    /**
     * PendingIntent for callback.
     */
    protected PendingIntent pi_g = null;

    private static final String DEBUG_TAG = "ExampleProgressService";

    /**
     * Message identifier for ProgressDialog init
     */
    public static final String PROGRESS_DIALOG_BROADCAST_INIT = "Dialog.Progress.Init";
    /**
     * Message identifier for ProgressDialog finish
     */
    public static final String PROGRESS_DIALOG_BROADCAST_FINISH = "Dialog.Progress.Finish";
    /**
     * Message identifier for ProgressDialog update
     */
    public static final String PROGRESS_DIALOG_BROADCAST_UPDATE = "Dialog.Progress.Update";

    /**
     * Identifier of the result for intent content
     */
    public static final String PROGRESS_DATA_RESULT = "Result";
    /**
     * Identifier of the result error for intent content
     */
    public static final String PROGRESS_DATA_RESULT_ERROR_MESSAGE = "Result.Error.Message";
    /**
     * Identifier of the result error exception for intent content
     */
    public static final String PROGRESS_DATA_RESULT_ERROR_EXCEPTION = "Result.Error.Exception";
    /**
     * Identifier of the result status for intent content
     */
    public static final String PROGRESS_DATA_RESULT_STATUS_BOOL = "Result.Status.boolean";

    /**
     * Identifier of the pending intent for intent content
     */
    public static final String PROGRESS_DATA_PENDING_RESULT = "PendingResult";

    public ExampleProgressService() {
        super("ExampleProgressService");
    }

    /**
     * Send the finish message.
     */
    private void closeProgressActivity() {
        Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_FINISH);

        sendBroadcast(intent);
    }

    /**
     * Do some magic with the intent content
     */
    private void extractVariablesFromIntentAndPrepare(Intent intent)
            throws Exception {
        pi_g = (PendingIntent) intent
                .getParcelableExtra(PROGRESS_DATA_PENDING_RESULT);

        if (pi_g == null) {
            throw new Exception("There is no pending intent!");
    }

    /**
     * Sends an error message.
     */
    private void failed(Exception e, String message) {
        Intent i = new Intent();
        i.putExtra(PROGRESS_DATA_RESULT_ERROR_EXCEPTION, e);
        i.putExtra(PROGRESS_DATA_RESULT_ERROR_MESSAGE, message);

        send(i, false);
    }

    /**
     * Sends the init message.
     */
    private void initProgressActivity() {
        Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_INIT);

        intent.putExtra(PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR,
                multipart_g);

        sendBroadcast(intent);
    }

    /**
     * (non-Javadoc)
     * 
     * @see android.app.IntentService#onHandleIntent(android.content.Intent)
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        extractVariablesFromIntentAndPrepare(intent);

        initProgressActivity();

        // do your calculation here and implements following code
        Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_UPDATE);

        intent.putExtra(PROGRESS_DIALOG_INT_VALUE, progressValue);

        sendBroadcast(intent);

        // If you finished, use one of the two methods to send the result or an error
        success(result);
        failed(exception, optionalMessage);
    }

    /**
     * Sends the data to the calling Activity
     */
    private void send(Intent resultData, boolean status) {
        resultData.putExtra(PROGRESS_DATA_RESULT_STATUS_BOOL, status);

        closeProgressActivity();

        try {
            pi_g.send(this, Activity.RESULT_OK, resultData);
        } catch (PendingIntent.CanceledException e) {
            Log.e(DEBUG_TAG,
                    "There is something wrong with the pending intent", e);
        }
    }

    /**
     * Sends the result message.
     */
    private void success(String result) {
        Intent i = new Intent();
        i.putExtra(PROGRESS_DATA_RESULT, result);

        send(i, true);
    }
}

Результат выполнения вычислений должен быть доступен в parentActivity, поэтому мы создаем PendingIntent в этом Activity и вызываем IntentService< /эм>.

// Some identifier for the call
int requestCode = 12345;

final Intent sI = new Intent(ExampleProgressService.PROGRESS_SERVICE_ACTION);

// Callback
sI.putExtra(ExampleProgressService.PROGRESS_DATA_PENDING_RESULT, parentActivity
        .createPendingResult(requestCode, null,
                PendingIntent.FLAG_CANCEL_CURRENT));

// Service start
parentActivity.startService(sI);

Для получения результатов нам необходимо переопределить метод onActivityResult(int requestCode, int resultCode, Intent data).

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
    // Compares the requestCode with the requestCode from above
    if (requestCode == ...) {
        if (data.getBooleanExtra(ExampleProgressService.PROGRESS_DATA_RESULT_STATUS_BOOL, false)) {
            // Calculation was success
            data.getStringExtra(ExampleProgressService.PROGRESS_DATA_RESULT);
        } else
        {
            // Calculation is failed
            data.getStringExtra(ExampleProgressService.PROGRESS_DATA_RESULT_ERROR_MESSAGE);
            ((Exception) data.getSerializableExtra(ExampleProgressService.PROGRESS_DATA_RESULT_ERROR_EXCEPTION));
        }
    }
}

Это была магия, надеюсь, она вам поможет.

person CSchulz    schedule 27.06.2011