如何在MVVM/retrofit 架构中使用DataBinding 在RecyclerView 的一行中设置数据?

How to set data in a row of RecyclerView using DataBinding in MVVM/retrofit Architecture?

我有问题,我正在尝试在简单的项目中实现数据绑定,我只使用一个对象制作了一个示例,它很简单并且有效,但现在我正在尝试对列表执行此操作,这更难,因为我现在正在处理适配器。

所以现在我的 xml 布局在布局标签内,并在 xml 中声明了一个变量,定义了我要集成的模型,我的 activity_main 也在布局标签内

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    >
    <data>
        <variable
            name="contract"
            type="com.example.cosysimulation.models.ContractModel" />
    </data>
            <TextView
                android:id="@+id/courtier"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="22sp"
                android:text="@{contract.courtier}"
                android:layout_marginTop="8dp"
                android:layout_marginLeft="12dp"
                android:layout_toLeftOf="@+id/contratImage"
                android:textColor="@color/colorPrimaryDark"></TextView>
</layout>

这是我的 activity :

public class MainActivity extends AppCompatActivity {

    ContractsListViewModel contractsListViewModel;

    @BindView(R.id.contractList)
    RecyclerView contractList;

    RecyclerView.Adapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        ActivityMainBinding main = DataBindingUtil.setContentView(this, R.layout.activity_main);


        ButterKnife.bind(this);
        contractList.setLayoutManager(new LinearLayoutManager(this));


        contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
        contractsListViewModel.call();

        contractsListViewModel.contractList.observe(this,contractModels -> {
            adapter = new ContractListAdapter(MainActivity.this, contractModels);
            contractList.setAdapter(adapter);
        });

    }
}

这是我的适配器:

public class ContractListAdapter extends RecyclerView.Adapter<ContractListAdapter.ContractViewHolder> {

    List<ContractModel> contracts;
    Context context;
    public ContractListAdapter(Context context, List<ContractModel> contracts){
        this.context = context;
        this.contracts = contracts;
    }

    @NonNull
    @Override
    public ContractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contrat, parent, false);
        return new ContractViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ContractViewHolder holder, int position) {
        holder.bind(contracts.get(position));
    }

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

    public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

        @BindView(R.id.courtier)
        TextView courtier;

        @BindView(R.id.contratImage)
        ImageView contractImage;

        public ContractViewHolder(@NonNull View itemView){
            super(itemView);
            ButterKnife.bind(this, itemView);

       }

        public void bind(ContractModel contractModel){
            courtier.setText(contractModel.getCourtier());
        }

    }
}

这是我的合同模型:

public class ContractModel {

@SerializedName("courtier")
private String courtier;


public ContractModel(String courtier) {
    this.courtier = courtier;
}

public String getCourtier() {
    return courtier;
}

public void setCourtier(String courtier) {
    this.courtier = courtier;
}

}

任何帮助将不胜感激,我在 Youtube 上找到的教程大多只显示一个对象的绑定,这样更容易。

所以您主要要求将 DataBinding 库与 RecyclerView 适配器一起使用。

首先,我只是操纵你的主要 class 以适应 DataBinding,方法是使用数据绑定膨胀你的 RecyclerView,并省略使用 ButterKnife 库。

您可以使用 activity 的 DataBinding 对象将布局中的视图扩展到 java,并使用它们的 ID,此处 DataBinding 库从xml 通过删除下划线并将每个单词的第一个字母转换为大写(从第二个单词开始)。例如,您可以使用以下内容扩充您的 RecyclerView:main.contractList 其中 xml 中的 RecyclerView ID 为 contract_list.

public class MainActivity extends AppCompatActivity {

    ContractsListViewModel contractsListViewModel;

   // @BindView(R.id.contractList)
   // RecyclerView contractList;

    RecyclerView.Adapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        ActivityMainBinding main = DataBindingUtil.setContentView(this, R.layout.activity_main);


        // ButterKnife.bind(this);
        main.contractList.setLayoutManager(new LinearLayoutManager(this)); // "contract_list" is the id of the RecyclerView in the layout, so data binding removes the "_" and capitalize 1st letter of each word after the first one


        contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
        contractsListViewModel.call();

        contractsListViewModel.contractList.observe(this,contractModels -> {
            adapter = new ContractListAdapter(MainActivity.this, contractModels);
            main.contractList.setAdapter(adapter);
        });

    }
}

回到您的问题:无需更改您的列表项布局,因为您通过数据绑定完美地做到了这一点。

现在,对于适配器:

就像获取 activity 布局的绑定对象一样,还有一个与您的列表项布局相关联的绑定对象,您必须在适配器中构建它,您可以在 onCreateViewHolder()方法。

这里命名为ContratBinding,这里你的布局命名为"contract.xml",如果你的布局命名为list_item.xml,那么你的对象将是ListItemBinding.

然后您将自定义 ViewHolder 构造函数以接受 ContratBinding 实例而不是 View 实例。并将 binding.getRoot() 发送到它的超级 class 而不是视图;因为 getRoot() returns 在使用 DataBinding.

时根视图本身

当您在列表项布局中定义了一个名为 contract<variable> 时,您必须在适配器中使用 setContract() 方法来让 xml 布局知道这个变量是什么。当您将数据与 onBindViewHolder().

中的视图绑定时,您通常可以这样做

您的适配器将是

public class ContractListAdapter extends RecyclerView.Adapter<ContractListAdapter.ContractViewHolder> {

    List<ContractModel> contracts;
    Context context;

    public ContractListAdapter(Context context, List<ContractModel> contracts){
        this.context = context;
        this.contracts = contracts;
    }

    @NonNull
    @Override
    public ContractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.contrat, parent, false);
        // return new ContractViewHolder(view);

        ContratBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.contrat, parent, false); // ContratBinding >> as your list item layout named "contrat"
        return new ContractViewHolder(binding);

    }

    @Override
    public void onBindViewHolder(@NonNull ContractViewHolder holder, int position) {
      // holder.bind(contracts.get(position));

      holder.binding.setContract(contracts.get(position)); // "Contract" is the variable "name" provided in your <layout><data> within the list item layout


    }

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

    public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    //    @BindView(R.id.courtier)
    //    TextView courtier;

    //    @BindView(R.id.contratImage)
    //    ImageView contractImage;

    private ContratBinding binding; 

    //    public ContractViewHolder(@NonNull View itemView){
    //        super(itemView);
    //        ButterKnife.bind(this, itemView);

    //   }

        public ContractViewHolder(@NonNull ContratBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }



    //    public void bind(ContractModel contractModel){
    //        courtier.setText(contractModel.getCourtier());
    //    }

    }
}

我打算注释掉您的 ButterKnife 和不再与 DataBinding 一起使用的代码,以查看差异

希望这对您有所帮助,欢迎随时评论以获取更多帮助。