Android Open Source - CATaZine-Live Cursor Loader Expandable List Adapter






From Project

Back to project page CATaZine-Live.

License

The source code is released under:

GNU General Public License

If you think the Android project CATaZine-Live listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.melegy.catazine.adapter;
/*from  w  w w  .ja  v  a  2  s . c  o  m*/
import com.melegy.catazine.Constants;

import android.app.Activity;
import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Pair;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;


/**
 * A fairly simple ExpandableListAdapter that creates views defined in an XML file. You can specify the XML file that defines the appearance of the views.
 */
public abstract class CursorLoaderExpandableListAdapter extends BaseExpandableListAdapter {
    private static final String URI_ARG = "uri";
    private final Activity mActivity;
    private final LoaderManager mLoaderMgr;
    private final Uri mGroupUri;

    private final int mCollapsedGroupLayout;
    private final int mExpandedGroupLayout;
    private final int mChildLayout;
    private final LayoutInflater mInflater;

    private Cursor mGroupCursor;
    /**
     * The map of a group position to the group's children cursor
     */
    private final SparseArray<Pair<Cursor, Boolean>> mChildrenCursors = new SparseArray<Pair<Cursor, Boolean>>();

    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            CursorLoader cursorLoader = new CursorLoader(mActivity, mGroupUri, null, null, null, null) {

                @Override
                public Cursor loadInBackground() {
                    Cursor c = super.loadInBackground();
                    onCursorLoaded(mActivity, c);
                    return c;
                }

            };
            cursorLoader.setUpdateThrottle(Constants.UPDATE_THROTTLE_DELAY);
            return cursorLoader;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            mGroupCursor = data;
            setAllChildrenCursorsAsObsolete();
            notifyDataSetChanged();
            notifyDataSetChanged(data);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            mGroupCursor = null;
            setAllChildrenCursorsAsObsolete();
            notifyDataSetInvalidated();
        }
    };

    private void setAllChildrenCursorsAsObsolete() {
        int key;
        for (int i = 0; i < mChildrenCursors.size(); i++) {
            key = mChildrenCursors.keyAt(i);
            mChildrenCursors.put(key, new Pair<Cursor, Boolean>(mChildrenCursors.get(key).first, true));
        }
    }

    private final LoaderManager.LoaderCallbacks<Cursor> mChildrenLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            CursorLoader cursorLoader = new CursorLoader(mActivity, (Uri) args.getParcelable(URI_ARG), null, null, null, null) {

                @Override
                public Cursor loadInBackground() {
                    Cursor c = super.loadInBackground();
                    onCursorLoaded(mActivity, c);
                    return c;
                }

            };
            cursorLoader.setUpdateThrottle(Constants.UPDATE_THROTTLE_DELAY);
            return cursorLoader;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            mChildrenCursors.put(loader.getId() - 1, new Pair<Cursor, Boolean>(data, false));
            notifyDataSetChanged();
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            mChildrenCursors.delete(loader.getId() - 1);
            notifyDataSetInvalidated();
        }
    };

    /**
     * Constructor.
     *
     * @param collapsedGroupLayout resource identifier of a layout file that defines the views for collapsed groups.
     * @param expandedGroupLayout  resource identifier of a layout file that defines the views for expanded groups.
     * @param childLayout          resource identifier of a layout file that defines the views for all children but the last..
     */
    public CursorLoaderExpandableListAdapter(Activity activity, Uri groupUri, int collapsedGroupLayout, int expandedGroupLayout, int childLayout) {
        mActivity = activity;
        mLoaderMgr = activity.getLoaderManager();
        mGroupUri = groupUri;

        mCollapsedGroupLayout = collapsedGroupLayout;
        mExpandedGroupLayout = expandedGroupLayout;
        mChildLayout = childLayout;

        mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mLoaderMgr.restartLoader(0, null, mGroupLoaderCallback);
    }

    /**
     * Constructor.
     *
     * @param groupLayout resource identifier of a layout file that defines the views for all groups.
     * @param childLayout resource identifier of a layout file that defines the views for all children.
     */
    public CursorLoaderExpandableListAdapter(Activity activity, Uri groupUri, int groupLayout, int childLayout) {
        this(activity, groupUri, groupLayout, groupLayout, childLayout);
    }

    /**
     * Makes a new child view to hold the data pointed to by cursor.
     *
     * @param parent The parent to which the new view is attached to
     * @return the newly created view.
     */
    public View newChildView(ViewGroup parent) {
        return mInflater.inflate(mChildLayout, parent, false);
    }

    /**
     * Makes a new group view to hold the group data pointed to by cursor.
     *
     * @param isExpanded Whether the group is expanded.
     * @param parent     The parent to which the new view is attached to
     * @return The newly created view.
     */
    public View newGroupView(boolean isExpanded, ViewGroup parent) {
        return mInflater.inflate((isExpanded) ? mExpandedGroupLayout : mCollapsedGroupLayout, parent, false);
    }

    /**
     * Gets the Cursor for the children at the given group. Subclasses must implement this method to return the children data for a particular group.
     * <p/>
     * If you want to asynchronously query a provider to prevent blocking the UI, it is possible to return null and at a later time call setChildrenCursor(int, Cursor).
     * <p/>
     * It is your responsibility to manage this Cursor through the Activity lifecycle. It is a good idea to use {@link Activity#managedQuery} which will handle this for you. In some situations, the
     * adapter will deactivate the Cursor on its own, but this will not always be the case, so please ensure the Cursor is properly managed.
     *
     * @param groupCursor The cursor pointing to the group whose children cursor should be returned
     * @return The cursor for the children of a particular group, or null.
     */
    abstract protected Uri getChildrenUri(Cursor groupCursor);

    @Override
    public Cursor getChild(int groupPosition, int childPosition) {
        // Return this group's children Cursor pointing to the particular child
        Pair<Cursor, Boolean> childCursor = mChildrenCursors.get(groupPosition);
        if (childCursor != null && !childCursor.first.isClosed()) {
            childCursor.first.moveToPosition(childPosition);
            return childCursor.first;
        }

        return null;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        Pair<Cursor, Boolean> childrenCursor = mChildrenCursors.get(groupPosition);
        if (childrenCursor != null && !childrenCursor.first.isClosed() && childrenCursor.first.moveToPosition(childPosition)) {
            return childrenCursor.first.getLong(childrenCursor.first.getColumnIndex("_id"));
        }

        return 0;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        Pair<Cursor, Boolean> cursor = mChildrenCursors.get(groupPosition);
        if (cursor == null || cursor.first.isClosed() || !cursor.first.moveToPosition(childPosition)) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }

        View v;
        if (convertView == null) {
            v = newChildView(parent);
        } else {
            v = convertView;
        }
        bindChildView(v, mActivity, cursor.first);
        return v;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        Pair<Cursor, Boolean> childCursor = mChildrenCursors.get(groupPosition);

        // We need to restart the loader
        if ((childCursor == null || childCursor.second) && mGroupCursor != null && !mGroupCursor.isClosed() && mGroupCursor.moveToPosition(groupPosition)) {
            Bundle args = new Bundle();
            args.putParcelable(URI_ARG, getChildrenUri(mGroupCursor));
            mLoaderMgr.restartLoader(groupPosition + 1, args, mChildrenLoaderCallback);
        }

        if (childCursor != null && !childCursor.first.isClosed()) {
            return childCursor.first.getCount();
        }

        return 0;
    }

    @Override
    public Cursor getGroup(int groupPosition) {
        // Return the group Cursor pointing to the given group
        if (mGroupCursor != null && !mGroupCursor.isClosed()) {
            mGroupCursor.moveToPosition(groupPosition);
        }
        return mGroupCursor;
    }

    @Override
    public int getGroupCount() {
        if (mGroupCursor != null && !mGroupCursor.isClosed()) {
            return mGroupCursor.getCount();
        }

        return 0;
    }

    @Override
    public long getGroupId(int groupPosition) {
        if (mGroupCursor != null && !mGroupCursor.isClosed() && mGroupCursor.moveToPosition(groupPosition)) {
            return mGroupCursor.getLong(mGroupCursor.getColumnIndex("_id"));
        }

        return 0;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        if (mGroupCursor == null || mGroupCursor.isClosed() || !mGroupCursor.moveToPosition(groupPosition)) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }

        View v;
        if (convertView == null) {
            v = newGroupView(isExpanded, parent);
        } else {
            v = convertView;
        }
        bindGroupView(v, mActivity, mGroupCursor, isExpanded);
        return v;
    }

    /**
     * Bind an existing view to the group data pointed to by cursor.
     *
     * @param view       Existing view, returned earlier by newGroupView.
     * @param context    Interface to application's global information
     * @param cursor     The cursor from which to get the data. The cursor is already moved to the correct position.
     * @param isExpanded Whether the group is expanded.
     */
    protected abstract void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded);

    /**
     * Bind an existing view to the child data pointed to by cursor
     *
     * @param view    Existing view, returned earlier by newChildView
     * @param context Interface to application's global information
     * @param cursor  The cursor from which to get the data. The cursor is already moved to the correct position.
     */
    protected abstract void bindChildView(View view, Context context, Cursor cursor);

    /**
     * Called on the background thread just after loaded the cursor
     *
     * @param context Interface to application's global information
     * @param cursor  The cursor from which to get the data.
     */
    protected abstract void onCursorLoaded(Context context, Cursor cursor);

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public void onGroupCollapsed(int groupPosition) {
        mLoaderMgr.destroyLoader(groupPosition + 1);
        mChildrenCursors.delete(groupPosition);
    }

    /**
     * Notifies a data set change.
     *
     * @param data the new cursor
     */
    public void notifyDataSetChanged(Cursor data) {
    }
}




