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)   …

Continue ReadingGlobalSearchAdapter Setup in Open Event Android App

Global Search in Open Event Android

In the Open Event Android app we only had a single data source for searching in each page that was the content on the page itself. But it turned out that users want to search data across an event and therefore across different screens in the app. Global search solves this problem. We have recently implemented  global search in Open Event Android that enables the user to search data from the different pages i.e Tracks, Speakers, Locations etc all in a single page. This helps the user in obtaining his desired result in less time. In this blog I am describing how we implemented the feature in the app using JAVA and XML. Implementing the Search The first step of the work is to to add the search icon on the homescreen. We have done this with an id R.id.action_search_home. @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_home, menu); // Get the SearchView and set the searchable configuration SearchManager searchManager = (SearchManager)getContext(). getSystemService(Context.SEARCH_SERVICE); searchView = (SearchView) menu.findItem(R.id.action_search_home).getActionView(); // Assumes current activity is the searchable activity searchView.setSearchableInfo(searchManager.getSearchableInfo( getActivity().getComponentName())); searchView.setIconifiedByDefault(true); } What is being done here is that the search icon on the top right of the home screen  is being designated a searchable component which is responsible for the setup of the search widget on the Toolbar of the app. @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater();    inflater.inflate(R.menu.menu_home, menu);    SearchManager searchManager =            (SearchManager) getSystemService(Context.SEARCH_SERVICE);    searchView = (SearchView) menu.findItem(R.id.action_search_home).getActionView();    searchView.setSearchableInfo(            searchManager.getSearchableInfo(getComponentName()));    searchView.setOnQueryTextListener(this);    if (searchText != null) {        searchView.setQuery(searchText, true);    }    return true; } We can see that a queryTextListener has been setup in this function which is responsible to trigger a function whenever a query in the SearchView changes. Example of a Searchable Component <?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android"    android:hint="@string/global_search_hint"    android:label="@string/app_name" /> For More Info : https://developer.android.com/guide/topics/search/searchable-config.html If this searchable component is inserted into the manifest in the required destination activity’s body the destination activity is set and intent filter must be set in this activity to tell whether or not the activity is searchable. Manifest Code for SearchActivity <activity        android:name=".activities.SearchActivity"        android:launchMode="singleTop"        android:label="Search App"        android:parentActivityName=".activities.MainActivity">    <intent-filter>        <action android:name="android.intent.action.SEARCH" />    </intent-filter>    <meta-data        android:name="android.app.searchable"        android:resource="@xml/searchable" /> </activity> And the attribute  android:launchMode=”singleTop”  is very important as if we want to search multiple times in the SearchActivity all the instances of our SearchActivity would get stored on the call stack which is not needed and would also eat up a lot of memory. Handling the Intent to the SearchActivity We basically need to do a standard if check in order to check if the intent is of type ACTION_SEARCH. if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) {    handleIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) {    super.onNewIntent(intent);    handleIntent(intent); } public void handleIntent(Intent intent) {    final String query = intent.getStringExtra(SearchManager.QUERY);    searchQuery(query); } The function searchQuery is called within handleIntent in order to search for the text that we received…

Continue ReadingGlobal Search in Open Event Android