gpt4 book ai didi

java - 多种数据类型的 RecyclerView.Adapter

转载 作者:搜寻专家 更新时间:2023-11-01 09:24:46 25 4
gpt4 key购买 nike

我正在尝试在我的应用程序中实现搜索功能,用户可以在其中搜索不同类型的数据:轨道、专辑或艺术家。用户在 Activity A 中选择要搜索的数据类型,然后在 Activity B 中执行实际搜索。

在 Activity A 中:

    Intent intent = new Intent(this, PostSearch.class);
intent.putExtra(PostSearch.EXTRA_POST_TYPE, postType);

startActivityForResult(intent, RC_NEW_POST);

EXTRA_POST_TYPE 指定将执行的搜索类型。然后在 Activity B 中提取此额外内容。我已经为每种数据类型定义了类:TrackAlbumArtist。在 Activity B 中,我有一个由适配器支持的 RecyclerView。我希望对每种数据类型使用相同的适配器定义。但是,我不确定这是否可能。

我已将我的适配器定义如下(为简洁起见缩短):

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();
}
}

我以这种方式定义了我的适配器,因为当我在 Activity B 中实例化它时,我将从 EXTRA_POST_TYPE 中知道我正在处理的数据类型,并且可以执行如下操作:

mAdapter = new PostSearchAdapter(this, mSearchType);

...其中 mSearchType 具有由 EXTRA_POST_TYPE 存储的值。但是,我的问题现在必须处理适配器中的 mSearchResults。我已经使用 Java ? 通配符类型定义了这个成员变量:

private List<?> mSearchResults;

我这样做是因为在实例化适配器之前我不知道列表将包含什么类型的数据。然后我在适配器的覆盖构造函数中实例化 mSearchResults,因为我现在知道根据 mSearchType 的值将哪种数据放入数组中:

public PostSearchAdapter(Context context, int searchType) {
this.mContext = context;
mSearchType = searchType;

switch (mSearchType) {
//Instantiate mSearchResults here
}
}

我面临着两个大问题。首先是我仍然必须为存储在 onBindViewHolder() 中的列表中的对象进行强制转换:

Track track = (Track) mSearchResults.get(position);

我知道这是个问题,因为使用参数化数据类型的主要优点之一是我们不再必须像上面那样进行转换。其次,我在 addData() 中仍然遇到编译时错误。 Android Studio 提示捕获和通配符的问题:

enter image description here

我不完全理解这个错误,这让我停滞不前。

我应该指出,我对 Java 中的泛型没有最透彻的理解,但我觉得我试图解决的问题可以通过使用它们来完成。对此有任何见解都将不胜感激!

最佳答案

您没有正确使用泛型。

您的 TrackAlbum 是否共享一个父类(super class)或任何接口(interface)?

如果不创建接口(interface)并将其添加到两个类,否则继续使用您的父类(super class):

public interface ISearchResult{ }

然后将您的适配器更改为一个抽象类,为ViewHolder 添加正确的类型声明和一个模板:

public abstract class PostSearchAdapter<T extends ISearchResult> extends RecyclerView.Adapter<PostSearchAdapter.PostSearchViewHolder> {
// note change from private to protected
protected final Context mContext;
protected final ArrayList<T> mSearchResults = new ArrayList<T>();

// constructor no longer handles weird type variable
public PostSearchAdapter(Context context) {
this.mContext = context;
}

// oncreate viewholder is removed on purpose

@Override
public void onBindViewHolder(PostSearchAdapter.PostSearchViewHolder viewHolder, int position) {
viewHolder.bind(mSearchResults.get(position));
}

public void addData(List<T> newData) {
mSearchResults.addAll(newData);
notifyDataSetChanged();
}

public void clearData(){
mSearchResults.clear();
}

@Override
public int getItemCount() {
return mSearchResults.size(); // this is never null
}

// ViewHolder template
protected abstract class PostSearchViewHolder extends RecyclerView.ViewHolder{
protected PostSearchViewHolder(View itemView) {
super(itemView);
// this can have some or all views that are shared between search results
}

protected abstract void bind(T data);
}
}

这会处理基本方法。现在您需要为每个搜索结果类型创建此适配器的子类(注意类型参数在扩展中使用):

public class TrackAdapter extends PostSearchAdapter<Track> {
public TrackAdapter(Context context) {
super(context);
}

@NonNull
@Override
public PostSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// if all types share layout You can create helper method in superclass to inflate it
View searchResult = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.list_item_search_result, parent, false);

return new TrackViewHolder(searchResult);
}

protected class TrackViewHolder extends PostSearchViewHolder{
protected TrackViewHolder(View itemView) {
super(itemView);
// store views not included in superclass in fields
}

@Override
protected void bind(Track data) {
// bind views to Track data...
}
}
}

现在只剩下创作了。简单的静态工厂方法将处理这个问题,例如添加到 PostSearchAdapter 类:

public static PostSearchAdapter create(Context context, int resultType){
switch (resultType){
case 0:
return new TrackAdapter(context);
case 1:
return new AlbumAdapter(context);
default:
throw new IllegalArgumentException("Invalid resultType:"+resultType);
}
}

这让您可以通过简单的调用获得正确类型的适配器:

mAdapter = PostSearchAdapter.create(this, mSearchType);

关于java - 多种数据类型的 RecyclerView.Adapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51460260/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com