Android架构实战(二)—— RxJava

本文深入探讨了RxJava在Android开发中的应用,对比了传统线程模式与RxJava的区别,展示了如何利用RxJava简化多线程操作、优化代码结构,并通过实例演示了如何使用RxJava进行数据获取、异常处理及任务链式操作,强调其在提高代码可读性和可维护性上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇Android架构实战(一)—— 核心思想中,我们已经对一种更清晰的安卓架构进行了一个概括性的了解,相信大家对其基本框架已经有所了解了。RxJava可以说是一种更清晰的安卓架构中一个非常核心的技术,它是连通各个层级直接的利器。RxJava在android开发中也越来越流行,它对降低耦合度,降低代码复杂性,增加可控性方面,有着非常大的作用。今天,我就来介绍一下我对RxJava的实用心得,以及学到的一些技巧。

一、基本介绍

多线程的操作对于一个Android程序来说是必不可少的,在发起网络请求,大量数据库操作,文件读取等耗时操作时,在其他线程执行任务能够降低用户对等待的时间的感知,使程序变得更加友好。众所周知,非UI线程是不允许对UI进行任何操作的,然而一个任务执行的结果往往是需要通过UI层面来进行展示的。为了解决这个问题,Android提供了消息队列的机制,即所谓的handler。

然而Handler的使用,无形中会带来许多问题。最明显的就是Message将一端逻辑代码生硬的分离开了,同时,如果Message类型过多的话,Handler内部的条件判断也随之增加,可读性大大降低。另外,在定义handler的时候,我们都会发现编译器给了这样一个警告:Handler classes should be static or leaks might occur。这是因为Handler如果定义成Activity的一个内部类,任意一个延时性的Message都会持有Handler的引用,而因为这个引用的存在,Handler无法被消除,从而导致Handler的外部类Activity也无法被回收。也就是说,如果消息队列中还存在未被处理的Message,而Activity却企图finish掉自己的话,程序就会crash了。(解决方式,网上都有讲解,一般都是通过static的Handler和弱应用来规避的)

可以说,Handler只是提供了一种多线程交互的方式,然而它却要求开发人员投入一定的精力去进行维护,这样一种交互效果自然不是我们想得到的结果。于是这个时候响应式的架构就被引入了进来。RxJava是采用观察者模式来进行工作的:对于每一个任务来说,它都是一个可被观察的对象,我们需要做的就是为每一个对象来定义一个观察者,这样当对象发出任何事件的时候,观察者都能发现并进行相应的处理。这个模式优雅的地方在于:观察对象和观察者所处的线程是不受限制的。也就是说,你可以将任何一个耗时的操作当成观察对象,扔到另一个线程去执行,然后在UI线程定义一个观察者,对完成或者异常事件进行处理就好了。(其实观察者模式在Android中很常见,如:监听发件箱的变化)

二、基本介绍

下面,以一个最基本的向服务器获取数据为例进行说明。对于这样一个最基本的操作,一个最基本的封装方法可以是这样的:
public static void startDownload(Actvity actvity, final CallBack callBack) {
        new Thread(new Runnable {
            // 开始下载
            Data data;
            try{
                data = getDataFromServer();
            }catch(Exceptioni e){
                callBack.onFail(e);
            }
            // 下载完成
            activity.runOnUiThread(new Runnable() {
                callBack.onSuccess(data):
            });
        }).start();
    }
在Activity中发起线程,然后定义一个CallBack函数传递给方法,然后方法内部就开发发起网络请求了。如果想对这个任务做一些干预操作,就只能再提供一些其他的封装方法,或者提供更多的回调来实现了。在这个过程中,任务始终是以线程的方式存在的,只能够通过在工具类内部对其进行操作或者干预,维护成本和逻辑性都比较复杂。(当然,有许多网络请求库都已经对这些过程进行了封装,性能和易用性都很高,比如Volley)

