Advanced-Adapters

A suite of adapters designed to provide alternatives to Android’s provided adapters. From standard ArrayAdapters to RolodexAdapters (sectioned adapters); They provide customizable filtering solutions which can be safely mutated during any filtering operation. Don’t need filtering? No problem, we have those specific kind as well.

All the adapters created were meant to fill the void where you need to build a custom adapter from scratch but don’t want to worry about the data management part. Below are some code examples with simple explanations of what they provide.

FILTERABLE ADAPTERS

Compared to Android’s ArrayAdapter:

  • Filtering Logic You provide the how, adapter takes care of the rest.
  • Active Filtering Mutating adapter will re-filter data on the fly.
  • Resolves Bugs 9666, 69179
  • More List Implementations
    • contains(), containsAll()
    • removeAll(), retainAll()
    • update()
  • Convenience methods
    • getFilteredList()
    • getList(), setList()
  • LayoutInflater Passed down to both getView() and getDropDownView()
  • Slightly smarter internal notifyDataSetChanged() invocations


Code Example

    public class MovieAdapter extends AbsArrayAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }

        //Easily customize your filtered results here.  Too easy!
        @Override
        protected boolean isFilteredOut(MovieItem movie, CharSequence constraint) {
            return !movie.title.toLowerCase(Locale.US).contains(
                    constraint.toString().toLowerCase(Locale.US));
        }
    }

Perks:

  • SparseArray Backed Based on and designed to work only with Android’s SparseArray
  • SparseArray Implementation Unlike a typical array based adapter, all interactions with this adapter are akin to working with a SparseArray.
  • Filtering Logic You provide the how, adapter takes care of the rest.
  • Active Filtering Mutating adapter will re-filter data on the fly.
  • Convenience methods
    • getFilteredSparseArray()
    • getSparseArray(), setSparseArray()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

    public class MovieAdapter extends SparseAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }

        //Easily customize your filtered results here.  Too easy!
        @Override
        protected boolean isFilteredOut(int keyId, MovieItem item, CharSequence constraint) {
            return !item.title.toLowerCase(Locale.US).
                    contains(constraint.toString().toLowerCase(Locale.US));
        }
    }

Perks:

  • JSONArray Backed Based on and designed to work only with Android’s JSONArray
  • JSONArray Implementation Unlike a typical array based adapter, all interactions with this adapter are akin to working with a JSONArray.
  • Filtering Logic You provide the how, adapter takes care of the rest.
  • Manage Type Filtering Storing multiple types of objects? No problem, you can create a specific filtering logic for each data type. Even for your own custom classes.
  • Built-in Filters Default filtering logic supplied for Boolean, Double, Integer, Long and String data types. Can optionally override these with your own behavior.
  • Active Filtering Mutating adapter will re-filter data on the fly.
  • Convenience methods
    • getFilteredJSONArray()
    • getJSONArray(), setJSONArray()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

    public class MovieAdapter extends JSONAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }

        //Easily customize your filtered results here.  Too easy!
        @Override
        protected boolean isFilteredOut(Object item, CharSequence constraint) {
            return !item.toString().toLowerCase(Locale.US).
                    contains(constraint.toString().toLowerCase(Locale.US));
        }
    }

Perks:

  • Section Adapter Easily create sections for your data without manually organizing it yourself.
  • ExpandableListView For use with only.
  • ArrayList & Map Backing Designed to work only with Android’s ArrayList. Data is organized in a Map of ArrayLists.
  • Uses PatchedExpandableListAdapter Which fixes broken ExpandableListView features and provides additional conveniences. Learn more here.
  • Organizing Data You provide the how, adapter takes care of the rest.
  • Filtering Logic You provide the how, adapter takes care of the rest. Sound familiar?
  • Active Filtering Mutating adapter will re-filter data on the fly.
  • Convenience methods
    • getFilteredList(), getList(), setList()
    • sortGroup(), sortAllChildren()
    • collapseAll(), expandAll(), hasAutoExpandingGroups(), isGroupSelectable()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

class MovieAdapter extends RolodexArrayAdapter<Integer, MovieItem> {

    MovieAdapter(Context activity) {
        super(activity);
    }

    @Override
    public Integer createGroupFor(MovieItem childItem) {
        return childItem.year;
    }

    @Override
    public View getChildView(LayoutInflater inflater, int groupPosition, int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        if (convertView == null) {
            //Inflate your view
        }

        //Fill your view with data
        return convertView;
    }

    @Override
    public View getGroupView(LayoutInflater inflater, int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        if (convertView == null) {
            //Inflate your view
        }

        //Fill your view with data
        return convertView;
    }

    @Override
    protected boolean isChildFilteredOut(MovieItem movie, CharSequence constraint) {
        //Make sure we aren't checking against a constraint containing a movie year, then filter by movie title
        return !TextUtils.isDigitsOnly(constraint) && !movie.title.toLowerCase(Locale.US).contains(
                constraint.toString().toLowerCase(Locale.US));
    }

    @Override
    protected boolean isGroupFilteredOut(Integer year, CharSequence constraint) {
        //Lets filter out everything whose year does not the numeric values in constraint.
        return TextUtils.isDigitsOnly(constraint) && !year.toString().contains(constraint);
    }
}

NON-FILTERABLE ADAPTERS

Compared to Android’s ArrayAdapter:

  • Filtering Removed So no internal synchronized blocks to slow things down.
  • More List Implementations
    • contains(), containsAll()
    • removeAll(), retainAll()
    • update(), insertAll()
  • Convenience methods
    • getList(), setList()
  • LayoutInflater Passed down to both getView() and getDropDownView()
  • Slightly smarter internal notifyDataSetChanged() invocations


