关于RxAndroid

关于RxAndroid

背景交代

RxAndroid基于RxJava,又多点特性,比如切换主线程;

响应式编程很火也很好用,但需要一点学习成本

目前Rx系列的教程泛滥,都能够学习Rx的基础和理论知识:

  • 不过在看这些教程的时候,总是觉得很多例子太脱离实际,或许是大婶们不屑于用在小地方?
  • 对于我来说,需要点直观的实例,才好明白Rx的强大之处。
  • 你说他强大,巴拉巴拉一通理论知识,不拿点实例当干货怎么有理有据?
  • 在这里就把自己使用过的一些例子做个记录。

实例记录

1.配合Retrofit进行网络请求、加载缓存文件、定时操作、延迟操作...

这几招网上都有,都是常见的用法,不过Rx的优势并不局限于这些用处。

Rx真正的优势在于其灵活性,每个人在使用的过程中都可以总结出自己的一套使用方法。


2.RxBus

比起EventBus,优点是减少一个jar包,减轻apk体积


3.加载缓存图片

  • 之一
Observable.from(mFileNames)
                .subscribeOn(Schedulers.io())
                //随意切换线程
                .observeOn(AndroidSchedulers.mainThread())
                //预先做一些处理
                .doOnSubscribe(() -> {
                    for (int i = 0; (i < count) && (first + i < mArrayList.size()); i++) {
                        if (mArrayList.get(first + i).hasThumbnail) {
                            mFileNames.add(mArrayList.get(first + i).path);
                        }
                    }
                })
                //操作完成后刷新
                .doOnCompleted(this::notifyDataSetChanged)
                .map((Func1<String, Object>) s -> FMThumbnailHelper.findThumbnailInCache(mContext, s))
                .subscribe(o -> {
                });

我觉得Rx一定要搭配lambda,不然复杂了看起来也会显得混乱,配合lambda后,简洁之风扑面而来。

这里主要是doOnSubscribe和doOnCompleted进行预、后处理,再配合lambda,使得代码逻辑清晰,简洁迷人。

  • 之二

代码:

        //原始代码
        Drawable d = null;
        if (null != FMThumbnailHelper.getThumbnailCathe())
            d = (Drawable) FMThumbnailHelper.getThumbnailCathe().get(name);
        if (null != d)
            iv.setImageDrawable(d);
            
        // Rx && Lambda
        Observable.just(name)
                .filter(s -> null != FMThumbnailHelper.getThumbnailCathe())
                .map(s -> (Drawable) FMThumbnailHelper.getThumbnailCathe().get(s))
                .filter(drawable -> drawable != null)
                .subscribe(iv::setImageDrawable);
  • 我觉得这个例子很好,原始代码也不复杂,但是给人一种不舒服的感觉,似乎不够优雅?
  • Rx + Lambda处理之后,看起来代码量还增大了,但是逻辑变得一清二楚:filter空的—>map为drawable—>filter空的—> setImageDrawable
  • 这不是很优雅吗?看着自己都觉得舒心。

4.根据文件类型加载图标

原始代码:

if (file != null && file.isDirectory()) {
                iv.setImageResource(R.drawable.file_icon_folder);
            } else {
                Drawable d = null;
                if (null != FMThumbnailHelper.getThumbnailCathe()) {
                    d = (Drawable) FMThumbnailHelper.getThumbnailCathe()
                            .get(path);
                }
                if (d != null) {
                    iv.setImageDrawable(d);
                } else {
                    Drawable icon = getDefaultIconByCategory(mCategoryIndex);
                    if (null == icon) {
                        iv.setImageResource(MediaFile.getIconForPath(path));
                    } else {
                        iv.setImageDrawable(icon);
                    }
                }
            }

Rx + Lambda:

Observable<Drawable> source = Observable
                    .concat(ObservableUtil.getDirectory(context, file),
                            ObservableUtil.getThumbNail(path),
                            ObservableUtil.getDefault(context, mCategoryIndex),
                            ObservableUtil.getMedia(context, path))
                    .first();
            source.subscribe(iv::setImageDrawable);
  • 原始代码的逻辑看的有点晕,但实际上是要根据类型选择图标,只不过可供选择的渠道有点多;

  • 简而言之:按顺序在有序列表中查找唯一答案;

  • 在Rx中使用了concat和first()来确保实现此要求,concat确保按顺序查找,first()要求一旦匹配则停止查找行为;

  • Rx优化过后的代码,不是简洁清晰太多了吗?


5.删除文件及其在媒体库中的文件

原始代码:

 if (srcFile.isFile()) {
			mCurrentSrcFile = srcFile.getAbsolutePath();
			if (srcFile.exists()) {
				if (!FileUtil.deleteFile(srcFile)) {
					handleResult(ERROR);
				} else {
					updateProgress();
				}
			}
		} else if (srcFile.isDirectory()) {
			mHasDirectory = true;
			updateProgress();
			File[] files = srcFile.listFiles();
			if (files != null) {
				for (File f : files) {
					filePaths.add(f.getAbsolutePath());
					deleteFiles(f);
				}
			}
			if (FileUtil.deleteFile(srcFile)) {
				filePaths.add(srcFile.getAbsolutePath());
			} else {
				handleResult(ERROR);
				return false;
			}
		}

if (!mHasDirectory) {
			for (String deleteFileName : filePaths) {
				FileUtil.deleteFileInDB(mContext, deleteFileName);
			}
		} else if (!TextUtils.isEmpty(mCurPath)) {
			FileUtil.startMediaScan(mContext, mCurPath);
			for (String deleteFileName : filePaths) {
					FileUtil.deleteFileInDB(mContext, deleteFileName);
			}
		}


Rx + lambda:

// delete
Observable.just(rootPath)
                //flatMap出所子文件(不包括文件夹)
                .flatMap(new Func1<File, Observable<File>>() {
                    @Override
                    public Observable<File> call(File file) {
                        return RxUtil.listFiles(file);
                    }
                })
                //显示进度
                .doOnSubscribe(() -> updateProgress()
                .subscribe(new Subscriber<File>() {
                    @Override
                    public void onCompleted() {
                        //删除完子文件后删除剩余的所有空文件夹
                        deleteEmptyFolder(rootPath);
                        //刷新进度
                        updateProgress();
                    }

                    @Override
                    public void onError(Throwable e) {
                        //处理异常
                        handleResult(ERROR_DEL_FAIL);
                    }

                    @Override
                    public void onNext(File f) {
                        mCurrentSrcFile = f.getAbsolutePath();
                        mTotalOperSize += f.length();
                        // 删除发射的那一个文件
                        FileUtil.deleteFile(f);
                        //删除媒体库中对应的文件
                        FileUtil.deleteFileInDB(mContext, mCurrentSrcFile);
                        //刷新进度
                        updateProgress();
                    }
                });


// RxUtil
public class RxUtil {

    public static Observable<File> listFiles(final File f) {
        if (f.isDirectory()) {
            return Observable.from(f.listFiles()).flatMap(new Func1<File, Observable<File>>() {
                @Override
                public Observable<File> call(File file) {
                    return listFiles(file);
                }
            });
        } else {
            return Observable.just(f).filter(file -> f.exists());
        }
    }

}
  • 这次的原始代码稍显复杂,看起来有点绕,且烦人,逻辑很杂乱;
  • 但我相信你看了下面Rx的代码之后,顿时会感觉神清气爽。
    • 这次运用flatMap来一次发射文件夹内的所有文件,抛弃了大量绕人的if else;
    • 充分利用Subscriber的onNext、onError和onCompleted处理对应的逻辑,有条有理

未完待续

posted @ 2016-10-01 19:32  shadowxs  阅读(54)  评论(0)    收藏  举报