/*
* 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.support.v7.app.AppCompatActivity;
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 optionally 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;
private boolean mShowProgressDialog;
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();
if (mShowProgressDialog) {
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, boolean showProgressDialog) {
mShowProgressDialog = showProgressDialog;
fragmentManager.beginTransaction().add(this, getUniqueFragmentTag()).commitAllowingStateLoss();
}
public void execute(FragmentManager fragmentManager) {
execute(fragmentManager, true);
}
public void execute(AppCompatActivity activity, boolean showProgressDialog) {
execute(activity.getSupportFragmentManager(), showProgressDialog);
}
public void execute(AppCompatActivity activity) {
execute(activity.getSupportFragmentManager());
}
private String getUniqueFragmentTag() {
return FRAGMENT_TAG_PREFIX + System.currentTimeMillis() + "." + sCounter++;
}
}