那么,再来看一看使用RxJava的实现方式:
public static void getData() {
        getDownloadObservable()
                .subscribeOn(Schedulers.from(jobExecutor)) // 从线程池中获取线程
                .observeOn(AndroidSchedulers.mainThread()) // 观察者的线程为主线程
                .subscribe(new Subscriber<Data>()); // 自定义观察者
    }

    public static Observable<Data> getDownloadObservable() {
        return Observable.create(new Observable.OnSubscribe<Data>() {
            @Override
            public void call(Subscriber<? super Data> subscriber) {
                try {
                    subscriber.onNext(getDateFromServer()); // 数据接收
                    subscriber.onCompleted(); // 任务完成
                } catch (Exception e) {
                    subscriber.onError(e); // 任务异常
                }
            }
        });
    }
当中的static函数可以看成是一个封装好的工具类。可以很明显的看到,需要执行的任务以Observable的形式被返回给主线程了。这样以来,对任务操纵的主动权就交还到调用者本身了。最基本的,在得到这个Observable后,就可以通过observeOn和subscribeOn这两个方法对任务和订阅者所在的线程进行任意的调配了(在示例中,我们自己提供了一个线程池,使得多个任务可以并发进行)。再比如,如果开发人员想要对任务的结果进行再次加工处理,则可以使用map/flatmap/filter等方法对Observable进行链式的操作。值得一提的是,链式的加工方法相当于流水线的效果,对于解耦方面的意义重大。而如果想要通过CallBack实现这种功能的化,就只能通过回调嵌套回调来进行了。

三、个人总结

通过以上两个简单示例的对比,可以很直观的感觉两者的区别:在传统线程模式,任务只是被放到线程中执行,调用者无法对其进行直接的操作。另外,线程的管理功能也交由开发人员来管理。尽管有许多开源库对线程管理进行了相对良好的封装,但这也使得任务本身变得更加不可见了。如果想要对执行中的任务进行操作,则需要通过开源库提供的有限接口来实现,对库的依赖性就高,可拓展性相对受限。而在RxJava中,调用者能够获得任务的操控权,而且不论是线程调度还是加工处理,RxJava都提供了方便的操作接口。另外,RxJava对于面向对象的契合更加优雅,每一个任务都被具象为了一个Observable对象,其实例可以被直接的传递或者返回,非常有利于代码的解耦和模块功能划分。

总的来说,RxJava在解决多线程操作这样一个令开发人员头疼的问题上提供了很大的帮助。使用RxJava也可以使代码的结构更加合理美观,在异常处理方面,在任何一个过程中产生的异常,都会被传递到订阅者的onError方法接收到,从而进行统一的处理。不过似乎RxJava没有提供一个可以中断任务的方法,只能是通过unsubscribe去取消订阅,也就是不去管它,让任务自行结束,算是一种比较折衷的方法吧。
以上就是我在使用RxJava过程中,自己的一些理解,可能会存在一些错误的地方,欢迎大家即使指出。

附录

下面是一种更清晰的安卓架构给出的一个线程池工厂类JobExecutor,可以直接拿来使用
/**
 * Decorated {@link java.util.concurrent.ThreadPoolExecutor}
 */
public class JobExecutor implements Executor {

    private static final int INITIAL_POOL_SIZE = 3;
    private static final int MAX_POOL_SIZE = 5;

    // Sets the amount of time an idle thread waits before terminating
    private static final int KEEP_ALIVE_TIME = 10;

    // Sets the Time Unit to seconds
    private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

    private final BlockingQueue<Runnable> workQueue;

    private final ThreadPoolExecutor threadPoolExecutor;

    private final ThreadFactory threadFactory;

    public JobExecutor() {
        this.workQueue = new LinkedBlockingQueue<>();
        this.threadFactory = new JobThreadFactory();
        this.threadPoolExecutor = new ThreadPoolExecutor(INITIAL_POOL_SIZE, MAX_POOL_SIZE,
                KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, this.workQueue, this.threadFactory);
    }

    @Override public void execute(Runnable runnable) {
        if (runnable == null) {
            throw new IllegalArgumentException("Runnable to execute cannot be null");
        }
        this.threadPoolExecutor.execute(runnable);
    }

    private static class JobThreadFactory implements ThreadFactory {
        private static final String THREAD_NAME = "android_";
        private int counter = 0;

        @Override public Thread newThread(Runnable runnable) {
            return new Thread(runnable, THREAD_NAME + counter);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值