org.jraf.android.util.async.TaskFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.jraf.android.util.async.TaskFragment.java

Source

/*
 * This source is part of the
 *      _____  ___   ____
 *  __ / / _ \/ _ | / __/___  _______ _
 * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/
 * \___/_/|_/_/ |_/_/ (_)___/_/  \_, /
 *                              /___/
 * repository.
 *
 * Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jraf.android.util.async;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;

import org.jraf.android.util.Constants;
import org.jraf.android.util.dialog.ProgressDialogFragment;
import org.jraf.android.util.handler.HandlerUtil;

/**
 * A non UI {@link Fragment} that executes a task in the background.<br/>
 * A {@link ProgressDialogFragment} is shown while the task is running for at least a few milliseconds.
 */
@SuppressLint("ValidFragment")
public class TaskFragment extends Fragment {
    private static final String TAG = Constants.TAG + TaskFragment.class.getSimpleName();
    private static final String FRAGMENT_TAG_PREFIX = TaskFragment.class.getName() + ".FRAGMENT_TAG.";

    private static final int DELAY_SHOW_PROGRESS_DIALOG = 250; // ms

    private static int sCounter = 0;

    private Task<?> mTask;
    private boolean mTaskStarted;
    private volatile boolean mTaskFinished;
    private Exception mCallerStackTrace;

    public TaskFragment() {
    }

    public TaskFragment(Task<?> task) {
        mTask = task;
        mTask.setFragment(this);
        mCallerStackTrace = new Exception();
    }

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

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (!mTaskStarted && mTask != null) {
            mTaskStarted = true;
            startTask();
        }
    }

    private void startTask() {
        AsyncTask<Void, Void, Boolean> asyncTask = new AsyncTask<Void, Void, Boolean>() {
            @Override
            public void onPreExecute() {
                mTask.onPreExecute();
                HandlerUtil.getMainHandler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // This will happen after a small delay, so we must check that the task hasn't already finished,
                        // and that the fragment is still added.
                        Log.d(TAG, "onPreExecute mTaskFinished=" + mTaskFinished);
                        if (!mTaskFinished && isResumed()) {
                            ProgressDialogFragment progressDialogFragment = new ProgressDialogFragment();
                            progressDialogFragment.show(getFragmentManager(), ProgressDialogFragment.FRAGMENT_TAG);
                        }
                    }
                }, DELAY_SHOW_PROGRESS_DIALOG);
            }

            @Override
            protected Boolean doInBackground(Void... params) {
                try {
                    mTask.doInBackground();
                } catch (Throwable t) {
                    Log.w(TAG, "doInBackground", t);
                    Log.w(TAG, "Caller stack trace: ", mCallerStackTrace);
                    return false;
                }
                return true;
            }

            @Override
            protected void onPostExecute(Boolean ok) {
                Log.d(TAG, "onPostExecute ok=" + ok);
                mTaskFinished = true;
                FragmentManager fragmentManager = getFragmentManager();
                if (fragmentManager != null) {
                    fragmentManager.executePendingTransactions();
                    DialogFragment dialogFragment = (DialogFragment) getFragmentManager()
                            .findFragmentByTag(ProgressDialogFragment.FRAGMENT_TAG);
                    if (dialogFragment != null)
                        dialogFragment.dismissAllowingStateLoss();
                }
                if (isAdded()) {
                    if (ok) {
                        mTask.onPostExecuteOk();
                    } else {
                        mTask.onPostExecuteFail();
                    }
                }
                if (fragmentManager != null)
                    fragmentManager.beginTransaction().remove(TaskFragment.this).commitAllowingStateLoss();
            }
        };
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            executeHoneycomb(asyncTask);
        } else {
            asyncTask.execute();
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void executeHoneycomb(AsyncTask<Void, Void, Boolean> asyncTask) {
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public void execute(FragmentManager fragmentManager) {
        fragmentManager.beginTransaction().add(this, getUniqueFragmentTag()).commitAllowingStateLoss();
    }

    private String getUniqueFragmentTag() {
        return FRAGMENT_TAG_PREFIX + System.currentTimeMillis() + "." + sCounter++;
    }
}