将设备旋转到横向时,AsyncTask失败

时间:2013-11-13 08:37:34

标签: android android-asynctask screen-rotation

我有一个活动,其中我有一个ProgressBar,一个ImageView和一个TextView,我从AsyncTask更新所有三个。这三个都在任务运行时,屏幕完全处于一个方向,但当屏幕方向从一个方向更改为另一个方向时,ImageViewTextView不会显示,ProgressBar会冻结。

attachdetach方法添加到任务中,并在retainNonConfigurationInstance和使用Activity被销毁时使用getLastNonConfigurationInstance返回任务效果。我还实现了三种方法,用于获取从AsyncTask到无效的各种进度值。

MyActivity看起来像这样:

    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]);
}

使用构造函数将Activity传递给任务:

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

这些是处理AsyncTaskActivity之间互动的方法:

   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 个答案:

答案 0 :(得分:2)

当方向更改时,您的活动获取将被销毁并重新创建。片段由活动托管。

默认情况下,在发生配置更改时,会破坏并重新创建片段及其父活动。调用片段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.

您可以查看此博客,了解建议的解决方法。使用interface作为活动的回调。

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

可以在

获得相同的源代码

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

从博客引用

活动流程

当MainActivity第一次启动时,它会实例化TaskFragment并将其添加到Activity的状态。 TaskFragment通过TaskCallbacks接口创建并执行AsyncTask和代理进度更新并将结果返回到MainActivity。当发生配置更改时,MainActivity会经历其正常的生命周期事件,并且一旦创建,新的Activity实例就会传递给onAttach(Activity)方法,从而确保TaskFragment始终保持对当前显示的Activity实例的引用,即使之后配置更改。由此产生的设计既简单又可靠;应用程序框架将处理重新分配活动实例,因为它们被拆除并重新创建,而TaskFragment及其AsyncTask永远不必担心配置更改的不可预测的发生。