Android JetPack以及框架MVVM

JetPack

文章目录

  • JetPack
  • 前言
  • 一、LifeCycle
    • 1.Activity/Fragment的使用
    • 2.Service中使用
    • 3.application中使用(ProcessLifecycleOwner)
  • 二、Navigation
    • 1.使用Navigation
    • 2. 使用safe args传递参数
    • 3.NavigationUI的使用方法
    • 4.深层链接DeepLink
      • 1.PendingIntent的方式
      • 2.URL的方式
  • 三、ViewModel与LiveData
  • 四、Room
    • 1建立数据库
    • 2Room结合LiveData ViewModel使用
  • 五、WorkManager
    • 1 OneTimeWorkRequest
    • 2 PeriodicWorkRequest
    • 3 任务链
  • 五、DataBinding
    • 1 二级页面绑定
    • 2 BindingAdapter
  • 六、Paging(待补充3种DataSourse用法)
    • 1 Paging的3个核心类
    • 2 3种DataSource
  • 七、MVVM架构
    • 1使用Jetpack组件构建MVVM应用程序


前言

Android JetPack以及框架MVVM_第1张图片

一、LifeCycle

LifeCycle完美解决了组件对页面生命周期的依赖问题 使组件能够自己管理其生命周期 而无须在页面中对其进行管理

1.Activity/Fragment的使用

首先编写生命监测者

public class MyLifeListener implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void create(){
        Log.d("Life","On_create");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    private void resume(){
        Log.d("Life","On_resume");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void destory(){
        Log.d("Life","On_destory");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    private void pause(){
        Log.d("Life","On_pause");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void start(){
        Log.d("Life","On_start");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void sop(){
        Log.d("Life","On_stop");
    }
}
public class MainActivity extends AppCompatActivity implements LifecycleOwner, View.OnClickListener {
    private MyLifeListener myLifeListener;
    private Button starts,stops;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myLifeListener=new MyLifeListener();
        getLifecycle().addObserver(myLifeListener);
    }

在各个生命周期间便会自动执行对应的方法

2.Service中使用

service中使用比较特殊首先创建服务我这边定义的是Ms

public class Ms extends LifecycleService {
    private MyserviceObserver myserviceObserver;
    public Ms(){
        myserviceObserver=new MyserviceObserver();
        getLifecycle().addObserver(myserviceObserver);
    }
}

继承 LifecycleService 后才能使用添加生命监测者 这样的Ms也就是我们自定义的class其本身就是一个服务

public class MyserviceObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    private void createS(){
        Log.d("Ls","On_create");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void destoryS(){
        Log.d("Ls","On_destory");
    }
}

随后在Activity中定义两个按钮来starservice和stopservice来测试

同样的在其对应的生命周期中对应的方法 (如果运行没反应请检查AndroidManifest.xml中是否注册Ms服务)

3.application中使用(ProcessLifecycleOwner)

application中使用能监测整个app的生命周期

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(new MyLifeListener());
    }
}

其中MylifeListener就是我们第一小节中创建的一个生命监测者

二、Navigation

1.Navigation Graph 这是一种新型的XML资源文件 其中包含应用程序所有的页面 以及页面间的关系
2.NavHostFragment 这是一个特殊的Fragment 你可以认为它是其他Fragment的“容器” Navigation Graph中的Fragment正是通过NavHostFragment进行展示的
3.NavController 这是一个Java/Kotlin对象 用于在代码中完成Navigation Graph中具体的页面切换工作

当你想切换Fragment时 使用NavController对象 告诉它你想要去Navigation Graph中的哪个Fragment NavController会将你想去的Fragment展示在NavHostFragment中

1.使用Navigation

Android JetPack以及框架MVVM_第2张图片
Android JetPack以及框架MVVM_第3张图片
起个名字定义一下类型 为Navigation点击OK后会生成标记2的文件夹以及文件
随后Android Studio可能会询问你 是否自动帮你添加相关依赖 单击OK即可

implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'androidx.navigation:navigation-ui:2.3.0'

亦或者手动添加至app下gradle

Android JetPack以及框架MVVM_第4张图片

Android JetPack以及框架MVVM_第5张图片
然后我们在这里创建两个fragment

Android JetPack以及框架MVVM_第6张图片
点击这个按钮就可以编辑这个fragment的下一个目的地


    
        
       

    
    
        
    


这是编辑后nav_graph中的代码 可以大致看一下

   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_one, container, false);
        
        view.findViewById(R.id.tv11).setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_oneFragment_to_twoFragment));
        return view;
    }

在fragment中定义按钮进行跳转 这是 第一种方法

   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_one, container, false);
        
          view.findViewById(R.id.tv11).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Navigation.findNavController(v).navigate(R.id.action_oneFragment_to_twoFragment);
            }
        });
        return view;
    }

在fragment中定义按钮进行跳转 这是 第二种方法

2. 使用safe args传递参数

实现跳转后我们利用safe args来进行传值
Android JetPack以及框架MVVM_第7张图片

classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0-alpha01'

在最外层gradle图中标记处加入代码

接着在app下gradle加入

apply plugin: 'androidx.navigation.safeargs'

Android JetPack以及框架MVVM_第8张图片

然后在nav_graph中写入argument

写入后会生 “fragment名字+Args”

   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_one, container, false);
        Bundle bundle=new oneFragmentArgs.Builder().setUsername("如果我为空 我 就是 2货").build().toBundle();
        view.findViewById(R.id.tv11).setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_oneFragment_to_twoFragment,bundle));
        return view;
    }

写入值 两种跳转方法都可以

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_two, container, false);
        tv22= view.findViewById(R.id.tv22);
        Bundle bundle=getArguments();
        if(bundle!=null) {
            tv22.setText(oneFragmentArgs.fromBundle(bundle).getUsername());
        }
        view.findViewById(R.id.tv22).setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_twoFragment_to_oneFragment));
        return view;
    }

拿值方法

3.NavigationUI的使用方法

导航图是Navigation组件中很重要的一部分 它可以帮助我们快速了解页面之间的关系 再通过NavController便可以完成页面的切换工作 而在页面的切换过程中 通常还伴随着App bar中menu菜单的变化 对于不同的页面 App bar中的menu菜单很可能是不一样的 App bar中的各种按钮和菜单 同样承担着页面切换的工作 例如 当ActionBar左边的返回按钮被单击时 我们需要响应该事件 返回到上一个页面 既然Navigation和App bar都需要处理页面切换事件 那么 为了方便管理 Jetpack引入了NavigationUI组件 使App bar中的按钮和菜单能够与导航图中的页面关联起来

Android JetPack以及框架MVVM_第9张图片
其中navController()中就是布局的fragment的id

Android JetPack以及框架MVVM_第10张图片
设置menu

Android JetPack以及框架MVVM_第11张图片
Android JetPack以及框架MVVM_第12张图片

item的id与nav——graph中对应起来

  navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                //切换事件
            }
        });

切换中的事件方法

4.深层链接DeepLink

1.PendingIntent的方式

通过sendNotification()方法向通知栏发送一条通知 模拟用户收到一条推送的情况 我们需要在代码中设置一个PendingIntent

    //设置一个通知
    private void sendNotification(){
        if(this==null){
            return;
        }
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            int importance=NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel=new NotificationChannel("aabb","ChannelName",importance);
            channel.setDescription("description");
            NotificationManager notificationManager=this.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
        NotificationCompat.Builder builder=new NotificationCompat.Builder(this, "aabb")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("一个标题")
                .setContentText("我是内容")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(getPendingIntent())
                .setAutoCancel(true);
        NotificationManagerCompat notificationManagerCompat=NotificationManagerCompat.from(this);
        notificationManagerCompat.notify(1,builder.build());
    }

    private PendingIntent getPendingIntent() {
        if(this!=null){
            Bundle bundle=new Bundle();
            bundle.putString("username","I love you lili");
            return Navigation
                    .findNavController(this,R.id.nav_host_fragment)//activity布局中fragment的id
                    .createDeepLink()
                    .setGraph(R.navigation.nav_graph)//设置navigation
                    .setDestination(R.id.twoFragment)//设置跳转的fragment的id
                    .setArguments(bundle)
                    .createPendingIntent();
        }
        return null;
    }

