【问题标题】:The AsyncTask fails when I rotate the device to landscape当我将设备旋转到横向时,AsyncTask 失败
【发布时间】:2013-11-13 08:37:33
【问题描述】:

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

在任务中添加attachdetach方法并在Activity被销毁时使用retainNonConfigurationInstance返回任务并使用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;
}

【问题讨论】:

  • androiddesignpatterns.com/2013/04/…。看看这个是否有帮助
  • @Raghunandan 如何实现 onCancelled。我想在按下后退键时取消...而是移至另一个活动
  • 另外,帖子似乎没有使用super.onPreExecutesuper.onProgressUpdatesuper.onPostExecute
  • dwonload 源修改它以满足您的需要。 github.com/alexjlockwood/worker-fragments。你明白了。现在以您想要的方式处理问题。
  • 哇哦,它有效。谢谢伙计,将其发布为答案,我会接受它。

标签: android android-asynctask screen-rotation


【解决方案1】:

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

默认情况下,当配置发生更改时,Fragment 会与它们的父 Activity 一起被销毁并重新创建。调用 Fragments 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 第一次启动时,它会实例化 TaskFragment 并将其添加到 Activity 的状态中。 TaskFragment 创建并执行 AsyncTask 并通过 TaskCallbacks 接口将进度更新和结果代理回 MainActivity。当配置发生更改时,MainActivity 会经历其正常的生命周期事件,并且一旦创建新的 Activity 实例就会传递给 onAttach(Activity) 方法,从而确保 TaskFragment 将始终持有对当前显示的 Activity 实例的引用,即使之后配置更改。由此产生的设计既简单又可靠;应用程序框架将在 Activity 实例被拆除和重新创建时处理它们的重新分配,并且 TaskFragment 及其 AsyncTask 永远不需要担心配置更改的不可预知的发生。

【讨论】:

    猜你喜欢
    • 2010-11-12
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 1970-01-01
    相关资源
    最近更新 更多