概述
在Android中使用RecyclerView - Part1中,我们学习了如何创建一个自定义的RecyclerView
,接下来我们会将RecyclerView
、ViewModel
和LiveData
结合起来,对Part1的代码进行重构,实现添加产品的功能,最终的运行效果如下:
应用架构
下图是Google
推荐的应用架构,它强调了应用中的各模块应彼此独立。
-
Activity
/Fragment
: 只放UI相关代码 -
ViewModel
:存放操作数据逻辑的代码,将数据放到LiveData
中,当LiveData
数据发生变化时,会通知UI
进行 更新 -
Repository
:仓库类,控制数据的来源。例如:数据可能来自本地数据库,也可能来自服务器 -
Model
:自本地数据库模型,该类中会放增删改查本地数据库的逻辑 -
Remote Data Source
:服务器数据模型,该类中会放增删改查服务器数据的逻辑。我们可以利用Retrofit第三方库,完成网络请求的相关操作
我们按照Google
推荐的应用架构,来设计Demo
的架构,如下图:
-
MainActivity
:存放UI相关逻辑 -
ProductViewModel
:ViewModel
类,存放数据操作逻辑 -
ProductRepository
:Product
仓库类 -
FakeDataSource
:创建一个"假的"数据来源类
Java代码改造
创建FakeDataSource
首先,创建一个FakeDataSource
类,用作操作Product
的数据。这个类中主要有4个方法:
-
public void add(Product product)
:添加产品 -
public void delete(int index)
:删除产品 -
public void modify(int index, Product product)
:更新产品 -
public MutableLiveData<List<Product>> getList()
:获取产品列表
每次有数据更新时,会通过listMutableLiveData.setValue(list);
把值设置到LiveData
中,这样在MainAtivity
中就可以通过LiveData
监听到list
的变化
public class FakeDataSource {
private MutableLiveData<List<Product>> listMutableLiveData;
private List<Product> list;
public FakeDataSource() {
listMutableLiveData = new MutableLiveData<>();
list = new ArrayList<>();
listMutableLiveData.setValue(list);
}
public void add(Product product) {
list.add(product);
listMutableLiveData.setValue(list);
}
public void delete(int index) {
if (list.size() < index) {
return;
}
list.remove(index);
listMutableLiveData.setValue(list);
}
public void modify(int index, Product product) {
if (list.size() < index) {
return;
}
list.set(index, product);
listMutableLiveData.setValue(list);
}
public MutableLiveData<List<Product>> getList() {
return listMutableLiveData;
}
}
创建ProductRepository
创建仓库类ProductRepository
,这个类会调用到FakeDataSource
中的方法
public class ProductRepository {
private FakeDataSource fakeDataSource;
public ProductRepository() {
fakeDataSource = new FakeDataSource();
}
public void add(Product product) {
fakeDataSource.add(product);
}
public void delete(int index) {
fakeDataSource.delete(index);
}
public void modify(int index, Product product) {
fakeDataSource.modify(index, product);
}
public MutableLiveData<List<Product>> getList() {
return fakeDataSource.getList();
}
}
创建ProductViewModel
创建ViewModel
类ProductViewModel
,这个类会调用ProductRepository
中的方法
public class ProductViewModel extends ViewModel {
private ProductRepository repository;
public ProductViewModel() {
repository = new ProductRepository();
}
public void add(Product product) {
repository.add(product);
}
public void delete(int index) {
repository.delete(index);
}
public void modify(int index, Product product) {
repository.modify(index, product);
}
public MutableLiveData<List<Product>> getList() {
return repository.getList();
}
}
修改MyAdapter
1、在MyAdapter
中新增ProductViewModel
和构造方法。ProductViewModel
通过构造方传入到MyAdapter
中
private ProductViewModel viewModel;
public MyAdapter(ProductViewModel viewModel) {
this.viewModel = viewModel;
}
2、修改onBindViewHolder
,通过ProductViewModel
获取list
,再从list
中获取Product
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
List<Product> list = viewModel.getList().getValue();
if (list.size() > 0) {
Product product = list.get(position);
binding.name.setText(product.getName());
binding.price.setText(product.getPrice() + "¥");
binding.index.setText(String.valueOf(position + 1));
}
}
3、修改getItemCount
,通过ProductViewModel
获取list
的长度,即RecyclerView
需要展示的item
个数
@Override
public int getItemCount() {
List<Product> list = viewModel.getList().getValue();
return list.size();
}
修改Main Activity
1、增加private ProductViewModel model
;
2、创建ProductViewModel
,需要引入依赖implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.0"
3、将ProductViewModel
作为参数,传给MyAdapter
的构造方法
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MyAdapter adapter;
private ProductViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
model = new ViewModelProvider(this).get(ProductViewModel.class);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyAdapter(model);
binding.recyclerView.setAdapter(adapter);
}
}
在完成前面的代码后,运行效果如下:
运行效果因为现在没有创建产品,所以列表是空的。接下来,会在主界面增加产品添加的功能
UI界面改造
添加控件
在主界面增加2个EditText
和1个Button
,用作添加产品
对应代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/add"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="添加"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.873" />
<EditText
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:hint="名称"
android:inputType="textPersonName"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.536"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.154" />
<EditText
android:id="@+id/price"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:hint="价格"
android:inputType="numberSigned"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.515" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.61" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
实现添加产品功能
接下来,在MainActivity
中设置button
的按键监听。按下按键时,去获取EditText
的内容,并创建一个Product
类,再调用ProductViewModel
的add
方法,把产品添加进去
public class MainActivity extends AppCompatActivity {
.... ...
@Override
protected void onCreate(Bundle savedInstanceState) {
... ...
binding.add.setOnClickListener(view -> {
if (TextUtils.isEmpty(binding.name.getText())
|| TextUtils.isEmpty(binding.price.getText())) {
Toast.makeText(this, "请输入名称和价格", Toast.LENGTH_SHORT).show();
return;
}
String name = binding.name.getText().toString();
String price = binding.price.getText().toString();
Product product = new Product();
product.setName(name);
product.setPrice(Float.parseFloat(price));
model.add(product);
});
}
}
实现列表更新功能
设置ProductViewModel
中的LiveData
数据监听,当MutableLiveData<List<Product>>
发生变化时,会回调onChanged
方法,再通过adapter.notifyDataSetChanged()
实现list的更新
public class MainActivity extends AppCompatActivity {
... ...
@Override
protected void onCreate(Bundle savedInstanceState) {
... ...
model.getList().observe(this, new Observer<List<Product>>() {
@Override
public void onChanged(List<Product> products) {
adapter.notifyDataSetChanged();
}
});
}
}
运行效果
所有代码已经编写完成,最终运行效果如下:
运行效果
网友评论