这样通过pendingintent我们就可以跳转页面了

2.URL的方式

在导航图中为页面添加标签 在app:uri属性中填入的是你的网站的相应Web页面地址 后面的参数会通过Bundle对象传递到页面中


        
    

为Activity设置标签 当用户在Web页面中访问你的网站时 应用程序便能得到监听
Android JetPack以及框架MVVM_第13张图片

我们可以在Google app中输入相应的Web地址 也可以通过adb工具 使用命令行来完成操作

adb shell am start -a android.intent.action.VIEW
-d "http : / / www . whatsyourname.com/I love you li"

三、ViewModel与LiveData

Android JetPack以及框架MVVM_第14张图片
ViewModel的生命周期 由此可见ViewModel不受横屏竖屏切换的影响

添加依赖

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
}

ViewModel用于存放页面所需要的各种数据 不仅如此 我们还可以在其中放一些与数据相关的业务逻辑 例如 我们可以在ViewModel中进行数据的加工 获取等操作 因此 ViewModel中的数据可能会随着业务的变化而变化
对页面来说 它并不关心ViewModel中的业务逻辑 它只关心需要展示的数据是什么 并且希望在数据发生变化时 能及时得到通知并做出更新 LiveData的作用就是 在ViewModel中的数据发生变化时通知页面 因此 LiveData通常被放在ViewModel中使用 用于包装ViewModel中那些需要被外界观察的数据 我们从LiveData(实时数据)这个名字 也能大概推测出它的特性与作用

public class TimerViewModel extends ViewModel {
    private Timer timer;	
    private MutableLiveData number;	//用MutableLiveData包装起来

    public LiveData getNumber(){
        if(number==null){
            number=new MutableLiveData<>();
        }
        return number;
    }

    public void startimer(){
        if(timer==null){
            number.setValue(0);
            timer=new Timer();
            TimerTask timerTask=new TimerTask() {
                @Override
                public void run() {
                    number.postValue(number.getValue()+1);//setvalue只能在主线程 而postvalue则两者皆可
                }
            };
            timer.schedule(timerTask,1000,1000);
        }
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        timer.cancel();
    }
    
}

创建TimerViewModel类

public void doit(){
        tv11=view.findViewById(R.id.tv11);
        TimerViewModel timerViewModel=new ViewModelProvider(this).get(TimerViewModel.class);
        MutableLiveData liveData= (MutableLiveData) timerViewModel.getNumber();//得到ViewModel中的LiveData
			
		//使用liveData.observe观察viewModel中的数据变化
        liveData.observe(getActivity(), new Observer() {
            @Override
            public void onChanged(Integer integer) {
                tv11.setText(integer+"");
            }
        });
        timerViewModel.startimer();
    }

以上代码是在fragment中调用的 可以自己尝试在activity中调用

四、Room

Android采用Sqlite作为数据库存储 由于Sqlite代码写起来烦琐且容易出错 因此 开源社区逐渐出现了各种ORM(Object Relational Mapping)库 这些开源ORM库都是为了方便Sqlite的使用而出现的 包括数据库的创建 升级 增/删/改/查等操作 常见的ORM库有ORMLite GreenDAO等 Google也意识到了推出自家ORM库的必要性 于是有了Room Room与其他ORM库一样 也是在Sqlite上提供了一层封装

加入依赖

implementation 'androidx.room:room-runtime:2.2.2'
annotationProcessor 'androidx.room:room-compiler:2.2.2'

