Android Open Source - GreenDroid Item Adapter






From Project

Back to project page GreenDroid.

License

The source code is released under:

Apache License

If you think the Android project GreenDroid 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

/*
 * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
 *//from   www. j a  va2 s .  com
 * 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 greendroid.widget;

import greendroid.widget.item.DescriptionItem;
import greendroid.widget.item.DrawableItem;
import greendroid.widget.item.Item;
import greendroid.widget.item.LongTextItem;
import greendroid.widget.item.ProgressItem;
import greendroid.widget.item.SeparatorItem;
import greendroid.widget.item.SubtextItem;
import greendroid.widget.item.SubtitleItem;
import greendroid.widget.item.TextItem;
import greendroid.widget.item.ThumbnailItem;
import greendroid.widget.itemview.ItemView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

/**
 * <p>
 * A ListAdapter that acts like an ArrayAdapter. An ItemAdapter manages a
 * ListView that is backed by an array of {@link Item}s. This is more advanced
 * than a simple ArrayAdapter because it handles different types of itemviews
 * internally. Adding, removing items from the internal array is also possible.
 * </p>
 * <p>
 * The ListView can be notified of underlying data changes manually using
 * notifyDataSetChanged or automatically using the
 * {@link #setNotifyOnChange(boolean)} method.
 * </p>
 * <p>
 * Finally, an ItemAdapter can be created via XML code using the
 * {@link #createFromXml(Context, int)} method. This is a very powerful feature
 * when you want to display static data or if you want to pre-populate your
 * ItemAdapter.
 * </p>
 * 
 * @author Cyril Mottier
 */
public class ItemAdapter extends BaseAdapter {

    private static final int DEFAULT_MAX_VIEW_TYPE_COUNT = 10;

    private static class TypeInfo {
        int count;
        int type;
    }

    private List<Item> mItems;
    private HashMap<Class<? extends Item>, TypeInfo> mTypes;
    private Context mContext;

    private boolean mNotifyOnChange;
    private int mMaxViewTypeCount;

    /**
     * Constructs an empty ItemAdapter.
     * 
     * @param context The context associated with this array adapter.
     */
    public ItemAdapter(Context context) {
        this(context, new ArrayList<Item>());
    }

    /**
     * Constructs an ItemAdapter using the specified items.
     * <p>
     * <em><strong>Note</strong>: Using this constructor implies the internal array will be
     * immutable. As a result, adding or removing items will result in an
     * exception.</em>
     * </p>
     * 
     * @param context The context associated with this array adapter.
     * @param items The array of {@link Item}s use as underlying data for this
     *            ItemAdapter
     */
    public ItemAdapter(Context context, Item[] items) {
        this(context, Arrays.asList(items), DEFAULT_MAX_VIEW_TYPE_COUNT);
    }

    /**
     * Constructs an ItemAdapter using the specified items.
     * <p>
     * 
     * @param context The context associated with this array adapter.
     * @param items The list of {@link Item}s used as data for this ItemAdapter
     */
    public ItemAdapter(Context context, List<Item> items) {
        this(context, items, DEFAULT_MAX_VIEW_TYPE_COUNT);
    }

    /**
     * Constructs an ItemAdapter using the specified items.
     * <p>
     * <em><strong>Note</strong>: Using this constructor implies the internal array will be
     * immutable. As a result, adding or removing items will result in an
     * exception.</em>
     * </p>
     * <p>
     * <em><strong>Note</strong>: A ListAdapter doesn't handle variable view type 
     * count (even after a notifyDataSetChanged). An ItemAdapter handles several 
     * types of cell are therefore use a trick to overcome the previous problem.
     * This trick is to fool the ListView several types exist. If you already
     * know the number of item types you'll possibly have, simply set it using this method</em>
     * </p>
     * 
     * @param context The context associated with this array adapter.
     * @param items The array of {@link Item}s use as underlying data for this
     *            ItemAdapter
     * @param maxViewTypeCount The maximum number of view type that may be
     *            generated by this ItemAdapter
     */
    public ItemAdapter(Context context, Item[] items, int maxViewTypeCount) {
        this(context, Arrays.asList(items), maxViewTypeCount);
    }

