赞
踩
本项目实现了对Lifecycle,LiveData,ViewModel,Room,Paging,Navigation这六个官方构架组件的全面使用,组件的单独使用或者合作使用都有(PS:WorkManager bug 太多,不建议使用,我这里也不会提到他,因为我反正是有坑,迈不过去)
贴一张项目主界面图,大家可以先下载项目自己运行一下
Lifecycle主要作用是方便监听activity和Fragment生命周期
在监听activity和Fragment时,在代码里没有什么区别,和下面一样
- getLifecycle().addObserver(new IPresenter());
-
-
- class IPresenter implements LifecycleObserver {
-
- @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate( LifecycleOwner owner){
- tv.setText(tv.getText()+"onCreate\n");
- }
- 。。。。。。。
- }
但是他有一个枚举类,有点意思
- Lifecycle.State 是一个枚举类,用于描述当前 生命周期拥有者 的状态,与onStop之类的有点不一样,更加宽泛点 ,
- 通过此函数获取getLifecycle().getCurrentState(),
-
- DESTROYED:onDestroy执行中和之后
- INITIALIZED : onCreate执行前包括执行时
- CREATED:onCreate与onStop之间
- STARTED:onStart与onPause之间
- RESUMED:onResume执行中和 到 onPause开始执行前
-
- 还有一个特殊的比较方法,getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED),这个比较的当前值的等级是否等于或高于给的值,
- 也就是说State枚举类里的值越往后面,值越大,如果当前是 RESUMED ,那上面这个判断是 true
所以在我们刷新界面时,可以添加一个判断 if(getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)),保证当前activity 可见时才刷新
LIveData是一个抽象类,实现类有MutableLiveData、MediatorLiveData
MutableLiveData:这个数据类有着监听自身变化的能力,并且通过监听者模式告诉 其他组件数据更新。这个能够与ViewModel、Room配合,这个后面说
- MutableLiveData<Integer> num=new MutableLiveData<>();
- MyObserver observer;
-
- observer=new MyObserver();
- num.observe(this,observer);
-
- class MyObserver implements Observer<Integer> {
-
- @Override
- public void onChanged(@Nullable Integer integer) {
- tv.setText(""+integer);
- }
- }
MediatorLiveData 与 MutableLiveData的不同之处在于,他能统合 MutableLiveData,就像是一个ArrayList添加一个list一样,不仅数据添加进去了,而且如果添加进去的 MutableLiveData 有Observer ,而MediatorLiveData 也有Observer,在这个MutableLiveData 数据发生改变时, MediatorLiveData 的Observer也会触发。
以下代码就是将MutableLiveData添加到 MediatorLiveData,
mediatorLiveData.addSource(num,mediatorLiveData::setValue);
我们先看看我们如何获取ViewModel这个类的对象
ViewModelProviders.of(getActivity()).get(MyViewModel.class);
而这个getActivity()也可以换成Fragment的实例
现在我说一下这个为何能够做到跨组件通讯,因为它能跨组件获取同一个实例
比如:在ActivityA里有FragmentA、FragmentB,你在FragmentA通过给getActivity()得到ViewModel的实例,和你在FragmentB也这样做得到的实例是一样的。说白了,在FragmentA你如果改变这个ViewModel的LIveData这样的属性,在FragmentB能够监听的到
- viewModel= ViewModelProviders.of(getActivity()).get(MyViewModel.class);
- btn_add.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- viewModel.setNum(viewModel.getNum().getValue()+1);
- }
- });
- viewModel= ViewModelProviders.of(getActivity()).get(MyViewModel.class);
- viewModel.getNum().observe(this,new MyObserver());
Room有三个部分:实体类、数据库操控类、数据库创建类
实体类,和GreenDao、Realm一样通过注解来创建表,和修改属性
这个是实体类的属性能够是LIveData
- @Entity(tableName = "test")
- public class TestBean {
-
- @PrimaryKey
- private long id;
-
- private String name="";
-
- ......
- }
数据库操控类,你别看他是接口类,但是他通过Room框架的注解却有着真正的操控数据的能力,
- @Dao
- public interface TestDao {
-
- @Query("SELECT * FROM test")
- List<TestBean> getAll();
-
- @Query("SELECT * FROM test WHERE id = (:id)")
- TestBean getById(int id);
-
- @Insert
- void insert(TestBean testBean);
-
- @Delete
- void delete(TestBean testBean);
-
- @Update
- void update(TestBean testBean);
-
- }
数据库创建类,能够创建数据库,并且能够修改数据库版本
- @Database(entities = {TestBean.class},version = 1)
- public abstract class TestDataBase extends RoomDatabase{
-
- public abstract TestDao testDao();
-
-
- }
Room数据库的数据可以通过 给MutableLiveData,来完成对界面刷新的绑定
- data.observe(this, new Observer<List<TestBean>>() {
- @Override
- public void onChanged(@Nullable List<TestBean> testBeans) {
-
- }
- });
- data.setValue(testDao.getAll());
Paging实现的分页加载指的是:你如果有100条数据,但是你的屏幕能够显示出来的只有10条,那你把100条item都加载到RecyclerView里,就会浪费内存,那你先给RecyclerView加载20条数据,当你把RecyclerView拉到底部,Paging再给RecyclerView 20条数据,让他再加载出20条item给用户看。
还是三个步骤实现Paging的基础使用
第一个LiveData数据类,这个PageSize就是你每一次给RecyclerView的数据数量
- val allCheeses = LivePagedListBuilder(dao.allCheesesByName(), PagedList.Config.Builder()
- .setPageSize(PAGE_SIZE)
- .setEnablePlaceholders(ENABLE_PLACEHOLDERS)
- .build()).build()
第二个实现PagedListAdapter,其中还用了DiffUtil这个帮助RecyclerView优化更新的工具类
- class CheeseAdapter : PagedListAdapter<Cheese, CheeseViewHolder>(diffCallback) {
- override fun onBindViewHolder(holder: CheeseViewHolder, position: Int) {
- holder.bindTo(getItem(position))
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CheeseViewHolder =
- CheeseViewHolder(parent)
-
- companion object {
-
- private val diffCallback = object : DiffUtil.ItemCallback<Cheese>() {
- override fun areItemsTheSame(oldItem: Cheese, newItem: Cheese): Boolean =
- oldItem.id == newItem.id
-
- override fun areContentsTheSame(oldItem: Cheese, newItem: Cheese): Boolean =
- oldItem == newItem
- }
- }
- }
第三个将Adapter与数据库连接起来
viewModel.allCheeses.observe(this, Observer(adapter::submitList))
说实话代码太多了,大家还是看看项目代码比较好,这个例子是Kotlin的语言,我是从官方例子里弄出来的
首先用NavHostFragment占个位,并且设置xml来控制Fragment的显示和跳转
- <fragment
- android:id="@+id/my_nav_host_fragment"
- android:name="androidx.navigation.fragment.NavHostFragment"
- app:defaultNavHost="true"
- app:navGraph="@navigation/nav_graph_main" />
然后看看这个 nav_graph_main 写了啥,开头 这个app:startDestination 设置了默认显示Fragment
- <navigation
- app:startDestination="@id/page1Fragment">
然后接下来 在fragment标签里 指定了该fragment 的具体实现类和 action(活动)
通过id 来唯一标识, name来指定 实现类
- <fragment
- android:id="@+id/page1Fragment"
- android:name="com.example.lilingzhi.llvr.fragment.MainPage1Fragment"
- android:label="fragment_page1"
- tools:layout="@layout/fragment_main_page1">
- <action
- android:id="@+id/action_page2"
- app:destination="@id/page2Fragment"
- app:enterAnim="@anim/slide_right_in"
- app:exitAnim="@anim/slide_left_out"
- app:popEnterAnim="@anim/slide_left_in"
- app:popExitAnim="@anim/slide_right_out" />
- </fragment>
action标签描述的是Fragment跳转的 目的地和跳转动画(目的地 进入动画、出发地退出、出发地返回时 进入、目的地返回时退出), 而action标签里,id是唯一标识,app:destination指定了跳转目的地
,在Java代码通过以下触发(从出发地到目的地)
Navigation.findNavController(it).navigate(R.id.action_page2)
想要返回时(目的地到出发地)
Navigation.findNavController(it).navigateUp()
在activity点击返回键可以触发 返回动画
- override fun onSupportNavigateUp() =
- findNavController(this, R.id.my_nav_host_fragment).navigateUp()
Android官方架构组件Navigation:大巧不工的Fragment管理框架
Android 架构组件(一)——Lifecycle-Aware Components
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。