Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android -Retained headless fragment

I am reading about how to interact between UI and background thread here.

This article has following note:

The AsyncTask does not handle configuration changes automatically, i.e. if the activity is recreated. The programmer has to handle that in his coding. A common solution to this is to declare the AsyncTask in a retained headless fragment.

I dont understand what is retained headless fragment.

For example, in this way I can add fragment:

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.frame, new MyFragment());
transaction.commit();

And in fragment I can execute AsyncTask like this:

MyTask myTask = new MyTask();
String[] args = {"Hello"};
myTask.execute(args);

Is this called "to declare the AsyncTask in a retained headless fragment"?

like image 402
Joe Rakhimov Avatar asked Jul 25 '16 05:07

Joe Rakhimov


1 Answers

Headless fragment is nothing but a fragment which does not have a view. In onCreate() of the fragment lifeCycle, use setRetainInstance(true);. This will not destroy the fragment even if the activity recreates. So if an AsyncTask is running in fragment, on recreation of the activity, you wont lose the AsyncTask.

In onCreate of the activity, you have to add the fragment with a tag. Before adding, check if the fragment exist using getFragmentManager().findFragmentByTag(TAG), if the fragment is null then create a new instance of the fragment and add it. In Fragment there will not be any view inflated, so no need to override onCreateView().

An example of headlessFragment :

public class HeadlessProgressFragment extends Fragment {

private ProgressListener mProgressListener;
private AsyncTask<Void, Integer, Void> mProgressTask;

public interface ProgressListener {
    void updateProgress(int progress);
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

public void setProgressListener(Context context) {
    mProgressListener = (ProgressListener) context;
}

public void startProgress(final int size) {
    if (mProgressTask == null || mProgressTask.getStatus() != AsyncTask.Status.RUNNING || mProgressTask.getStatus() == AsyncTask.Status.FINISHED) {
            mProgressTask = new AsyncTask<Void, Integer, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    for (int index = 0; index < size; index++) {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            publishProgress(index + 1);
                        }
                    }
                    return null;
                }

                @Override
                protected void onProgressUpdate(Integer... values) {
                    super.onProgressUpdate(values);
                    if (mProgressListener != null) {
                        mProgressListener.updateProgress(values[0]);
                    }
                }
            };
            mProgressTask.execute();
        }
    }
}

In Activity Something like this :

public class MainActivity extends FragmentActivity implements HeadlessProgressFragment.ProgressListener {

private static final String TAG = "progress_fragment";
private ProgressBar mProgressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.dummy_view);
    mHeadlessProgressFragment = (HeadlessProgressFragment) getSupportFragmentManager().findFragmentByTag(TAG);
    if (mHeadlessProgressFragment == null) {
        mHeadlessProgressFragment = new HeadlessProgressFragment();
        getSupportFragmentManager().beginTransaction().add(mHeadlessProgressFragment,TAG).commit();
    }
    mHeadlessProgressFragment.setProgressListener(this);
    mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
    final Button startFillBtn = (Button) findViewById(R.id.btn_start_filling);
    startFillBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mHeadlessProgressFragment.startProgress(100);
        }
    });
}

    @Override
    public void updateProgress(int progress) {
        mProgressBar.setProgress(progress);
    }
}
like image 56
Akshay Bhat 'AB' Avatar answered Nov 11 '22 00:11

Akshay Bhat 'AB'