美文网首页
在Android中使用RecyclerView - Part2

在Android中使用RecyclerView - Part2

作者: 伤口不该结疤 | 来源:发表于2021-03-20 15:32 被阅读0次

    概述

    在Android中使用RecyclerView - Part1中,我们学习了如何创建一个自定义的RecyclerView,接下来我们会将RecyclerViewViewModelLiveData结合起来,对Part1的代码进行重构,实现添加产品的功能,最终的运行效果如下:

    运行效果

    应用架构

    下图是Google推荐的应用架构,它强调了应用中的各模块应彼此独立。

    推荐应用架构
    • Activity/Fragment : 只放UI相关代码
    • ViewModel:存放操作数据逻辑的代码,将数据放到LiveData中,当LiveData数据发生变化时,会通知UI进行 更新
    • Repository:仓库类,控制数据的来源。例如:数据可能来自本地数据库,也可能来自服务器
    • Model:自本地数据库模型,该类中会放增删改查本地数据库的逻辑
    • Remote Data Source:服务器数据模型,该类中会放增删改查服务器数据的逻辑。我们可以利用Retrofit第三方库,完成网络请求的相关操作

    我们按照Google推荐的应用架构,来设计Demo的架构,如下图:

    Demo的应用架构
    • MainActivity:存放UI相关逻辑
    • ProductViewModelViewModel类,存放数据操作逻辑
    • ProductRepositoryProduct仓库类
    • 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

    创建ViewModelProductViewModel,这个类会调用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类,再调用ProductViewModeladd方法,把产品添加进去

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

    运行效果

    所有代码已经编写完成,最终运行效果如下:

    运行效果

    参考

    应用架构指南

    完整代码

    https://github.com/zhanghuamao/RecyclerViewDemo02

    相关文章

      网友评论

          本文标题:在Android中使用RecyclerView - Part2

          本文链接:https://www.haomeiwen.com/subject/gvcwcltx.html