    /**
     * Constructs an ItemAdapter using the specified items.
     * <p>
     * <em><strong>Note:</strong> A ListAdapter doesn't handle variable view type 
     * count (even after a notifyDataSetChanged). An ItemAdapter handles several 
     * types of cell are therefore use a trick to overcome the previous problem.
     * This trick is to fool the ListView several types exist. If you already
     * know the number of item types you'll possibly have, simply set it using this method</em>
     * </p>
     * 
     * @param context The context associated with this array adapter.
     * @param items The list of Items used as data for this ItemAdapter
     * @param maxViewTypeCount The maximum number of view type that may be
     *            generated by this ItemAdapter
     */
    public ItemAdapter(Context context, List<Item> items, int maxViewTypeCount) {
        mContext = context;
        mItems = items;
        mTypes = new HashMap<Class<? extends Item>, TypeInfo>();
        mMaxViewTypeCount = Integer.MAX_VALUE;

        for (Item item : mItems) {
            addItem(item);
        }

        mMaxViewTypeCount = Math.max(1, Math.max(mTypes.size(), maxViewTypeCount));
    }

    private void addItem(Item item) {
        final Class<? extends Item> klass = item.getClass();
        TypeInfo info = mTypes.get(klass);

        if (info == null) {
            final int type = mTypes.size();
            if (type >= mMaxViewTypeCount) {
                throw new RuntimeException("This ItemAdapter may handle only " + mMaxViewTypeCount + " different view types.");
            }
            final TypeInfo newInfo = new TypeInfo();
            newInfo.count = 1;
            newInfo.type = type;
            mTypes.put(klass, newInfo);
        } else {
            info.count++;
        }
    }

    private void removeItem(Item item) {
        final Class<? extends Item> klass = item.getClass();
        TypeInfo info = mTypes.get(klass);

        if (info != null) {
            info.count--;
            if (info.count == 0) {
                // TODO cyril: Creating a pool to keep all TypeInfo instances
                // could be a great idea in the future.
                mTypes.remove(klass);
            }
        }
    }

    /**
     * Returns the context associated with this array adapter. The context is
     * used to create Views from the resource passed to the constructor.
     * 
     * @return The Context associated to this ItemAdapter
     */
    public Context getContext() {
        return mContext;
    }

    /**
     * Returns the current number of different views types used in this
     * ItemAdapter. Having a <em>getCurrentViewTypeCount</em> equal to
     * <em>getViewTypeCount</em> means you won't be able to add a new type of
     * view in this adapter (The Adapter class doesn't allow variable view type
     * count).
     * 
     * @return The current number of different view types
     */
    public int getActualViewTypeCount() {
        return mTypes.size();
    }