1建立数据库

创建一个Entity

@Entity(tableName = "Dog")
public class Dog {

    @PrimaryKey(autoGenerate = true)//设置自动增长
    @ColumnInfo(name = "id",typeAffinity = ColumnInfo.INTEGER) //name指数据库中的名字 typeAffinity指数据类型
    private int id;

    @ColumnInfo(name = "name",typeAffinity = ColumnInfo.TEXT)
    private String name;

    @ColumnInfo(name = "age",typeAffinity = ColumnInfo.TEXT)
    private String age;


    public Dog(int id, String name, String age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    /**
     *
     * 由于Room只能识别和使用一个构造器 如果希望定义多个构造器可以使用工gnore标签 让 Room忽略这个构造器
     * 不仅如此 @Ignore标签还可用于字段
     * Room 不会持久化被@Ignore标签标记过的字段的数据
     */
    @Ignore
    public Dog(int id, String name) {
        this.id = id;
        this.name = name;
    }

}

一个Dao层

@Dao
public interface DogDao {
    @Insert//增加
    void InsertDog(Dog dog);

    @Update//修改
    void UpdateDog(Dog dog);

    @Delete//删除
    void DeleteDog(Dog dog);

    @Query("SELECT * FROM Dog")//查看全部
    List GetDogList();

    @Query("SELECT * FROM Dog WHERE id=:id")//根据id查看单个
    Dog GetOneDog(int id);

}

然后是数据库的建立和数据库升级的操作

@Database(entities = {Dog.class},version = 1)//如果要加入多个表用,分开 每次更新表数据需要在version后加1
public abstract class MyDatatable extends RoomDatabase {

    private static final String DATABASE_NAME="my_db";

    private static MyDatatable myDatatable;

    private static Migration MIGRATION1_2=new Migration(1,2){//当前版本为1 升级版本加1为2

        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
                //升级的相关操作
        }
    };

    public static synchronized MyDatatable getInstance(Context context){
        if(myDatatable==null){
            myDatatable= Room.databaseBuilder(context.getApplicationContext(),MyDatatable.class,DATABASE_NAME).build();
            //myDatatable= Room.databaseBuilder(context.getApplicationContext(),MyDatatable.class,DATABASE_NAME).addMigrations(MIGRATION1_2).build();
            //上方数据库升级代码
        }
            return myDatatable;
    }
    public abstract DogDao dogDao();
}

2Room结合LiveData ViewModel使用

@Dao
public interface DogDao {
    @Insert//增加
    void InsertDog(Dog dog);

    @Update//修改
    void UpdateDog(Dog dog);

    @Delete//删除
    void DeleteDog(Dog dog);

    @Query("SELECT * FROM Dog")//查看全部
    LiveData> GetDogList();                          //用LiveData包起来

    @Query("SELECT * FROM Dog WHERE id=:id")//根据id查看单个
    Dog GetOneDog(int id);

}

激将上面的Dao层中返回的list用LiveData包起来

在使用ViewModel时 不能将任何类型的Context或含有Context引用的对象传入ViewModel 因为这可能会导致内存泄漏 但如果你希望在ViewModel中使用Context 该怎么办呢 可以使用AndroidViewModel类 它继承自ViewModel 并接收Application作为Context 这意味着 它的生命周期和Application是一样的 那么这就不算是一个内存泄漏了

public class DogViewModel extends AndroidViewModel {
    private MyDatatable myDatatable;        //数据库
    private LiveData> livedatadog;        //LiveData包装的数据

    public DogViewModel(@NonNull Application application) {
        super(application);
        myDatatable=MyDatatable.getInstance(application);
        livedatadog=myDatatable.dogDao().GetDogList();
    }
    public LiveData> getLivedatadog(){
        return livedatadog;
    }
}
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DogViewModel dogViewModel=new ViewModelProvider(this).get(DogViewModel.class);
        dogViewModel.getLivedatadog().observe(this, new Observer>() {
            @Override
            public void onChanged(List dogs) {
                //时时监测数据变化 并进行处理操作
            }
        });
    }

