android - 当我将设备旋转到横向时,AsyncTask 失败

标签 android android-asynctask screen-rotation

我有一个 Activity,其中有一个 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;
}

最佳答案

当方向改变时,您的 Activity 将被破坏并重新创建。 fragment 由 Activity 托管。

默认情况下,当配置发生更改时,Fragment 会与其父 Activity 一起被销毁并重新创建。调用 Fragments setRetainInstance(true) 允许我们绕过这个销毁和重新创建循环,向系统发出信号以在重新创建 Activity 时保留 Fragment 的当前实例。

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)作为 Activity 的回调。

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

其源代码位于

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

引自博客

事件流程

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

关于android - 当我将设备旋转到横向时,AsyncTask 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19949013/

相关文章:

android - 从 firebase 获取所有 child (用户)但向一个 child (用户)显示按钮?

android - android中的异步任务与线程

javascript - IE11(Windows Phone 8.1)无法感应(显示尺寸)屏幕旋转?

android - 如何在屏幕旋转期间处理 AsyncTask?

ios - GLKit的-drawRect : is not called during screen rotation

android - kotlin.TypeCastException : null cannot be cast to non-null type android. support.v7.widget.Toolbar

android - 将 Phonegap Build 2.1 与 Phonegap 版本 2.2 结合使用

java - Android在ActionBarActivity中接收广播

android - 使用 AsyncTask 启动 Activity

android - AsyncTask 已弃用?使用什么方法代替 onPreExecute 和 onPostExecute?