AsyncTask завершается неудачей, когда я поворачиваю устройство в альбомную ориентацию


У меня есть деятельность,в которой у меня есть ProgressBar, ImageView и TextView, я обновляю все три из AsyncTask.Все три обновляются, когда экран полностью находится в одной ориентации, когда выполняется задача, но ImageView и TextView не отображаются, а ProgressBar зависает, когда ориентация экрана меняется с одной ориентации на другую.

Добавление методов attach и detach к задаче и использование методов retainNonConfigurationInstance для возврата задачи, когда Activity и использование методов getLastNonConfigurationInstance уничтожены, не имело эффект.Я также реализовал три метода для получения различных значений прогресса из AsyncTask без эффекта.

Моя активность выглядит так:

    static final String TAG="ImageUpdateActivity";
TextView txt_currentOp;
ImageView img_currentOp;
ImageUpdatingTask task;
CustomProgressBar updatebar;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_imageupdate);
    txt_currentOp=(TextView)findViewById(R.id.txt_currentOp);
    img_currentOp=(ImageView)findViewById(R.id.img_updateOp);
    updatebar=(CustomProgressBar)findViewById(R.id.progressbar_update);
    String filename=getIntent().getStringExtra("pathName");
    task=(ImageUpdatingTask)getLastNonConfigurationInstance();
    if(task!=null)
    {
        task.attach(this);
        if(task.getStatus()==AsyncTask.Status.RUNNING)
        {   
            Log.d(TAG, "The progress description is: "+task.getProgressDesc());
            txt_currentOp.setText(task.getProgressDesc());
            img_currentOp.setImageBitmap(task.getProgressBitmap());
            updatebar.setProgress(task.getProgress());
        }
    }
    else
    {
        task=new ImageUpdatingTask(this);
        task.execute(filename);
    }
}

public Object retainNonConfigurationInstance()
{
    task.detach();
    return task;
}

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
        if(task.getStatus()!=AsyncTask.Status.FINISHED)
        {
            task.cancel(true);
            task=null;
        }
        Intent i=new Intent(this,ImagePreviewActivity.class);
        startActivity(i);
    }
    return super.onKeyDown(keyCode, event);
}

Вот как я обновляю прогресс из моего метода doInBackground, где

 int progress=0;
 Bitmap progressBitmap=null;
 String progressDesc=null;

Являются глобальными переменными.

 mOperation=BITMAP_TO_PIX;
    progressDesc=getValueFromOperation(mOperation);
    Pix pix=convertBitmapToPix(bitmap);
    mOperation=CONVERT_TO_8;
    progressDesc=getValueFromOperation(mOperation);
    Pix pix2=convertOperation(pix);
    temp=pix2.copy();
    tempImg=convertPixToBitmap(temp);
    progressBitmap=tempImg;
    temp=null;
    progress+=10;//60
    publishProgress(tempImg);

И в моем publishProgress я использую:

   @Override
protected void onProgressUpdate(Bitmap... values) {
// TODO Auto-generated method stub
    super.onProgressUpdate(values);
    int oldOperation=0,oldProgress=0;
    if(mOperation!=oldOperation)
    {
        String progressText=getValueFromOperation(mOperation);
        Log.d(TAG, progressText);
        activity.txt_currentOp.setText(progressText);
        oldOperation=mOperation;
    }
    if(oldProgress!=progress)
    {
        Log.d(TAG,"Update the progress: "+progress);
        activity.updatebar.setProgress(progress);
        oldProgress=progress;
    }

    activity.img_currentOp.setImageBitmap(values[0]);
}

И действие, передается задаче с помощью конструктора:

  public ImageUpdatingTask(ImageUpdateActivity activity)
{
    this.activity=activity;
}

Это методы, которые заботятся о взаимодействии между AsyncTask и the Activity:

   public void attach(ImageUpdateActivity activity)
{
    this.activity=activity;
}

public void detach()
{
    activity=null;
}

    public int getProgress()
{
    return progress;
}

public Bitmap getProgressBitmap()
{
    return progressBitmap;
}

public String getProgressDesc()
{
    return progressDesc;
}
1 2

1 ответ:

При изменении ориентации ваша активность разрушается и воссоздается. Фрагменты размещаются действием.

По умолчанию фрагменты уничтожаются и воссоздаются вместе с их родительской активностью, когда происходит изменение конфигурации. Вызов фрагментов setRetainInstance(true) позволяет нам обойти этот цикл разрушения и воссоздания, сигнализируя системе, чтобы сохранить текущий экземпляр фрагмента, когда действие будет воссоздано.

public void setRetainInstance (boolean retain)

Added in API level 11
Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
onCreate(Bundle) will not be called since the fragment is not being re-created.
onAttach(Activity) and onActivityCreated(Bundle) will still be called.

Вы можете проверить этот блог на предмет предложенного обходного пути . Использует интерфейс в качестве обратного вызова к действию.

Http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

И исходный код для него доступен по адресу

Https://github.com/alexjlockwood/worker-fragments

Цитата из блога

Поток событий

Когда MainActivity запускается в первый раз, он создает экземпляр и добавляет фрагмент задачи в состояние действия. Фрагмент Задачи создает и выполняет AsyncTask и прокси-серверы обновления прогресса и результаты обратно в MainActivity через интерфейс TaskCallbacks. Когда происходит изменение конфигурации, MainActivity проходит через свои обычные события жизненного цикла, и после создания новый экземпляр Activity передается методу onAttach (Activity), таким образом гарантируя, что TaskFragment всегда будет содержать ссылку на текущий отображаемый экземпляр Activity даже после изменения конфигурации. Полученная конструкция одновременно проста платформа приложений будет обрабатывать переназначение экземпляров активности по мере их удаления и повторного создания, а TaskFragment и его AsyncTask никогда не должны беспокоиться о непредсказуемом возникновении изменений конфигурации.