异步操作(二)

本篇将讲解Android夜间模式,用添加蒙版的方式来实现

异步操作

异步编程 之一 异步操作+Rxjava

讲到异步编程那就得先介绍一下Android当前的架构

Android当前架构

在Android操作系统启动之后,会启动一个名为Zygote的进程,Zygote是负责创建其它大部分应用程序进程的一个进程。Zygote进程启动、加载核心程序库和数据结构到内存后会创建一个Dalvik虚拟机(DVM)进程(SystemServer),这个进程包含了大部分的系统服务(包括上面管理Activity,也就是ActivityManagerService)之后Zygote会为这个app创建一个DVM,在直接fork出一个子进程,这种架构的好处是同时启动多个App 时,多个App进程可以访问共享内存。

简单来说就是,先创建Zygote,在通过Zygote创建SystemServer进行(系统服务进程),最后在要创建的App创建Dalvik虚拟机

Zygote是Android系统创建进程的核心进程,负责启动Dalvik虚拟机,加载一些必要的系统资源和系统类,顺便启动SystemServer进行,最后在等待并处理App创建请求

异步编程

先来讲讲Android中最常见的异步方式

AsyncTask

AsyncTask在Kotlin中已被协程替代(可去<异步编程(三)>了解详情),所以下方将会用Java来进行讲解

介绍

AsyncTask是Android中自带的一个轻量级异步类,可以通过它轻松的实现工作线程和UI线程之间的通讯或切换

使用

AsyncTask是一个抽象类,想要使用它,那么就得先创建一个类来继承它,在重写它的4个方法(一般只用重写4个方法)

  • 需要重写的4个方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //这个就是要在后台做的工作,他将运行在后台工作线程上
    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    //这个时开始执行前的操作,运行在主线程上
    @MainThread
    protected void onPreExecute();

    //doInBackground完成后调用
    @MainThread
    protected void onPostExecute(Result result);

    //实时更新,通过在doInBackground中调用publishProgress()方法
    @MainThread
    protected void onProgressUpdate(Progress... values);
  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class AsyncTaskDome extends AppCompatActivity {
    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_async_task_dome);
    progressDialog = new ProgressDialog(this);
    new Download().execute("下载地址");
    }
    -----------------------------------------------
    public class Download extends AsyncTask<String, Integer, Boolean> {

    @Override
    protected void onPreExecute() {
    progressDialog.show();
    //初始化进度条
    }

    @Override
    protected Boolean doInBackground(String... strings) {
    //这里假装在进行下载
    Uri uri = Uri.parse(strings[0]);
    return true;
    }

    @Override
    protected void onProgressUpdate(Integer... integers) {
    //这里对进度条进行更新进度
    progressDialog.setMessage(String.valueOf(integers[0]));
    }
    }
    }

    上方的代码中,我创建了一个Download类用来继承AsyncTask,并重写了它的4个方法。之后就只需要在Activity中创建一个Download对象,然后执行execute添加到队列中去

RxJava

介绍

Rxjava是一个用来实现异步的、基于事件的第三方库(就把它理解成Android Handler 的升级版就行了)

概念

我们先来了解一下Rxjava的概念

  • RxJava的异步实现,就是通过一种扩展的观察者模式来实现的
  • Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer

使用

  1. 先创建一个Observer观察者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    object : Observer<String?> {
    override fun onNext(t: String) {
    println("onNext --> $t")
    }

    override fun onError(e: Throwable) {
    println("on error --> $e")
    }

    override fun onSubscribe(d: Disposable) {
    println("onSubscribe --> $d")
    }

    override fun onComplete() {
    println("onComplete")
    }
    }
  2. 再创建 Observable 被观察者

    1
    2
    3
    4
    val observable: Observable<String> = Observable.create{
    it.onNext("continue!")
    it.onComplete()
    }
  3. 最后再进行关联

    1
    observable.subscribe(observer)
  4. 当然,也可以直接使用链式调用来写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Observable.create(ObservableOnSubscribe<String> {
    it.onNext("1")
    it.onNext("2")
    it.onNext("3")
    it.onNext("4")
    it.onComplete()
    }).subscribe(object : Observer<String?> {
    override fun onNext(t: String) {
    println("onNext --> $t")
    }

    override fun onError(e: Throwable) {
    println("on error --> $e")
    }

    override fun onSubscribe(d: Disposable) {
    }

    override fun onComplete() {
    println("perform !")
    }
    })

Scheduler (线程切换)

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)

在RxJava内部已经内置了几个Scheduler,下面将会进行介绍

  • Schedulers.newThread()

    开启一个新线程并使用

  • Schedulers.io()

    切换到I/O线程,进行操作

    I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程

  • Schedulers.computation()

    切换到计算而所使用的线程

    这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU

  • AndroidSchedulers.mainThread()

    切换回当前所在的主线程

  • subscribeOn()

    说人话就是数据处理所在的线程

  • observeOn()

    结果返回所在的线程