Activity中的调用

五、WorkManager

1.针对的是不需要及时完成的任务
例如 发送应用程序日志 同步应用程序数据 备份用户数据等 站在业务需求的角度 这些任务都不需要立即完成 如果我们自己来管理这些任务 逻辑可能会非常复杂 若API使用不恰当 可能会消耗大量电量
2.保证任务一定会被执行
WorkManager能保证任务一定会被执行 即使应用程序当前不在运行中 甚至在设备重启过后 任务仍然会在适当的时刻被执行 这是因为WorkManager有自己的数据库 关于任务的所有信息和数据都保存在该数据库中因此 只要任务交给了WorkManager 哪怕应用程序彻底退出 或者设备被重新启动 WorkManager依然能够保证完成你交给它的任务
3.兼容范围广
WorkManager最低能兼容API Level 14 并且不需要你的设备安装Google Play Services 因此 不用过于担心兼容性问题 因为API Level 14已经能够兼容几乎100%的设备

添加依赖

 implementation 'androidx.work:work-runtime:2.2.0'
public class TestWork extends Worker {

    public TestWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {

        //所有操作的代码都将在这里编写
        return Result.success();//返回有3种结果  Result.success()代表成功 Result.failure()代表失败 Result.retry()代表需要重新执行

    }
}

然后创建一个TestWork用于测试

  //设置触发条件
        Constraints constraints=new Constraints.Builder()
                .setRequiresCharging(true)  //设备处于充电状态
                .setRequiredNetworkType(NetworkType.CONNECTED)//设备处于联网状态
                .setRequiresBatteryNotLow(true)//设备电量充足
                .build();
  OneTimeWorkRequest oneTimeWorkRequest=new OneTimeWorkRequest.Builder(TestWork.class)
                .setConstraints(constraints)//设置触发条件
                //.setInitialDelay(10, TimeUnit.SECONDS)//设置出发时间(这边设置为10秒)

                .setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.SECONDS)
                //假如Worker线程的执行出现了异常 如服务器宕机 你可能希望过一段时间后 重试该任务 那么可以在Worker的doWork()方法中返回Result.retry() 系统会有默认的指数退避策略来帮你重试任务 也可以通过setBackoffCriteria()方法来自定义指数退避策略

                .addTag("testtag")
                //设置tag标签后 你就可以通过该标签跟踪任务的状态:WorkManager.getWork InfosByTagLiveData(String tag);也可以取消任务:WorkManager.cancelAll WorkByTag(String tag)

                .build();

        //将任务配置好之后 需要将其提交给系统 WorkManager.enqueue()方法用于将配置好的WorkRequest交给系统来执行
        WorkManager.getInstance(this).enqueue(oneTimeWorkRequest);

WorkRequest是一个抽象类 它有两种实现方式——OneTimeWorkRequest和PeriodicWorkRequest 分别对应的是一次性任务和周期性任务

1 OneTimeWorkRequest

任务在提交给系统后 可以通过WorkInfo获知任务的状态 WorkInfo包含任务的id tag Worker对象传递过来的outputData 以及任务当前的状态 有3种方式可以得到WorkInfo对象
● WorkManager.getWorkInfosByTag()
● WorkManager.getWorkInfoById()
● WorkManager.getWorkInfosForUniqueWork()

如果希望实时获知任务的状态,这3个方法还有对应的LiveData方法。
● WorkManager.getWorkInfosByTagLiveData()
● WorkManager.getWorkInfoByIdLiveData()
● WorkManager.getWorkInfosForUniqueWorkLiveData()

通过LiveData 我们便可以在任务状态发生变化时收到通知

WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.getId())
                .observe(MainActivity.this, new Observer() {
                    @Override
                    public void onChanged(WorkInfo workInfo) {
                        Log.d("WorkInfo",workInfo+"");
                    }
                });