    /**
     * Adds the specified object at the end of the array.
     * 
     * @param item The object to add at the end of the array.
     */
    public void add(Item item) {
        mItems.add(item);
        addItem(item);
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    /**
     * Inserts the specified object at the specified index in the array.
     * 
     * @param item The object to insert into the array.
     * @param index The index at which the object must be inserted.
     */
    public void insert(Item item, int index) {
        mItems.add(index, item);
        addItem(item);
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    /**
     * Removes the specified object from the array.
     * 
     * @param item The object to remove.
     */
    public void remove(Item item) {
        if (mItems.remove(item)) {
            removeItem(item);
            if (mNotifyOnChange) {
                notifyDataSetChanged();
            }
        }
    }

    /**
     * Remove all elements from the list.
     */
    public void clear() {
        mItems.clear();
        mTypes.clear();
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    /**
     * Sorts the content of this adapter using the specified comparator.
     * 
     * @param comparator The comparator used to sort the objects contained in
     *            this adapter.
     */
    public void sort(Comparator<? super Item> comparator) {
        Collections.sort(mItems, comparator);
        if (mNotifyOnChange) {
            notifyDataSetChanged();
        }
    }

    /**
     * Control whether methods that change the list ({@link #add},
     * {@link #insert}, {@link #remove}, {@link #clear}) automatically call
     * notifyDataSetChanged(). If set to false, caller must manually call
     * notifyDataSetChanged() to have the changes reflected in the attached
     * view. The default is true, and calling notifyDataSetChanged() resets the
     * flag to true.
     * 
     * @param notifyOnChange if true, modifications to the list will
     *            automatically call notifyDataSetChanged()
     */
    public void setNotifyOnChange(boolean notifyOnChange) {
        mNotifyOnChange = notifyOnChange;
    }

    /**
     * Creates an ItemAdapter from a given resource ID
     * 
     * @param context The Context in which the ItemAdapter will be used in
     * @param xmlId The resource ID of an XML file that describes a set of
     *            {@link Item}
     * @return a new ItemAdapter constructed with the content of the file
     *         pointed by <em>xmlId</em>
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static ItemAdapter createFromXml(Context context, int xmlId) throws XmlPullParserException, IOException {
        return createFromXml(context, context.getResources().getXml(xmlId));
    }

    /**
     * Creates an ItemAdapter from a given XML document. Called on a parser
     * positioned at a tag in an XML document, tries to create an ItemAdapter
     * from that tag.
     * 
     * @param context The Context in which the ItemAdapter will be used in
     * @param parser The XmlPullParser
     * @return a new ItemAdapter constructed with the content of the file
     *         pointed by <em>xmlId</em>
     * @throws XmlPullParserException
     * @throws IOException
     */
    public static ItemAdapter createFromXml(Context context, XmlPullParser parser) throws XmlPullParserException, IOException {
        AttributeSet attrs = Xml.asAttributeSet(parser);

        int type;
        while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
            // Empty loop
        }

        if (type != XmlPullParser.START_TAG) {
            throw new XmlPullParserException("No start tag found");
        }

        if (!parser.getName().equals("item-array")) {
            throw new XmlPullParserException("Unknown start tag. Should be 'item-array'");
        }

        final List<Item> items = new ArrayList<Item>();
        final int innerDepth = parser.getDepth() + 1;
        final Resources r = context.getResources();

        int depth;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            if (depth > innerDepth) {
                continue;
            }

            String name = parser.getName();
            Item item;
            if (name.equals("text-item")) {
                item = new TextItem();
            } else if (name.equals("longtext-item")) {
                item = new LongTextItem();
            } else if (name.equals("description-item")) {
                item = new DescriptionItem();
            } else if (name.equals("separator-item")) {
                item = new SeparatorItem();
            } else if (name.equals("progress-item")) {
                item = new ProgressItem();
            } else if (name.equals("drawable-item")) {
                item = new DrawableItem();
            } else if (name.equals("subtitle-item")) {
                item = new SubtitleItem();
            } else if (name.equals("subtext-item")) {
                item = new SubtextItem();
            } else if (name.equals("thumbnail-item")) {
                item = new ThumbnailItem();
            } else {
                // TODO cyril: Remove that so that we can extend from
                // ItemAdapter and creates our own items via XML?
                throw new XmlPullParserException(parser.getPositionDescription() + ": invalid item tag " + name);
            }

            // TODO cyril: Here we should call a method that children may
            // override to be able to create our own Items

            if (item != null) {
                item.inflate(r, parser, attrs);
                items.add(item);
            }
        }

        return new ItemAdapter(context, items);
    }

    public int getCount() {
        return mItems.size();
    }

    public Object getItem(int position) {
        return mItems.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemViewType(int position) {
        return mTypes.get(getItem(position).getClass()).type;
    }

    @Override
    public boolean isEnabled(int position) {
        return ((Item) getItem(position)).enabled;
    }

    @Override
    public int getViewTypeCount() {
        return mMaxViewTypeCount;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        final Item item = (Item) getItem(position);
        ItemView cell = (ItemView) convertView;

        if (cell == null) {
            cell = item.newView(mContext, null);
            cell.prepareItemView();
        }

        cell.setObject(item);

        return (View) cell;
    }

}




Java Source Code List

com.cyrilmottier.android.gdcatalog.AboutActivity.java
com.cyrilmottier.android.gdcatalog.ActionBarActivity.java
com.cyrilmottier.android.gdcatalog.AsyncImageViewListActivity.java
com.cyrilmottier.android.gdcatalog.BasicItemActivity.java
com.cyrilmottier.android.gdcatalog.CatalogActivity.java
com.cyrilmottier.android.gdcatalog.CatalogApplication.java
com.cyrilmottier.android.gdcatalog.InfoTabActivity.java
com.cyrilmottier.android.gdcatalog.MapPinMapActivity.java
com.cyrilmottier.android.gdcatalog.PagedViewActivity.java
com.cyrilmottier.android.gdcatalog.QuickActionActivity.java
com.cyrilmottier.android.gdcatalog.SegmentedActivity.java
com.cyrilmottier.android.gdcatalog.SimpleAsyncImageViewActivity.java
com.cyrilmottier.android.gdcatalog.TabbedActionBarActivity.java
com.cyrilmottier.android.gdcatalog.TweakedItemViewActivity.java
com.cyrilmottier.android.gdcatalog.WebContentActivity.java
com.cyrilmottier.android.gdcatalog.XmlItemActivity.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItemView.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItem.java
greendroid.app.ActionBarActivity.java
greendroid.app.GDActivity.java
greendroid.app.GDApplication.java
greendroid.app.GDExpandableListActivity.java
greendroid.app.GDListActivity.java
greendroid.app.GDMapActivity.java
greendroid.app.GDTabActivity.java
greendroid.graphics.drawable.ActionBarDrawable.java
greendroid.graphics.drawable.DrawableStateSet.java
greendroid.graphics.drawable.MapPinDrawable.java
greendroid.image.ChainImageProcessor.java
greendroid.image.ImageCache.java
greendroid.image.ImageLoader.java
greendroid.image.ImageProcessor.java
greendroid.image.ImageRequest.java
greendroid.image.MaskImageProcessor.java
greendroid.image.ScaleImageProcessor.java
greendroid.util.Config.java
greendroid.util.GDUtils.java
greendroid.util.Md5Util.java
greendroid.util.Time.java
greendroid.widget.ActionBarHost.java
greendroid.widget.ActionBarItem.java
greendroid.widget.ActionBar.java
greendroid.widget.AsyncImageView.java
greendroid.widget.ItemAdapter.java
greendroid.widget.LoaderActionBarItem.java
greendroid.widget.NormalActionBarItem.java
greendroid.widget.PageIndicator.java
greendroid.widget.PagedAdapter.java
greendroid.widget.PagedView.java
greendroid.widget.QuickActionBar.java
greendroid.widget.QuickActionGrid.java
greendroid.widget.QuickActionWidget.java
greendroid.widget.QuickAction.java
greendroid.widget.SegmentedAdapter.java
greendroid.widget.SegmentedBar.java
greendroid.widget.SegmentedHost.java
greendroid.widget.item.DescriptionItem.java
greendroid.widget.item.DrawableItem.java
greendroid.widget.item.Item.java
greendroid.widget.item.LongTextItem.java
greendroid.widget.item.ProgressItem.java
greendroid.widget.item.SeparatorItem.java
greendroid.widget.item.SubtextItem.java
greendroid.widget.item.SubtitleItem.java
greendroid.widget.item.TextItem.java
greendroid.widget.item.ThumbnailItem.java
greendroid.widget.itemview.DescriptionItemView.java
greendroid.widget.itemview.DrawableItemView.java
greendroid.widget.itemview.ItemView.java
greendroid.widget.itemview.LongTextItemView.java
greendroid.widget.itemview.ProgressItemView.java
greendroid.widget.itemview.SeparatorItemView.java
greendroid.widget.itemview.SubtextItemView.java
greendroid.widget.itemview.SubtitleItemView.java
greendroid.widget.itemview.TextItemView.java
greendroid.widget.itemview.ThumbnailItemView.java