我的问题基于先前关于我的Code的问题-这是一种具有不同视图的新闻源,可以垂直或水平滚动或显示各种内容(基本上是广告)
现在我在Ben P的帮助下进行了管理,在上一篇文章中,我使用以下代码来组织我的观点:
this.items = new ArrayList<>();
if (listVertical.size() > 0) {
items.add(listVertical.remove(0));
}
if (listHorizontal.size() > 0) {
items.add(listHorizontal.remove(0));
}
while (listVertical.size() > 0 || listAd.size() > 0) {
if (listAd.size() > 0) {
items.add(listAd.remove(0));
}
int count = 5;
while (count > 0 && listVertical.size() > 0) {
items.add(listVertical.remove(0));
}
}
这是静态消息传递的静态方法。因此,我尝试使用JSON中的position元素来组织视图,如下所示:
{
"horizontal": [{...,position:"1",},{...,position:"3",...},{...,position:"4",...}] ,
"vertical": [{...,position:"2",},{...,position:"5",},{...,position:"6",}]
"ad": [{...,position:"0",},{...,position:"7",},{...,position:"8",}]
}
使用此代码,应该可以将Feed定位:
int length_tot= vertical.size() + horizontal.size() + ad.size();
this.items = new ArrayList<>();
for(int i = 0; i < lenth_tot; i++) {
if(vertical.getallthepositions_somehow == i) {
items.add(vertical.remove(0));
}
if(horizontal.getallthepositions_somehow == i) {
items.add(horizontal.remove(0));
}
if(ad.getallthepositions_somehow == i) {
items.add(ad.remove(0));
}
}
如您所见,我被困在遍历所有列表的过程中,寻找下一个要添加到我的项列表中的位置。
所以我的问题是:
找到下一个要添加的职位的最快方法是什么?我的解决方案感觉太沉重了,您是否想过(从处理器的角度来看)更经济的解决方案?
这是我的onBindViewHolder
:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == VIEW_TYPE_VERTICAL)
verticalView((VerticalViewHolder) holder, position);
if (holder.getItemViewType() == VIEW_TYPE_HORIZONTAL)
horizontalView((HorizontalViewHolder) holder, position);
}
以及适配器中的getItemViewType
:
@Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Vertical)
return VIEW_TYPE_VERTICAL;
if (items.get(position) instanceof Horizontal)
return VIEW_TYPE_HORIZONTAL;
}
编辑:
所以我想从服务器中获取JSON:
{
"horizontal": [{...,position:"1",},{...,position:"3",...},{...,position:"4",...}] ,
"vertical": [{...,position:"2",},{...,position:"5",},{...,position:"6",}]
"ad": [{...,position:"0",},{...,position:"7",},{...,position:"8",}]
}
是具有以下查看顺序的新闻源:
- [AD] (position=0)
- [HORIZONTAL] (position =1)
- [VERTICAL] (position=2)
- [HORIZONTAL]
- [HORIZONTAL]
以此类推...
因此,由于每个json数组中的psoition项,服务器基本上决定了适配器中我的视图的顺序
Ben P-我列表中正确顺序的代码:
Object[] itemsObject = new Object[listVertical.size() + listHorizontal.size() + adList.size()];
for (Vertical item : listVertical) {
itemsObject[Integer.parseInt(item.getPosition())] = item;
}
for (Horizontal item : listHorizontal) {
itemsObject[Integer.parseInt(item.getPosition())] = item;
}
for (Adfeed item : adList) {
it
ArrayList<Object> itemsPos = new ArrayList<>();
itemsPos.addAll(listVertical);
itemsPos.addAll(listHorizontal);
itemsPos.addAll(adList);
Collections.sort(items, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return Integer.compare(o1.getPosition(),o2.getPosition())
}
});
垂直,水平和Adfeed包含.getPosition()。那么如何在比较器中访问它们?
答案 0 :(得分:2)
实际上,无论如何,您都需要构造要在适配器中传递的项目列表,以显示在RecyclerView
中。因此,遍历每个列表中的所有元素(即水平,垂直和广告)并不是一个坏主意。实际上,您正在对要显示在RecyclerView
中的项目进行一些预处理,以便可以相应地执行。
我可以建议在预处理数据时进行一些小改进。在您的代码中,您必须在每次迭代中再次遍历所有元素。可以实际优化。考虑到该预处理不在适配器范围内,您可以执行以下操作。
int total = vertical.size() + horizontal.size() + ad.size();
int[] types = new int[total];
// Considering the positions are not overlapping.
for(int i = 0; i < vertical.size(); i++) {
types[vertical[i].position] = VIEW_TYPE_VERTICAL;
}
for(int i = 0; i < horizontal.size(); i++) {
types[horizontal[i].position] = VIEW_TYPE_HORIZONTAL;
}
for(int i = 0; i < add.size(); i++) {
types[add[i].position] = VIEW_TYPE_ADD;
}
// The type array has the view types for all elements now.
// Now add the views accordingly in your items list and then pass it to your adapter.
ArrayList<Item> items = new ArrayList<Item>();
for(int i = 0; i < type.length; i++) {
items.add(getItemBasedOnType(type[i]));
}
// Populate your adapter or pass new elements
adapter.addListItems(items);
getItemBasedOnType
可以是这样的。
private Item getItemBasedOnType(int type) {
if(type == VIEW_TYPE_VERTICAL) return vertical.remove(0);
else if(type == VIEW_TYPE_HORIZONTAL) return horizontal.remove(0);
else return add.remove(0);
}
希望能有所帮助。
答案 1 :(得分:1)
在实现RecyclerView.Adapter
时,您应努力首先创建一个代表数据集的有序列表(或数组)。如果您可以成功建立此列表,则其他所有操作都将变得非常容易。
为了从您发布的JSON示例构建列表,我将考虑两种不同的策略。第一种是使用数组,以便您可以分配特定的索引:
Object[] items = new Object[vertical.size() + horizontal.size() + ad.size()];
for (VerticalItem item : vertical) {
items[item.position] = item;
}
for (HorizontalItem item : horizontal) {
items[item.position] = item;
}
for (AdItem item : ad) {
items[item.position] = item;
}
第二个选项是使用List
,然后使用Comparator
对列表进行排序,以比较位置。这将要求您的三种商品类型中的每一种都具有一个与position
字段相同的超类,或者实现一个暴露getPosition()
等的接口。
List<PositionalItem> items = new ArrayList<>();
items.addAll(vertical);
items.addAll(horizontal);
items.addAll(ad);
Collections.sort(items, new Comparator<PositionalItem>() {
@Override
public int compare(PositionalItem lhs, PositionalItem rhs) {
return Integer.compare(lhs.getPosition(), rhs.getPosition());
}
});
这两种方法都会产生一个单独的排序列表,该列表中的项目以您想要显示的顺序排列。现在,我们可以使用它来实现Adapter
的其余部分。
(此示例假定您将Object[]
用于项目列表。如果使用List<PositionalItem>
或类似的名称,显然语法会稍有不同。)
private class MyAdapter extends RecyclerView.Adapter {
private final Object[] items;
public MyAdapter(Object[] items) {
this.items = items;
}
@Override
public int getItemCount() {
return items.length;
}
@Override
public int getItemViewType(int position) {
Object item = items[position];
if (item instanceof VerticalItem) {
return R.layout.newsfeed_vertical;
} else if (item instanceof HorizontalItem) {
return R.layout.newsfeed_horizontal;
} else if (item instanceof AdItem) {
return R.layout.newsfeed_ad;
} else {
throw new IllegalStateException("unexpected item type: " + item);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(viewType, parent, false);
switch (viewType) {
case R.layout.newsfeed_vertical: return new VerticalViewHolder(itemView);
case R.layout.newsfeed_horizontal: return new HorizontalViewHolder(itemView);
case R.layout.newsfeed_ad: return new AdViewHolder(itemView);
default: throw new IllegalStateException("unexpected viewType: " + viewType);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case R.layout.newsfeed_vertical: verticalView((VerticalViewHolder) holder, position);
case R.layout.newsfeed_horizontal: horizontalView((HorizontalViewHolder) holder, position);
case R.layout.newsfeed_ad: adView((AdViewHolder) holder, position);
default: throw new IllegalStateException("unexpected viewType: " + viewType);
}
}
// ...
}
您会注意到,我对视图类型使用了一个技巧:使用布局资源ID代替int
常量。无需定义自己的常量;资源框架已经为您创建了这些常量!
无论如何,我很高兴回答您的任何其他问题。但是这里的主要课程是担心首先先构建项目列表,然后再在所有Adapter方法中使用列表。
与其使用ArrayList<Object>
最好是为所有三种商品类型创建一个接口,然后使用该接口:
public interface NewsfeedItem {
int getPosition();
}
现在,您可以将implements NewsfeedItem
添加到每个类的声明中:
public class Vertical implements NewsfeedItem {
// ...
}
public class Horizontal implements NewsfeedItem {
// ...
}
public class Adfeed implements NewsfeedItem {
// ...
}
只要您的每个类中都有一个int getPosition()
方法,这将“正常工作”。看起来getPosition()
可能现在正在返回String,因此您可以更改接口定义以返回String
,也可以更改类以返回int
。两种方法都可以,只要两者都匹配即可。
然后,一旦设置了此界面,就可以更改排序代码以使用它:
ArrayList<NewsfeedItem> itemsPos = new ArrayList<>();
itemsPos.addAll(listVertical);
itemsPos.addAll(listHorizontal);
itemsPos.addAll(adList);
Collections.sort(items, new Comparator<NewsfeedItem>() {
@Override
public int compare(NewsfeedItem o1, NewsfeedItem o2) {
return Integer.compare(o1.getPosition(),o2.getPosition());
}
});