/
WorkManager与Worker之间的参数传递
WorkManager通过setInputData()方法向Worker传递数据 数据的传递通过Data对象来完成 需要注意的是 Data只能用于传递一些小的基本类型的数据 且数据最大不能超过10KB

 Data data=new Data.Builder().putString("hi","hello verybody").build(); //创建一个数据

        OneTimeWorkRequest oneTimeWorkRequest=new OneTimeWorkRequest.Builder(TestWork.class)
                .setInputData(data)//加入workrequest中
                .build();
  @NonNull
    @Override
    public Result doWork() {

        String data=getInputData().getString("hi");//接收外来数据

        Data dt=new Data.Builder().putString("hi","hello verybody").build();//需要传出去的数据

        //所有操作的代码都将在这里编写
        return Result.success(dt);//数据放入括号中传出

    }
 WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.getId())
                .observe(MainActivity.this, new Observer() {
                    @Override
                    public void onChanged(WorkInfo workInfo) {
                        if(workInfo!=null&&workInfo.getState()==WorkInfo.State.SUCCEEDED){
                            String data=workInfo.getOutputData().getString("hi");
                        }
                    }
                });

2 PeriodicWorkRequest

OneTimeWorkRequest和PeriodicWorkRequest 分别对应的是一次性任务和周期性任务 一次性任务在任务成功执行后 便彻底结束 而周期性任务则会按照设定的时间定期执行 二者使用起来没有太大差别 需要注意的是 周期性任务的间隔时间不能少于15分钟

//设置触发条件
        Constraints constraints=new Constraints.Builder()
                .setRequiresCharging(true)  //设备处于充电状态
                .setRequiredNetworkType(NetworkType.CONNECTED)//设备处于联网状态
                .setRequiresBatteryNotLow(true)//设备电量充足
                .build();


        PeriodicWorkRequest periodicWorkRequest=new PeriodicWorkRequest.Builder(TestWork.class,15,TimeUnit.MINUTES) //设置15分钟一次
                .setConstraints(constraints)
                .build();

3 任务链

如果有一系列的任务需要按顺序执行 那么可以利用WorkManager.begin With().then().then()…enqueue()的方式构建任务链 例如 在上传数据之前 可能需要先对数据进行压缩

 WorkManager.getInstance(this)
                .beginWith(oneTimeWorkRequest)
                .then(twoTimeWorkRequest)
                .enqueue();

假设除了压缩数据 还需要更新本地数据 压缩数据与更新本地数据二者没有先后顺序的区别 但与上传数据存在先后顺序

 WorkManager.getInstance(this)
                .beginWith(oneTimeWorkRequest,twoTimeWorkRequest)
                .then(threeTimeWorkRequest)
                .enqueue();

假设有更复杂的任务链 那么还可以考虑使用WorkContinuation.combine()方法 将任务链组合起来使用 在下面的代码中

 WorkContinuation workContinuation1=WorkManager.getInstance(this)
                .beginWith(oneTimeWorkRequest)
                .then(twoTimeWorkRequest);
        WorkContinuation workContinuation2=WorkManager.getInstance(this)
                .beginWith(threeTimeWorkRequest)
                .then(fourTimeWorkRequest);
        List list=new ArrayList<>();
        list.add(workContinuation1);
        list.add(workContinuation2);
        WorkContinuation.combine(list).then(fiveTimeWorkRequest).equals();

五、DataBinding

app下的gradle中 加入

android {
...

dataBinding{
        enabled true
    }
    
    }

Android JetPack以及框架MVVM_第15张图片
在 最外布局按alt加回车出现第一个 点击

Android JetPack以及框架MVVM_第16张图片
在data中定义实体类 也可以自定义字段

 				

                

布局文件名为activity_main_view.xml 因此 对应的Binding类为ActivitymainBinding
在Activity中修改代码

ActivityMainBinding activityMainBinding= DataBindingUtil.setContentView(this,R.layout.activity_main);

