I am trying to implement a search feature within my app where the user can search for different types of data: track, album, or artist. The user selects what type of data they'll be searching for in activity A and then the actual search is performed in activity B.
Within activity A:
Intent intent = new Intent(this, PostSearch.class);
intent.putExtra(PostSearch.EXTRA_POST_TYPE, postType);
startActivityForResult(intent, RC_NEW_POST);
EXTRA_POST_TYPE
specifies the kind of search that will be performed. This extra is then extracted within activity B. I have classes already defined for each data type: Track
, Album
, and Artist
. Within activity B, I have a RecyclerView
backed by an adapter. I was hoping to use the same adapter definition for each data type. However, I am not sure if this is possible.
I've defined my adapter as follows (shortened for brevity):
public class PostSearchAdapter extends RecyclerView.Adapter<PostSearchAdapter.PostSearchViewHolder> {
private Context mContext;
private int mSearchType;
private List<?> mSearchResults;
public PostSearchAdapter(Context context, int searchType) {
this.mContext = context;
mSearchType = searchType;
switch (mSearchType) {
case 0:
mSearchResults = new ArrayList<Track>();
break;
case 1:
mSearchResults = new ArrayList<Album>();
break;
case 2:
mSearchResults = new ArrayList<Album>();
break;
default:
Log.i(TAG, "Invalid search type for adapter. Uh oh...");
break;
}
}
@Override
public int getItemCount() {
if (mSearchResults == null) {
return 0;
} else {
return mSearchResults.size();
}
}
@NonNull
@Override
public PostSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View searchResult = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.list_item_search_result, parent, false);
return new PostSearchViewHolder(searchResult);
}
@Override
public void onBindViewHolder(PostSearchViewHolder viewHolder, int position) {
switch (mSearchType) {
case 0:
Track track = (Track) mSearchResults.get(position);
viewHolder.mTitle.setText(track.getTitle());
viewHolder.mArtist.setText(track.getArtistNames());
if (!TextUtils.isEmpty(track.getAlbum().getLargeAlbumCover())) {
Picasso.get()
.load(track.getAlbum().getLargeAlbumCover())
.error(R.drawable.ic_no_cover)
.into(viewHolder.mCover);
}
break;
case 1:
// Handle album results here
break;
case 2:
// Handle artist results here
break;
default:
break;
}
}
public void addData(List<?> newData) {
mSearchResults.add(newData);
notifyDataSetChanged();
}
public void clearData(){
mSearchResults.clear();
}
}
I've defined my adapter this way because when I instantiate it within activity B, I will know what type of data I'm dealing with from EXTRA_POST_TYPE
and can do something like:
mAdapter = new PostSearchAdapter(this, mSearchType);
...where mSearchType
has the value stored by EXTRA_POST_TYPE
. However, my issues now has to deal with mSearchResults
within my adapter. I've defined this member variable like this using the Java ?
wildcard type:
private List<?> mSearchResults;
I've done it this since I don't know what type of data the list will contain until the adapter is instantiated. I then instantiate mSearchResults
within the overriden constructor of the adapter since I now know what kind of data to put into the array based on the value of mSearchType
:
public PostSearchAdapter(Context context, int searchType) {
this.mContext = context;
mSearchType = searchType;
switch (mSearchType) {
//Instantiate mSearchResults here
}
}
There's 2 big issues that I'm facing with this. The first is that I still have to cast for the object that is being stored within the list in onBindViewHolder()
:
Track track = (Track) mSearchResults.get(position);
I know that this is a problem because one of the main advantages of using parameterized data types is so that we no longer have to do casting like so in the above. Second, I'm still getting a compile-time error within addData()
. Android Studio complains about something to with capture and the wildcard character:
I don't completely understand the error, which has left me at a standstill.
I should mention that I don't have the most thorough understanding of generics within Java, but I felt like the problem that I'm trying to solve could be accomplished by using them. Any sort of insight into this would be greatly appreciated!