Java 如何使用两个数据模型在RecyclerView中创建多视图类型?

Java 如何使用两个数据模型在RecyclerView中创建多视图类型?,java,android,api,android-recyclerview,retrofit,Java,Android,Api,Android Recyclerview,Retrofit,我有我使用改型库从API获得的数据。API工作得很好。问题是如何将数据放入列表并使用RecyclerView适配器显示它。我尝试使用HashMap,但它会使应用程序崩溃。有人能帮我展示这个问题的正确结构和解决方案吗 来自API的数据 报告模型 在报告列表中记录模型 我已经从API获得了数据 我要显示的界面 覆盖getItemViewType(位置:Int)并返回不同型号的不同类型 覆盖CreateViewHolder(父级:ViewGroup,viewType:Int),您可以根据it

我有我使用改型库从API获得的数据。API工作得很好。问题是如何将数据放入列表并使用RecyclerView适配器显示它。我尝试使用HashMap,但它会使应用程序崩溃。有人能帮我展示这个问题的正确结构和解决方案吗

来自API的数据

报告模型

在报告列表中记录模型

我已经从API获得了数据

我要显示的界面

  • 覆盖
    getItemViewType(位置:Int)
    并返回不同型号的不同类型
  • 覆盖CreateViewHolder(父级:ViewGroup,viewType:Int),您可以根据itemType创建itemViewHolder
  • 覆盖BindViewHolder(holder:BaseViewHolder,position:Int),您可以显示所需内容。记住判断项目的
    itemType

  • 通常,您需要根据您的模型创建不同的itemtype,然后创建不同的viewholder,最后使用您的模型显示viewholder

    我建议您将模型展平。不要让父母和孩子在一起,而要只有一个级别。另外,为用户界面和改装使用不同的数据模型。需要时,在模型之间进行转换。这样,事情就不会紧密耦合,在转换时可以做其他事情,例如,如果需要,格式化字符串

    // This is what the data model will extend
    interface UiBaseModel { }
    
    // monthly detail report
    class UiMonthlyDetailReport implements UiBaseModel {
    
        private String month;
        private String total;
    
        UiMonthlyDetailReport(String month, String total) {
            this.month = month;
            this.total = total;
        }
    
        public String getMonth() {
            return month;
        }
    
        public String getTotal() {
            return total;
        }
    }
    
    // monthly detail record
    class UiMonthlyDetailsRecord implements UiBaseModel {
    
        private String month;
        private String expenseName;
        private String expenseIcon;
        private String expenseTotal;
    
        UiMonthlyDetailsRecord(String month, String expenseName, String expenseIcon, String expenseTotal) {
            this.month = month;
            this.expenseName = expenseName;
            this.expenseIcon = expenseIcon;
            this.expenseTotal = expenseTotal;
        }
    
        public String getMonth() {
            return month;
        }
    
        public String getExpenseName() {
            return expenseName;
        }
    
        public String getExpenseIcon() {
            return expenseIcon;
        }
    
        public String getExpenseTotal() {
            return expenseTotal;
        }
    }
    
    
    
    // In your activity / fragment / viewmodel / presenter:
    
        List<ReportMonthlyDetailsReport> reports = ... // get your data from retrofit
        List<UiBaseModel> uiModels = ArrayList<UiBaseModel>();
        for (ReportMonthlyDetailsReport report : reports) {
            // First records, then report
            List<ReportMonthlyDetailsRecord> records = report.getRecords();
            for (ReportMonthlyDetailsRecord record : records) {
                // Create UI model and add to list
                UiMonthlyDetailsRecord uiRecord = UiMonthlyDetailsRecord(record.getMonth_label(), record.getExpense_type_name(), record.getExpense_type_icon(), record.getExpense_type_total());
                uiModels.add(uiRecord);
            }
            // Lastly, add the report
            UiMonthlyDetailsReport uiReport = UiMonthlyDetailsReport(report.getMonth_label(), report.getMonthly_total());
            uiModels.add(uiReport);
        }
    
        // Use the ui models (for the recycler adapter)
        MonthlyDetailsAdapter adapter = MonthlyDetailsAdapter(uiModels);
        recyclerView.adapter = adapter;
    
    //这就是数据模型将要扩展的内容
    接口UiBaseModel{}
    //每月详细报告
    类UiMonthlyDetailReport实现UiBaseModel{
    私人串月;
    私有字符串总数;
    UiMonthlyDetailReport(字符串月份,字符串总数){
    本月=月;
    这个.总计=总计;
    }
    公共字符串getMonth(){
    返回月份;
    }
    公共字符串getTotal(){
    返回总数;
    }
    }
    //每月详细记录
    类UiMonthlyDetailsRecord实现UiBaseModel{
    私人串月;
    私有字符串expenseName;
    私人字符串支出图标;
    私人字符串支出总额;
    UiMonthlyDetailsRecord(字符串月份、字符串费用名称、字符串费用图标、字符串费用总计){
    本月=月;
    this.expenseName=expenseName;
    this.expensecon=expensecon;
    this.expenseTotal=expenseTotal;
    }
    公共字符串getMonth(){
    返回月份;
    }
    公共字符串getExpenseName(){
    返回expenseName;
    }
    公共字符串getExpenseIcon(){
    返回费用图标;
    }
    公共字符串getExpenseTotal(){
    返回费用总额;
    }
    }
    //在活动/片段/视图模型/演示者中:
    列表报告=…//从改装中获取数据
    List uiModels=ArrayList();
    对于(ReportMonthlyDetailsReport:报告){
    //先记录,然后报告
    列表记录=report.getRecords();
    for(ReportMonthlyDetailsRecord记录:记录){
    //创建UI模型并添加到列表
    UiMonthlyDetailsRecord uiRecord=UiMonthlyDetailsRecord(record.getMonth_label(),record.getExpense_type_name(),record.getExpense_type_icon(),record.getExpense_type_total());
    uiModels.add(uiRecord);
    }
    //最后,添加报告
    UiMonthlyDetailsReport uiReport=UiMonthlyDetailsReport(report.getMonth\u label(),report.getMonthly\u total());
    uiModels.add(uiReport);
    }
    //使用ui模型(用于回收器适配器)
    MonthlyDetailsAdapter适配器=MonthlyDetailsAdapter(uiModels);
    recyclerView.adapter=适配器;
    
    剩下要做的就是适配器。有很多关于如何支持多种视图类型的示例,简单的未完成示例:

    public class MonthlyDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private final static int VIEW_TYPE_RECORD = 0;
        private final static int VIEW_TYPE_REPORT = 1;
    
        private List<UiBaseModel> data;
    
        MonthlyDetailsAdapter(List<UiBaseModel> data) {
            this.data = data;
        }
    
        class RecordViewHolder extends RecyclerView.ViewHolder {
            public RecordViewHolder(@NonNull View itemView) {
                // code
                super(itemView);
            }
        }
    
        class ReportViewHolder extends RecyclerView.ViewHolder {
            public ReportViewHolder(@NonNull View itemView) {
                // code
                super(itemView);
            }
        }
    
        @Override
        public int getItemViewType(int position) {
            UiBaseModel item = data.get(position);
            if (item instanceof UiMonthlyDetailsRecord) {
                return VIEW_TYPE_RECORD;
            } else {
                return VIEW_TYPE_REPORT;
            }
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof RecordViewHolder) {
                UiMonthlyDetailsRecord record = (UiMonthlyDetailsRecord) data.get(position);
                // bind record
            } else if (holder instanceof ReportViewHolder) {
                UiMonthlyDetailsReport report = (UiMonthlyDetailsReport) data.get(position);
                // bind report
            }
        }
    }
    
    公共类MonthlyDetailsAdapter扩展了RecyclerView.Adapter{ 私有最终静态int视图\类型\记录=0; 私有最终静态int视图\类型\报告=1; 私人名单数据; MonthlyDetailsAdapter(列表数据){ 这个数据=数据; } 类RecordViewHolder扩展了RecyclerView.ViewHolder{ public RecordViewHolder(@NonNull View itemView){ //代码 超级(项目视图); } } 类ReportViewHolder扩展了RecyclerView.ViewHolder{ public ReportViewHolder(@NonNull View itemView){ //代码 超级(项目视图); } } @凌驾 public int getItemViewType(int位置){ UiBaseModel项=data.get(位置); if(UiMonthlyDetailsRecord的项目实例){ 返回视图\类型\记录; }否则{ 返回视图类型报告; } } @凌驾 public void onBindViewHolder(@NonNull RecyclerView.ViewHolder,int位置){ if(RecordViewHolder的持有者实例){ UiMonthlyDetailsRecord记录=(UiMonthlyDetailsRecord)数据。获取(位置); //绑定记录 }else if(ReportViewHolder的持有者实例){ UiMonthlyDetailsReport report=(UiMonthlyDetailsReport)data.get(position); //装订报告 } } }
    问题是如何区分getItemViewType中的子项和父项?私有列表数据总量@重写列表中的公共int-getItemViewType(int-position){if(TextUtils.isEmpty(dataTotal.get(position).getMonthly\u-total()){return-TYPE\u-PARENT;}否则{return-TYPE\u-CHILD;}},还有另一个记录列表,它是报表列表的子项####################您可以创建一个包装器实体,并创建一个类似于
    列表

    数据类包装器的列表(val records:YourEntity,val report:YourEntity,val itemType,val itetype: