如何在尊重 MVVM 架构的同时,在回收视图中的项目内的按钮上提交点击事件?
How to submit a click event on a button inside an item in a recylcerview while respecting MVVM architecture?
我有一个问题,它是技术和概念上的,我正在尝试使用 MVVM 架构,我不想离开它,所以我有一个项目列表,每个项目都有一个删除按钮,我使用 recylcerview 显示列表,所以我使用适配器,现在当我在每一行调用一个事件时,我这样做:
这是我的Adapter,去ViewHolder里面的deleteBtn。
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) {
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.binding.setContract(contracts.get(position));
}
@Override
public int getItemCount() {
return this.contracts.size();
}
public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ContractsListViewModel listViewModel;
@BindView(R.id.courtier)
TextView courtier;
@BindView(R.id.delete)
Button deleteButton;
ContratBinding binding;
@BindView(R.id.contratImage)
ImageView contractImage;
public ContractViewHolder(@NonNull ContratBinding binding){
super(binding.getRoot());
this.binding = binding;
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
courtier.setOnClickListener(this);
deleteButton.setOnClickListener(this);
contractImage.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
if(deleteButton.getId() == v.getId()){
// action here
}
else {
Intent myIntent = new Intent(context, ContractActivity.class);
myIntent.putExtra("key", idOfContract + ""); //Optional parameters
context.startActivity(myIntent);
}
}
}
}
这是我的 MainActivity:
public class MainActivity extends AppCompatActivity {
ContractsListViewModel contractsListViewModel;
@BindView(R.id.contractList)
RecyclerView contractList;
@BindView(R.id.newContractBtn)
Button newContractBtn;
@BindView(R.id.listLoading)
ProgressBar listLoading;
@BindView(R.id.listError)
TextView listError;
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));
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
contractsListViewModel.contractList.observe(this,contractModels -> {
if(contractModels != null){
contractList.setVisibility((View.VISIBLE));
adapter = new ContractListAdapter(MainActivity.this, contractModels);
main.contractList.setAdapter(adapter);
}
});
contractsListViewModel.isLoading.observe(this,isLoading -> {
if(isLoading != null){
listLoading.setVisibility(isLoading ? View.VISIBLE : View.GONE );
if(isLoading){
listError.setVisibility(View.GONE);
contractList.setVisibility((View.GONE));
}
}
});
contractsListViewModel.error.observe(this,Error -> {
if(Error != null){
listError.setVisibility(Error ? View.VISIBLE : View.GONE );
}
});
newContractBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newContractIntent = new Intent(getApplicationContext(), NewContractActivity.class);
MainActivity.this.startActivity(newContractIntent);
}
});
}
@Override
public void onResume()
{
super.onResume();
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
}
}
因此,当我调用一个动作并观察它时,我通常会在我的 MainActivity 中执行,因为我在 MainActivity 中实例化了我的 ListViewModel,并调用了我的 ViewModel 方法,但现在我觉得我必须在此实例化相同的 ViewModel ViewHolder.
首先我不知道怎么做,因为当我在 MainActivity 中调用 'this' 时它指的是 MainActvity 但如果我在 ViewHolder 中调用它(而不是 activity ),它不会'行不通,那么我将如何在 ViewHolder 中调用我的 ViewModel。
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
其次,更重要的是,如果我这样做,我是否尊重 MVVM 架构?
因为我是如何将它概念化的:
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
// Delete Button clicked
if(deleteButton.getId() == v.getId()){
// I call the ViewModel
// call the action I want ( delete request )
// observe it in my MainActivity
}
}
任何帮助将不胜感激!
谢谢。
您必须使用绑定适配器在 MVVM 架构中使用数据进行按钮点击 binding.All 您的按钮点击将在同一 class 中进行。
<android.support.design.widget.Button
...
android:onClick="@{handlers::ButtonClicked}" />
public class MyClickHandlers {
public void onButtonClicked(View view) {
Toast.makeText(getApplicationContext(), "button clicked!", Toast.LENGTH_SHORT).show();
}
}
我会在 Activity 中创建一个回调函数并让 Activity 实现它:
interface OnDeleteClicklistener {
void onDelete(int id)
}
然后 activity 将在此方法中调用其 ViewModel:
void onDelete(int id) {
viewModel.deleteItem(id)
}
然后我不会将 ViewModel 传递给适配器,而是将 activity 作为接口传递:
recyclerView.setAdapter(MyAdapter(this, listOfItems)
适配器构造函数:
MyAdapter(OnDeleteClicklistener listener, List<Item> list)
这是您更新后的 Activity。
public class MainActivity extends AppCompatActivity {
ContractsListViewModel contractsListViewModel;
@BindView(R.id.contractList)
RecyclerView contractList;
@BindView(R.id.newContractBtn)
Button newContractBtn;
@BindView(R.id.listLoading)
ProgressBar listLoading;
@BindView(R.id.listError)
TextView listError;
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));
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
contractsListViewModel.contractList.observe(this,contractModels -> {
if(contractModels != null){
contracts.addAll(contractModels);
contractList.setVisibility((View.VISIBLE));
adapter = new ContractListAdapter(MainActivity.this, contractModels, new ContractListAdapter.OnButtonPressed() {
@Override
public void onClicked(int position) {
contractsListViewModel.callDelete(position);
}
});
main.contractList.setAdapter(adapter);
}
});
contractsListViewModel.isLoading.observe(this,isLoading -> {
if(isLoading != null){
listLoading.setVisibility(isLoading ? View.VISIBLE : View.GONE );
if(isLoading){
listError.setVisibility(View.GONE);
contractList.setVisibility((View.GONE));
}
}
});
contractsListViewModel.error.observe(this,Error -> {
if(Error != null){
listError.setVisibility(Error ? View.VISIBLE : View.GONE );
}
});
newContractBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newContractIntent = new Intent(getApplicationContext(), NewContractActivity.class);
MainActivity.this.startActivity(newContractIntent);
}
});
}
@Override
public void onResume()
{
super.onResume();
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
}
}
这是你更新后的ContractListAdapter
public class ContractListAdapter extends RecyclerView.Adapter<ContractListAdapter.ContractViewHolder> {
List<ContractModel> contracts;
Context context;
OnButtonPressed onButtonPressed;
public ContractListAdapter(Context context, List<ContractModel> contracts,OnButtonPressed onButtonPressed) {
this.context = context;
this.contracts = contracts;
this.onButtonPressed = onButtonPressed;
}
@NonNull
@Override
public ContractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
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.binding.setContract(contracts.get(position));
}
@Override
public int getItemCount() {
return this.contracts.size();
}
public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ContractsListViewModel listViewModel;
@BindView(R.id.courtier)
TextView courtier;
@BindView(R.id.delete)
Button deleteButton;
ContratBinding binding;
@BindView(R.id.contratImage)
ImageView contractImage;
public ContractViewHolder(@NonNull ContratBinding binding) {
super(binding.getRoot());
this.binding = binding;
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
courtier.setOnClickListener(this);
deleteButton.setOnClickListener(this);
contractImage.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
if (deleteButton.getId() == v.getId()) {
// action here
onButtonPressed.onClicked(position);
} else {
Intent myIntent = new Intent(context, ContractActivity.class);
myIntent.putExtra("key", idOfContract + ""); //Optional parameters
context.startActivity(myIntent);
}
}
}
interface OnButtonPressed {
void onClicked(int position);
}
}
我有一个问题,它是技术和概念上的,我正在尝试使用 MVVM 架构,我不想离开它,所以我有一个项目列表,每个项目都有一个删除按钮,我使用 recylcerview 显示列表,所以我使用适配器,现在当我在每一行调用一个事件时,我这样做:
这是我的Adapter,去ViewHolder里面的deleteBtn。
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) {
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.binding.setContract(contracts.get(position));
}
@Override
public int getItemCount() {
return this.contracts.size();
}
public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ContractsListViewModel listViewModel;
@BindView(R.id.courtier)
TextView courtier;
@BindView(R.id.delete)
Button deleteButton;
ContratBinding binding;
@BindView(R.id.contratImage)
ImageView contractImage;
public ContractViewHolder(@NonNull ContratBinding binding){
super(binding.getRoot());
this.binding = binding;
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
courtier.setOnClickListener(this);
deleteButton.setOnClickListener(this);
contractImage.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
if(deleteButton.getId() == v.getId()){
// action here
}
else {
Intent myIntent = new Intent(context, ContractActivity.class);
myIntent.putExtra("key", idOfContract + ""); //Optional parameters
context.startActivity(myIntent);
}
}
}
}
这是我的 MainActivity:
public class MainActivity extends AppCompatActivity {
ContractsListViewModel contractsListViewModel;
@BindView(R.id.contractList)
RecyclerView contractList;
@BindView(R.id.newContractBtn)
Button newContractBtn;
@BindView(R.id.listLoading)
ProgressBar listLoading;
@BindView(R.id.listError)
TextView listError;
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));
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
contractsListViewModel.contractList.observe(this,contractModels -> {
if(contractModels != null){
contractList.setVisibility((View.VISIBLE));
adapter = new ContractListAdapter(MainActivity.this, contractModels);
main.contractList.setAdapter(adapter);
}
});
contractsListViewModel.isLoading.observe(this,isLoading -> {
if(isLoading != null){
listLoading.setVisibility(isLoading ? View.VISIBLE : View.GONE );
if(isLoading){
listError.setVisibility(View.GONE);
contractList.setVisibility((View.GONE));
}
}
});
contractsListViewModel.error.observe(this,Error -> {
if(Error != null){
listError.setVisibility(Error ? View.VISIBLE : View.GONE );
}
});
newContractBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newContractIntent = new Intent(getApplicationContext(), NewContractActivity.class);
MainActivity.this.startActivity(newContractIntent);
}
});
}
@Override
public void onResume()
{
super.onResume();
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
}
}
因此,当我调用一个动作并观察它时,我通常会在我的 MainActivity 中执行,因为我在 MainActivity 中实例化了我的 ListViewModel,并调用了我的 ViewModel 方法,但现在我觉得我必须在此实例化相同的 ViewModel ViewHolder.
首先我不知道怎么做,因为当我在 MainActivity 中调用 'this' 时它指的是 MainActvity 但如果我在 ViewHolder 中调用它(而不是 activity ),它不会'行不通,那么我将如何在 ViewHolder 中调用我的 ViewModel。
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
其次,更重要的是,如果我这样做,我是否尊重 MVVM 架构?
因为我是如何将它概念化的:
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
// Delete Button clicked
if(deleteButton.getId() == v.getId()){
// I call the ViewModel
// call the action I want ( delete request )
// observe it in my MainActivity
}
}
任何帮助将不胜感激!
谢谢。
您必须使用绑定适配器在 MVVM 架构中使用数据进行按钮点击 binding.All 您的按钮点击将在同一 class 中进行。
<android.support.design.widget.Button
...
android:onClick="@{handlers::ButtonClicked}" />
public class MyClickHandlers {
public void onButtonClicked(View view) {
Toast.makeText(getApplicationContext(), "button clicked!", Toast.LENGTH_SHORT).show();
}
}
我会在 Activity 中创建一个回调函数并让 Activity 实现它:
interface OnDeleteClicklistener {
void onDelete(int id)
}
然后 activity 将在此方法中调用其 ViewModel:
void onDelete(int id) {
viewModel.deleteItem(id)
}
然后我不会将 ViewModel 传递给适配器,而是将 activity 作为接口传递:
recyclerView.setAdapter(MyAdapter(this, listOfItems)
适配器构造函数:
MyAdapter(OnDeleteClicklistener listener, List<Item> list)
这是您更新后的 Activity。
public class MainActivity extends AppCompatActivity {
ContractsListViewModel contractsListViewModel;
@BindView(R.id.contractList)
RecyclerView contractList;
@BindView(R.id.newContractBtn)
Button newContractBtn;
@BindView(R.id.listLoading)
ProgressBar listLoading;
@BindView(R.id.listError)
TextView listError;
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));
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
contractsListViewModel.contractList.observe(this,contractModels -> {
if(contractModels != null){
contracts.addAll(contractModels);
contractList.setVisibility((View.VISIBLE));
adapter = new ContractListAdapter(MainActivity.this, contractModels, new ContractListAdapter.OnButtonPressed() {
@Override
public void onClicked(int position) {
contractsListViewModel.callDelete(position);
}
});
main.contractList.setAdapter(adapter);
}
});
contractsListViewModel.isLoading.observe(this,isLoading -> {
if(isLoading != null){
listLoading.setVisibility(isLoading ? View.VISIBLE : View.GONE );
if(isLoading){
listError.setVisibility(View.GONE);
contractList.setVisibility((View.GONE));
}
}
});
contractsListViewModel.error.observe(this,Error -> {
if(Error != null){
listError.setVisibility(Error ? View.VISIBLE : View.GONE );
}
});
newContractBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newContractIntent = new Intent(getApplicationContext(), NewContractActivity.class);
MainActivity.this.startActivity(newContractIntent);
}
});
}
@Override
public void onResume()
{
super.onResume();
contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
contractsListViewModel.call();
}
}
这是你更新后的ContractListAdapter
public class ContractListAdapter extends RecyclerView.Adapter<ContractListAdapter.ContractViewHolder> {
List<ContractModel> contracts;
Context context;
OnButtonPressed onButtonPressed;
public ContractListAdapter(Context context, List<ContractModel> contracts,OnButtonPressed onButtonPressed) {
this.context = context;
this.contracts = contracts;
this.onButtonPressed = onButtonPressed;
}
@NonNull
@Override
public ContractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
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.binding.setContract(contracts.get(position));
}
@Override
public int getItemCount() {
return this.contracts.size();
}
public class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ContractsListViewModel listViewModel;
@BindView(R.id.courtier)
TextView courtier;
@BindView(R.id.delete)
Button deleteButton;
ContratBinding binding;
@BindView(R.id.contratImage)
ImageView contractImage;
public ContractViewHolder(@NonNull ContratBinding binding) {
super(binding.getRoot());
this.binding = binding;
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(this);
courtier.setOnClickListener(this);
deleteButton.setOnClickListener(this);
contractImage.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
int idOfContract = contracts.get(position).getId();
if (deleteButton.getId() == v.getId()) {
// action here
onButtonPressed.onClicked(position);
} else {
Intent myIntent = new Intent(context, ContractActivity.class);
myIntent.putExtra("key", idOfContract + ""); //Optional parameters
context.startActivity(myIntent);
}
}
}
interface OnButtonPressed {
void onClicked(int position);
}
}