GlobalSearchAdapter Setup in Open Event Android App
In this blog post I describe how the GlobalSearchAdapter in Open Event Android was made which enabled users to search quickly within the app. This post also outlines how to create Recycler Views with heterogenous layouts and explains how to write ViewHolders. Adapter Logic A custom adapter was built for the population of views in the Recycler View in the SearchActivity. private List<Object> filteredResultList = new ArrayList<>(); //ViewType Constants private final int TRACK = 0; private final int SPEAKER = 2; private final int LOCATION = 3; private final int DIVIDER = 4; The DIVIDER constant was assigned to the Result Type Header View. In a gist all the item types such as Speaker, Track, Location, Divider etc have been designated some constants. Getting the ItemViewType @Override public int getItemViewType(int position) { if(filteredResultList.get(position) instanceof Track){ return TRACK; } else if(filteredResultList.get(position) instanceof String){ return DIVIDER; } ...Similarly for other ItemTypes such as Session or Location else{ return 1; } } As the filteredResultList is of type Object we can insert objects of any type into the list as Object is a superclass of all classes. We would want a view which represents a TRACK if we have an object of type Track in the filteredResultList. And similarly for the other result types we could insert objects of type LOCATION, SPEAKER types in this list. getItemViewType() basically determines the type of the item that is visible to us. If the list consists of an item of type SPEAKER, in the RecyclerView. Code for onCreateViewHolder in GlobalSearchAdapter for the Recycler View @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder resultHolder = null; LayoutInflater inflater = LayoutInflater.from(parent.getContext()); switch(viewType) { case TRACK: View track = inflater.inflate(R.layout.item_track, parent, false); resultHolder = new TrackViewHolder(track,context); break; case SPEAKER: View speaker = inflater.inflate(R.layout.search_item_speaker, parent, false); resultHolder = new SpeakerViewHolder(speaker,context); break; //Similarly for other types default: break; } return resultHolder; } Depending upon the the viewType returned the desired layout is inflated and the desired ViewHolder is returned. Code for onBindViewHolder in GlobalSearchAdapter for the Recycler View @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()){ case TRACK: TrackViewHolder trackSearchHolder = (TrackViewHolder)holder; final Track currentTrack = (Track)getItem(position); trackSearchHolder.setTrack(currentTrack); trackSearchHolder.bindHolder(); break; //Similarly for all the other View Types default: break; } } These functions are being used to bind the data to the layouts that have been inflated already in the earlier snippet of code of onCreateViewHolder. The bindHolder functions of each ViewHolder type are being used to do the view binding i.e converting the information in the Object Track into what we see in the TrackViewHolder as seen in TrackViewFormat. All ViewHolders have been defined as separate classes in order to enable re usability of these classes. ViewHolder Implementation There are 4 main ViewHolders that were made to enable such a search. I’ll be talking about the TrackViewHolder in detail. public class TrackViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.imageView) ImageView trackImageIcon; @BindView(R.id.track_title) TextView trackTitle; @BindView(R.id.track_description) …
