【问题标题】:How to set data in a row of RecyclerView using DataBinding in MVVM/retrofit Architecture?如何在 MVVM/retrofit Architecture 中使用 DataBinding 在 RecyclerView 的一行中设置数据?
【发布时间】:2020-07-24 15:07:00
【问题描述】:

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

所以现在我的 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>

这是我的活动:

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());
        }

    }
}

这是我的合同模型:

公共类 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 上找到的教程主要显示了仅一个对象的绑定,这更容易。

【问题讨论】:

  • 您好,您使用的是 ButterKnife 库
  • 那么,您确定要改用 DataBinding 库吗?
  • 可以显示ContractModel吗?
  • 检查编辑,我已经编辑了
  • 对不起,我明白了.. 只是以为这是主要布局

标签: android mvvm data-binding retrofit


【解决方案1】:

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

首先,我只是通过使用数据绑定来扩展你的RecyclerView,并使用ButterKnife 库省略了你的主类以适应DataBinding

您可以使用活动的DataBinding 对象将布局中的视图膨胀到java 中,并使用它们的ID,这里DataBinding 库通过删除下划线并将每个单词的第一个字母转换为大写来适应xml 中的ID (从第二个单词开始)。例如,您可以使用 main.contractList 为您的 RecyclerView 充气,其中 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() 发送到其超类而不是视图;因为getRoot() 在使用DataBinding 时会返回根视图本身。

当您在列表项布局中定义了一个名为contract&lt;variable&gt; 时,您必须在适配器中使用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 一起使用的代码,以查看区别

希望这对您有所帮助,并随时发表评论以获得进一步的帮助。

【讨论】:

  • 返回新的 ViewHolder(绑定)?我认为您的意思是返回新的 ContractViewHolder .. 也是您的 mContext,我将其替换为 parent.getParent() .. 另外,我尝试使代码保持简单,因为我在每一行中都有一个按钮和图像,然后单击事件按钮.. 无论如何,谢谢,我现在就试试你的代码
  • @TaouBen 随时...你是对的对不起我没有运行它,只是自定义了你的代码..
猜你喜欢
  • 2021-06-22
  • 2018-06-23
  • 2017-01-10
  • 2018-01-28
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多