Question

I have an Activity in which I have a ProgressBar,an ImageView and a TextView,I update all three from an AsyncTask.All three get updated when the screen is completely in one orientation when the task is running,but the ImageView and TextView are not displayed and the ProgressBar freezes when the screen orientation changes from one orientation to another.

Adding the attach and detach methods to the task and using retainNonConfigurationInstance to return the task when the Activity and using getLastNonConfigurationInstance is destroyed has had no effect.I have also implement three methods for getting the various progress values from the AsyncTask to no effect.

MyActivity looks like this:

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

This is how I update the progress from my doInBackground method where

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

are global variables.

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

And in my publishProgress I use:

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

And the Activity,is passed to the task using the constructor:

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

These are the methods that take care of interaction between the AsyncTask and 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;
}
Was it helpful?

Solution

When orientation changes your activity gets is destroyed and recreated. Fragments are hosted by an activity.

By default, Fragments are destroyed and recreated along with their parent Activitys when a configuration change occurs. Calling Fragments setRetainInstance(true) allows us to bypass this destroy-and-recreate cycle, signaling the system to retain the current instance of the fragment when the activity is recreated.

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.

You can check this blog for a workaround suggested . Uses interface as callback to the activity.

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

and the source code for the same is available at

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

Quoting from the blog

Flow of Events

When the MainActivity starts up for the first time, it instantiates and adds the TaskFragment to the Activity's state. The TaskFragment creates and executes an AsyncTask and proxies progress updates and results back to the MainActivity via the TaskCallbacks interface. When a configuration change occurs, the MainActivity goes through its normal lifecycle events, and once created the new Activity instance is passed to the onAttach(Activity) method, thus ensuring that the TaskFragment will always hold a reference to the currently displayed Activity instance even after the configuration change. The resulting design is both simple and reliable; the application framework will handle re-assigning Activity instances as they are torn down and recreated, and the TaskFragment and its AsyncTask never need to worry about the unpredictable occurrence of a configuration change.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top