Code Example

    public class MovieAdapter extends NFArrayAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }
    }

Perks:

  • SparseArray Backed Based on and designed to work only with Android’s SparseArray
  • SparseArray Implementation Unlike a typical array based adapter, all interactions with this adapter are akin to working with a SparseArray.
  • Filtering Removed So no internal synchronized blocks to slow things down.
  • Convenience methods
    • getSparseArray(), setSparseArray()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

    public class MovieAdapter extends NFSparseAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }
    }

Perks:

  • JSONArray Backed Based on and designed to work only with Android’s JSONArray
  • JSONArray Implementation Unlike a typical array based adapter, all interactions with this adapter are akin to working with a JSONArray.
  • Filtering Removed So no internal synchronized blocks to slow things down.
  • Convenience methods
    • getJSONArray(), setJSONArray()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

    public class MovieAdapter extends JSONAdapter<MovieItem> {
        MovieAdapter(Context activity) {
            super(activity);
        }

        @Override
        public View getView(LayoutInflater inflater, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                //Inflate your view
            }

            //Fill your view with data
            return convertView;
        }
    }

Perks:

  • Section Adapter Easily create sections for your data without manually organizing it yourself.
  • ExpandableListView For use with only.
  • ArrayList & Map Backing Designed to work only with Android’s ArrayList. Data is organized in a Map of ArrayLists.
  • Uses PatchedExpandableListAdapter Which fixes broken ExpandableListView features and provides additional conveniences. Learn more here.
  • Organizing Data You provide the how, adapter takes care of the rest.
  • Filtering Removed So no internal synchronized blocks to slow things down.
  • Convenience methods
    • getList(), setList()
    • sortGroup(), sortAllChildren()
    • collapseAll(), expandAll(), hasAutoExpandingGroups(), isGroupSelectable()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Example

class MovieAdapter extends NFRolodexArrayAdapter<Integer, MovieItem> {

    MovieAdapter(Context activity) {
        super(activity);
    }

    @Override
    public Integer createGroupFor(MovieItem childItem) {
        return childItem.year;
    }

    @Override
    public View getChildView(LayoutInflater inflater, int groupPosition, int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        if (convertView == null) {
            //Inflate your view
        }

        //Fill your view with data
        return convertView;
    }

    @Override
    public View getGroupView(LayoutInflater inflater, int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        if (convertView == null) {
            //Inflate your view
        }

        //Fill your view with data
        return convertView;
    }
}

MISCELLANEOUS ADAPTERS

Perks:

  • ExpandableListView For use with only.
  • Replacement Foundation Want to create your own custom adapter? Start by using this guy instead of BaseExpandableListAdapter
  • Choice Mode Fixes and provides choice mode support for an ExpandableListView
  • Stop Group Collapse Wouldn’t it be nice to force an ExpandableListView to never collapse a group? Now possible.
  • Is Group Selectable BaseExpandableLisAdapter provides an isChildSelectable() method but forgot about an isGroupSelectable(). Now longer forgotten.
  • Convenience methods To name just a few:
    • collapseAll(), expandAll()
    • hasAutoExpandingGroups(), isGroupSelectable()
  • LayoutInflater Passed down to both getView() and getDropDownView()


Code Examples

Already have a custom adapter extending BaseExpandableListAdapter? No sweat. Just switch out with the PatchedExpandableListAdapter and you’re done.

class MyCustomAdapter extends PatchedExpandableListAdapter {
    //No further work required to get working.  Just implement your custom adapter
    //as normal. However there are a couple methods available to override for
    //certain behavior changes.

    //Override and return true to force all groups to always render expanded
    @Override
    public boolean hasAutoExpandingGroups() {
        return true;
    }

    //Override and return true to toggle whether a group is clickable or not.
    @Override
    public boolean isGroupSelectable(int groupPosition) {
        return true;
    }
}

To enable and use choice mode, there are a few key things to remember. All interactions relating to choice mode must go through the adapter instead of the ExpandableListView. Here are some code examples to get you started.

//If you need to set your own group or child click listeners, do so through the
//adapter.
mAdapter.setOnChildClickListener(new MyChildClickListener());
mAdapter.setOnGroupClickListener(new MyGroupClickListener());

//To enable choice mode, go through the adapter.
mAdapter.setChoiceMode(PatchedExpandableListAdapter.ChoiceMode.MULITPLE);

//If enabling one of the modal choice modes, don't forget to set the
//ChoiceModeListener
mAdapter.setMultiChoiceModeListener(new MyChoiceModeListener());

private class MyChoiceModeListener implements
		PatchedExpandableListAdapter.ChoiceModeListener {
	@Override
	public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
	}

	@Override
	public void onChildCheckedStateChanged(ActionMode mode, int groupPosition, long groupId,
										   int childPosition, long childId, boolean checked) {
	}

	@Override
	public boolean onCreateActionMode(ActionMode mode, Menu menu) {
	}

	@Override
	public void onDestroyActionMode(ActionMode mode) {
	}

	@Override
	public void onGroupCheckedStateChanged(ActionMode mode, int groupPosition, long groupId,
										   boolean checked) {
	}

	@Override
	public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
	}
}

When choide mode is turned on, if you need to access any of the data revolving around which items are selected and so forth, do so through the adapter. Those returned via the ExpandableListView will not be valid.

    //Example list of available functions
    mAdapter.getCheckedChildCount();
    mAdapter.getCheckedChildIds();
    mAdapter.getCheckedChildPositions();
    mAdapter.getCheckedGroupCount();
    mAdapter.getCheckedGroupIds();
    mAdapter.getCheckedGroupPositions();

There are a bunch more available methods when using choice mode. Just remember to work directly through the adapter instead of the ExpandableListView