美文网首页
RxJava线程切换的问题

RxJava线程切换的问题

作者: ztzt123 | 来源:发表于2018-02-26 16:31 被阅读0次

    专业版在前几个版本一直存在一个问题,就是在首页切换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直接使用缓存,页面展示出来,但其他的请求数据还没有获取到,这样展示出来也会有问题,对于其他的请求我们只能自己写缓存,这样确实不是一个好的解决方法,更好的解决方法还在寻找。

    相关文章

      网友评论

          本文标题:RxJava线程切换的问题

          本文链接:https://www.haomeiwen.com/subject/xmvyxftx.html