RecyclerView.Adapter实现中的泛型和通配符

时间:2016-10-06 16:43:09

标签: java android generics

我正在尝试为RecyclerView实现自定义适配器,而不使用单个强制转换或实例。

我的实施受this article的启发。

我的适配器应该能够显示以下类型的任何项目:

public interface InboxVisitable {
    int getType(InboxTypeFactory inboxTypeFactory);
}

我有2种此类型的实现:

public class InboxMonthViewModel implements SentInboxFragment.InboxVisitable {
    public String month;

    @Override
    public int getType(SentInboxFragment.InboxTypeFactory inboxTypeFactory) {
        return inboxTypeFactory.getType(this);
    }
}

public class InboxMessageViewModel implements SentInboxFragment.InboxVisitable {
    public String message;

    @Override
    public int getType(SentInboxFragment.InboxTypeFactory inboxTypeFactory) {
        return inboxTypeFactory.getType(this);
    }
}

InboxFactoryType是一个工厂,用于将特定类型链接到适配器用于确定视图类型的唯一ID:

public static class InboxTypeFactory {
    public int getType(InboxMessageViewModel message) {
        return R.layout.cell_inbox_message;
    }

    public int getType(InboxMonthViewModel month) {
        return R.layout.cell_inbox_message;
    }

    public InboxViewHolder getViewHolderForType(View itemView, int viewType) {
        if (viewType == R.layout.cell_inbox_message) {
            return new InboxMessageViewHolder(itemView);
        } else {
            return new InboxMonthViewHolder(itemView);
        }
    }
}

如您所见,工厂还负责为每种可能的类型创建视图持有者。

View Holder是一个通用视图持有者,因为适配器只需要知道一种类型的持有者:

private static abstract class InboxViewHolder<T extends InboxVisitable> extends RecyclerView.ViewHolder {
    public InboxViewHolder(View itemView) {
        super(itemView);
    }
    public abstract void bind(T data);
}

而且,由于我有两种类型的数据,我有2个相应的视图持有者:

private static class InboxMessageViewHolder extends InboxViewHolder<InboxMessageViewModel> {

    public InboxMessageViewHolder(View itemView) {
        super(itemView);
    }

    @Override
    public void bind(InboxMessageViewModel data) {
        // do stuff
        data.message;
    }
}

private static class InboxMonthViewHolder extends InboxViewHolder<InboxMonthViewModel> {

    public InboxMonthViewHolder(View itemView) {
        super(itemView);
    }

    @Override
    public void bind(InboxMonthViewModel data) {
        // do stuff
        data.month;
    }
}

现在,对于有趣的部分,适配器。 他正在使用工厂为每种特定数据类型获取正确的视图类型,并且通过该工厂,他还将为每个数据创建视图持有者。 适配器正在保存他正在操作的最通用类型的数据列表:InboxVisitable

private static class InboxAdapter extends RecyclerView.Adapter<InboxViewHolder> {

    private final InboxTypeFactory inboxTypeFactory;
    List<InboxVisitable> itemList;

    InboxAdapter() {
        inboxTypeFactory = new InboxTypeFactory();
    }

    @Override
    public InboxViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View itemView = LayoutInflater.from(parent.getContext())
                                            .inflate(viewType, parent, false);
        return inboxTypeFactory.getViewHolderForType(itemView, viewType);
    }

    @Override
    public void onBindViewHolder(InboxViewHolder holder, int position) {
        //noinspection unchecked
        holder.bind(itemList.get(position));
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }
}

这段代码完美无缺,但它有一个小缺陷:当绑定视图持有者时,编译器告诉我,当我向InboxVisitable方法bind(T)提供RecyclerView.Adapter<InboxViewHolder<? extends InboxVisitable>>时,会有一个未经检查的强制转换。

我尝试添加以指定adaper bind()(并在任何地方反映规范)但是,? extends InboxVisitable期望InboxVisitable,但我只提供给他一个bind()

我如何处理所有这些通用的疯狂,没有强制转换,没有实例,也没有对此library(shiny) myModUI <- function(id) { ns <- NS(id) tagList( fluidRow( splitLayout(cellWidths=c("75%","25%"), plotOutput(ns("g")), radioButtons(ns("radio"),label = "buttons", choices = list("with intercept"=1,"without intersept"=2), selected = 1)) ) ) } myMod <- function(input, output, server, seed) { output$g <- renderPlot({ set.seed(seed) xx <- rnorm(10) yy <- rnorm(10) plot(xx,yy) abline(reg=lm(yy~xx), col=2, lwd=ifelse(input$radio==1,2,1)) abline(reg=lm(yy~xx+0), col=3, lwd=ifelse(input$radio==2,2,1)) }) return(reactive(input$radio)) } server <- shinyServer(function(input, output, server) { lapply(1:5,function(i) { callModule(myMod,i,seed=i) }) }) ui <- shinyUI(fluidPage( titlePanel("My loop test"), mainPanel( lapply(1:5,function(i) { myModUI(i) }) ) )) shinyApp(ui=ui,server=server) 方法进行未经检查的调用?

非常感谢, 皮尔

0 个答案:

没有答案