package edu.gatech.oad.rocket.findmythings.list; import android.app.ListFragment; import android.app.LoaderManager; import android.content.Loader; import android.os.Bundle; import android.view.*; import edu.gatech.oad.rocket.findmythings.R; import edu.gatech.oad.rocket.findmythings.util.ToastHelper; import java.util.List; /** * A type-parametrized List Fragment that asynchronously loads content with a progress bar. * User: zw * Date: 4/13/13 * Time: 7:04 PM */ public abstract class ArrayListFragment<T> extends ListFragment implements LoaderManager.LoaderCallbacks<List<T>> { private static final String FORCE_REFRESH = "forceRefresh"; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getLoaderManager().initLoader(0, null, this); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setListAdapter(onCreateAdapter()); setListShown(false); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public void onCreateOptionsMenu(Menu optionsMenu, MenuInflater inflater) { inflater.inflate(R.menu.fragment_arraylist, optionsMenu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (isUnavailable()) return false; switch (item.getItemId()) { case R.id.refresh: forceRefresh(); return true; default: return super.onOptionsItemSelected(item); } } /** * Force a refresh of the items displayed ignoring any cached items */ protected void forceRefresh() { Bundle bundle = new Bundle(); bundle.putBoolean(FORCE_REFRESH, true); refresh(bundle); } /** * @param args * bundle passed to the loader by the LoaderManager * @return true if the bundle indicates a requested forced refresh of the * items */ protected static boolean isForceRefresh(Bundle args) { return args != null && args.getBoolean(FORCE_REFRESH, false); } private void refresh(final Bundle args) { if (isUnavailable()) return; setListShown(false); if (isForceRefresh(args)) { getListAdapter().clear(); } getLoaderManager().restartLoader(0, args, this); } /** * Refresh the fragment's list */ public void refresh() { refresh(null); } public void onLoadFinished(Loader<List<T>> loader, List<T> items) { Exception exception = getException(loader); if (exception != null) { showError(getErrorMessage(exception)); setListShown(true); return; } if (items != null) { getListAdapter().addAll(items); } setListShown(true); } /** * Is this fragment still part of an activity and usable from the UI-thread? * * @return true if usable on the UI-thread, false otherwise */ protected boolean isUnavailable() { return getActivity() == null; } /** * Show exception in a Toast * * @param message An error string expressed from a resource value */ protected void showError(final int message) { ToastHelper.showLong(getActivity(), message); } /** * Get exception from loader if it provides one by being a * {@link ThrowableAsyncTaskLoader} * * @param loader The loader being used and to check for an exception using * @return exception or null if none provided */ protected Exception getException(final Loader<List<T>> loader) { if (loader instanceof ThrowableAsyncTaskLoader) return ((ThrowableAsyncTaskLoader<List<T>>) loader).popLastException(); else return null; } /** * Set empty text on list fragment * * @param resId An Android resource ID to set the empty text string using */ protected void setEmptyText(final int resId) { setEmptyText(getString(resId)); } /** * Get error message to display for exception * * @param exception The exception to process * @return string resource id */ protected abstract int getErrorMessage(Exception exception); /** * Create adapter to display items * * @return adapter */ protected abstract ArrayListAdapter<T> onCreateAdapter(); /** * Get list adapter * * @return list adapter */ @SuppressWarnings("unchecked") public ArrayListAdapter<T> getListAdapter() { return (ArrayListAdapter<T>)super.getListAdapter(); } /** * Set list adapter to use on list view * * @param adapter Provide an adapter for the list view. */ public void setListAdapter(final ArrayListAdapter<T> adapter) { super.setListAdapter(adapter); } @Override public void onLoaderReset(Loader<List<T>> loader) {} }