Java Source Code List

com.melegy.catazine.Constants.java
com.melegy.catazine.MainApplication.java
com.melegy.catazine.activity.AboutActivity.java
com.melegy.catazine.activity.BaseActivity.java
com.melegy.catazine.activity.EntryActivity.java
com.melegy.catazine.activity.GeneralPrefsActivity.java
com.melegy.catazine.activity.HomeActivity.java
com.melegy.catazine.adapter.CursorLoaderExpandableListAdapter.java
com.melegy.catazine.adapter.DrawerAdapter.java
com.melegy.catazine.adapter.EntriesCursorAdapter.java
com.melegy.catazine.adapter.FeedsCursorAdapter.java
com.melegy.catazine.fragment.EntriesListFragment.java
com.melegy.catazine.fragment.EntryFragment.java
com.melegy.catazine.loader.BaseLoader.java
com.melegy.catazine.parser.OPML.java
com.melegy.catazine.parser.RssAtomParser.java
com.melegy.catazine.provider.DatabaseHelper.java
com.melegy.catazine.provider.FeedDataContentProvider.java
com.melegy.catazine.provider.FeedData.java
com.melegy.catazine.receiver.BootCompletedBroadcastReceiver.java
com.melegy.catazine.receiver.ConnectionChangeReceiver.java
com.melegy.catazine.service.FetcherService.java
com.melegy.catazine.service.RefreshService.java
com.melegy.catazine.utils.ArticleTextExtractor.java
com.melegy.catazine.utils.HtmlUtils.java
com.melegy.catazine.utils.NetworkUtils.java
com.melegy.catazine.utils.PrefUtils.java
com.melegy.catazine.utils.StringUtils.java
com.melegy.catazine.utils.ThrottledContentObserver.java
com.melegy.catazine.utils.UiUtils.java
com.melegy.catazine.view.DragNDropExpandableListView.java
com.melegy.catazine.view.DragNDropListener.java
com.melegy.catazine.view.EntryView.java
com.melegy.catazine.widget.ColorPickerDialogPreference.java
com.melegy.catazine.widget.TickerWidgetProvider.java
com.melegy.catazine.widget.WidgetConfigActivity.java
com.melegy.catazine.widget.WidgetProvider.java
com.melegy.catazine.widget.WidgetService.java