然后在Activity中
加入

activityMainBinding.setDog(BR.dog,dog);

代码中的BR 相当于Android中常用的R类
BR.dog 中的 dog就是代码中自己定义的name dog

1 二级页面绑定

将在一级页面中通过标签进行引用的页面 定义为二级页面

 
//二级页面同时也需要定义data
 
        

2 BindingAdapter

写入加载图片的依赖

implementation 'com.squareup.picasso:picasso:2.71828'

Manifest中加入网络权限


public class ImageViewBindingAdapter {
    @BindingAdapter("image")
    public static void setImage(ImageView imageView, String imageUrl){
        if(!TextUtils.isEmpty(imageUrl)){
            Picasso.get()
                    .load(imageUrl)//加载图片
                    .placeholder(R.drawable.ic_default)//默认显示的图片
                    .error(R.drawable.ic_error)//加载失败显示的图片
                    .into(imageView);
        }else{
            imageView.setBackground(Color.White;//无图片时的加载
        }
    }
}

        
    
 
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding activityMainBinding= DataBindingUtil.setContentView(this,R.layout.activity_main);
        activityMainBinding.setNetworkImage("https:XXXXXXX.jpg");
        }

活动中的代码

六、Paging(待补充3种DataSourse用法)

分页加载的一个组件

支持的三种形式
Android JetPack以及框架MVVM_第17张图片

1 Paging的3个核心类

● PagedListAdapter.
我们知道 RecyclerView通常需要搭配Adapter使用 若你希望RecyclerView能结合Paging组件使用 那么首先需要让RecyclerView的Adapter继承自PagedListAdapter
● PagedList.
PagedList负责通知DataSource何时获取数据 以及如何获取数据 例如 何时加载第一页/下一页 第一页加载的数量 提前多少条数据开始执行预加载等 需要注意的是 从DataSource获取的数据将存储在PagedList中
● DataSource.
在DataSource中执行具体的数据载入工作 注意 数据的载入需要在工作线程中进行 数据可以来自网络 也可以来自本地数据库 如Room。根据分页机制的不同,Paging为我们提供了3种DataSource

2 3种DataSource

● PositionalDataSource.
适用于可通过任意位置加载数据 且目标数据源数量固定的情况 例如 若请求时携带的参数为start=2&count=5 则表示向服务端请求从第2条数据开始往后的5条数据

● PageKeyedDataSource.
适用于数据源以“页”的方式进行请求的情况 例如 若请求时携带的参数为page=2&pageSize=5 则表示数据源以5条数据为一页 当前返回第二页的5条数据

● ItemKeyedDataSource.
适用于当目标数据的下一页需要依赖于上一页数据中最后一个对象中的某个字段作为key的情况 此类分页形式常见于评论功能的实现 例如 若上一页数据中最后一个对象的key为9527 那么在请求下一页时 需要携带参数since=9527&pageSize=5 则服务器会返回key=9527之后的5条数据

七、MVVM架构

MVVM即Model-View-ViewModel的缩写 它的出现是为了将图形界面与业务逻辑 数据模型进行解耦 MVVM也是Google推崇的一种Android项目架构模型 在前面的章节中所学习的Jetpack组件 大部分都是为了能够更好地架构MVVM应用程序而设计的

Android JetPack以及框架MVVM_第18张图片

1使用Jetpack组件构建MVVM应用程序

Android JetPack以及框架MVVM_第19张图片
● Model:使用Room数据库存储用户个人信息
● API:通过Retrofit库请求GitHub API
● Application:在其中实例化Room和Retrofit对象 以便统一管理和全局调用
● Repository:构建Repository层 用于处理Room中的数据与API接口得来的网络数据之间的业务关系
● ViewModel:从Repository层中获取数据 ViewModel不需要关心数据的来源是Room还是API接口
● View:我们的Activity和布局文件 将会用到DataBinding组件

你可能感兴趣的:(Android,移动开发,jetpack,android)