Как установить данные в строке RecyclerView, используя DataBinding в MVVM / Модификация архитектуры? - PullRequest
2 голосов
/ 12 апреля 2020

У меня проблема, я пытаюсь реализовать привязку данных в простом проекте, я сделал пример, используя только один объект, он прост и сработал, но сейчас я пытаюсь сделать это со списком, который сложнее, потому что я сейчас имею дело с адаптером.

Так что теперь мой xml макет находится внутри тега компоновки и объявил переменную в xml, определяющую модель, которую я хочу интегрировать, мой action_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:

publi c 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, показывают в основном привязку только одного объекта, что проще.

1 Ответ

1 голос
/ 12 апреля 2020

Таким образом, вы в основном просите использовать библиотеку DataBinding с RecyclerView адаптером.

Сначала я просто манипулировал вашим основным классом для адаптации с DataBinding, просто надувая ваш RecyclerView с помощью привязки данных и не используйте библиотеку ButterKnife.

вы можете накачать представления в вашем макете в java с помощью объекта DataBinding вашей деятельности и, используя их идентификаторы, здесь библиотека DataBinding адаптирует идентификаторы из xml, удаляя подчеркивания и преобразовывая первая буква каждого слова в верхнем регистре (начиная со второго слова). Например, вы можете накачать свой RecyclerView с помощью: main.contractList, где идентификатор RecyclerView в xml равен 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);
        });

    }
}

. Возврат к вашему вопросу: Нет необходимости изменять макет элемента списка, как вы это делали это отлично с привязкой данных.

Теперь, для адаптера:

Как и получение объекта привязки макета вашей активности, также есть объект привязки, связанный с макетом элемента списка, который вам нужно встроить адаптер, и вы делаете это в методе onCreateViewHolder().

здесь он называется ContratBinding, где ваш макет называется "contract. xml", если ваш макет называется list_item. xml, тогда ваш объект будет ListItemBinding.

Затем вы настроите ваш ViewHolder конструктор так, чтобы он принимал экземпляр ContratBinding вместо View. И отправьте binding.getRoot() в его суперкласс вместо представления; поскольку getRoot() возвращает само представление root, когда дело доходит до использования DataBinding.

И так как вы определили <variable> с именем contract в макете элемента списка, вы должны использовать * Метод 1038 * в вашем адаптере, чтобы макет 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, чтобы увидеть разницу

Надеюсь, что это поможет вам, и не стесняйтесь комментировать для получения дополнительной помощи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...