简体   繁体   中英

How to make multiple view type in RecyclerView using two data models?

I have the data that I get from API using the Retrofit library. The API working perfectly. The problem is how do I put the data into the list and display it using RecyclerView adapter. I tried using HashMap but it will crash the application. Can someone help me to show the right structure and solution of this issue?

The data from API

Report model

Record model inside the list of report

The data I already got from the API

The interface that I want to display

I suggest you flatten the model . Instead of having a parent with a child, have only one level. Also, use different data models for your UI and for Retrofit . When needed, convert between the models. This way, things are not tightly coupled and you can do other things when coverting, eg format strings if needed.

// 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;

All that's left to do is the adapter. There are plenty examples on how to support multiple view types, simple unfinished example:

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
        }
    }
}
  1. override getItemViewType(position: Int) and return different type with your different model.
  2. override onCreateViewHolder(parent: ViewGroup, viewType: Int) , you can create itemViewHolder according to itemType.
  3. override onBindViewHolder(holder: BaseViewHolder, position: Int) , you can display what you need. remember to judge the item's itemType

In general, you need to create different itemtype according to your model, then create different viewholder, finally display the viewholder with you model

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM