RxJava线程切换的问题

专业版在前几个版本一直存在一个问题,就是在首页切换Tab的时候每次都会转圈圈,我们已经使用了Retrofit缓存,正常来说读取缓存数据应该很快。转圈圈给我们的感觉是读取缓存很慢,我们开始怀疑Retrofit读取缓存的问题。我们需找到了原因其实是RxJava切换线程的问题,请求缓存从io线程切换回主线程需要等待一定的时间。看一段我们的测试代码。

    addSubscription(movieBoardUsecase.requestMainBoard(refresh)
            .subscribe(boardTop -> {
                time2 = (Formatter.getCurrentMillis() - time);
                Log.e("timeretrofit", "" + time2);
            }, throwable -> {

            }));

    time3 = Formatter.getCurrentMillis();
    addSubscription(movieBoardUsecase.requestMainBoard(refresh)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(boardTop -> {
                Log.e("timeRXthread", "" + (Formatter.getCurrentMillis() - time3 - time2));
                getView().setData(boardTop);
            }, throwable -> {
            }));

第一段我们不切换线程,直接在主线程请求缓存内的数据,打出发出请求再到获取到数据的时间。

第二段我们正常的切换线程请求缓存,然后减去上面在主线程请求缓存的时间,就获取到切换线程所需要的时间。

我们在页面状态由加载状态变成展示状态的时间。

09-07 22:17:49.176 10745-10745/com.sankuai.moviepro E/timeretrofit: 4
09-07 22:17:49.206 10745-10745/com.sankuai.moviepro E/timeRXthread: 26
09-07 22:17:49.207 10745-10745/com.sankuai.moviepro E/status: 35

上面是在模拟器上运行的时间,可能感觉时间很短,模拟器运行速度较快,参考价值不大,但已经能看出切换线程占用了大部分的耗时。我们换用真机,才能说明问题。

09-08 10:24:42.539 26994-26994/com.sankuai.moviepro E/timeretrofit: 7
09-08 10:24:42.639 26994-26994/com.sankuai.moviepro E/timeRXthread: 91
09-08 10:24:42.644 26994-26994/com.sankuai.moviepro E/status: 112

09-08 10:25:25.676 26994-26994/com.sankuai.moviepro E/timeretrofit: 13
09-08 10:25:25.777 26994-26994/com.sankuai.moviepro E/timeRXthread: 88
09-08 10:25:25.779 26994-26994/com.sankuai.moviepro E/status: 116

09-08 10:25:51.392 26994-26994/com.sankuai.moviepro E/timeretrofit: 28
09-08 10:25:51.609 26994-26994/com.sankuai.moviepro E/timeRXthread: 189
09-08 10:25:51.611 26994-26994/com.sankuai.moviepro E/status: 247

三组数据整体时间不是很稳定,但我们已经可以清楚地看出耗时的并不是Retrofit读取缓存的过程,大部分时间都消耗在RxJava切换线程上。

既然我们已经找到了问题想想解决办法吧。我们可以直接想到的有两种方法,但行不行得通要去试试。

1.在请求之前判断是否存在Http缓存。
2.自己增加一层缓存,优先使用内存缓存,避开retrofit发请求。

第一种方法,我们要在发请求之前知道是否存在Http缓存,http缓存的位置是我们自己指定的,专业版的缓存目录是在应用目录下的cache/responses,下面有好多文件,文件名都是经过加密的,都是.0和.1的文件还有一个journal文件,关于这些文件查了一些资料,okhttp缓存浅析

.0的文件里面是header

.1文件里面是返回的具体内容,即json数据

journal文件里面保存的是每一条reponse记录状态。包括读取,删除,写入等动作。

文件名的加密方式是MD5,可以参考okHttp的Cache。

public static FilterInputStream getFromCache(String url) throws Exception {
    File cacheDirectory = CacheUtils.getCacheDir(MovieProApplication.getContext(), "responses");
    DiskLruCache cache = DiskLruCache.create(FileSystem.SYSTEM, cacheDirectory,
            201105, 2, 10 * 1024 * 1024);
    cache.flush();
    String key = Util.md5Hex(url);
    final DiskLruCache.Snapshot snapshot;
    try {
        snapshot = cache.get(key);
        if (snapshot == null) {
            return null;
        }
    } catch (IOException e) {
        return null;
    }
    okio.Source source = snapshot.getSource(1) ;
    BufferedSource metadata = Okio.buffer(source);
    FilterInputStream bodyIn = new FilterInputStream(metadata.inputStream()) {
        @Override
        public void close() throws IOException {
            snapshot.close();
            super.close();
        }
    };
    return bodyIn ;
}

但是弄了半天我们有一个关键的问题,就是匹配缓存使用的是URL,但是我们在Presenter或者Fragment中并不能获取到URL,要修改的话,改动将会很大,所以这一种方法失败。

第二种是我们自己写内存缓存,还是存在问题,我们要把页面所有的数据缓存起来,使用一个Map,问题就是用什么作为获取缓存的匹配原则呢,正常也应该是通过URL,但是URL的方式行不通,我们只能拿到的是Observable,也无从匹配啊。后来我们重新思考了一下问题,我们当初是为了解决转圈圈的问问题,转圈圈的问题是从loaddata开始,在setData的是后结束。我们只需要避开这个过程,也就不会出现转圈圈的问题,但这只是一个比较差的解法,我们只缓存setData的数据,如果loaddata的时候数据不为空我们直接调用setData,但这样,如果页面有其他数据的话我们setData直接使用缓存,页面展示出来,但其他的请求数据还没有获取到,这样展示出来也会有问题,对于其他的请求我们只能自己写缓存,这样确实不是一个好的解决方法,更好的解决方法还在寻找。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容