在上一篇【Android 进阶】仿抖音系列之列表播放视频(二)中,我们实现列表播放视频,这一篇我们来对其做些优化。

当我们滑动列表播放视频时,如果你设置了状态栏显示网速的话,可以看到网速占用比较大,我们需要实现边播边缓存,下次播放时,就可以从缓存中取,减少网络使用。

Github上已经有现成的缓存库,我们只要集成进来就好,这是链接 AndroidVideoCache

1、创建MyApp 继承 Application,并在AndroidManifest.xml 中注册

2、在MyApplication 中添加代码,可以设置缓存路径、缓存大小等,这里用默认路径,配置缓存大小为1G。



    private HttpProxyCacheServer proxy;

    public static HttpProxyCacheServer getProxy(Context context) {
        MyApp app = (MyApp) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }

    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer.Builder(this)
                .maxCacheSize(1024 * 1024 * 1024)       // 1 Gb for cache
                .build();
    }

3、在MyVideoPlayer中,重写setUp 方法,这里需要注意的是,要做个判断,如果是本地视频的话,不使用代理

  @Override
    public void setUp(String url, int screen, Object... objects) {
       if (url.startsWith("http")) {
            HttpProxyCacheServer proxy = MyApp.getProxy(context);
            String proxyUrl = proxy.getProxyUrl(url);
            super.setUp(proxyUrl, screen, objects);
        } else {
            super.setUp(url, screen, objects);
        }
    }

就在我们以为万事大吉的时候,却发现并没有什么卵用,而且有时播放第二遍的时候还会卡死,这是什么鬼???

于是我们查看了app的缓存目录,发现同一个视频,会缓存多次,所以我们猜想,是不是缓存这里出了问题?

通过查看AndroidVideoCache的源码,我们发现AndroidVideoCache是通过代理的策略实现一个中间层将我们的网络请求转移到本地实现的代理服务器上,这样我们真正请求的数据就会被代理拿到,这样代理一边向本地写入数据,一边根据我们需要的数据看是读网络数据还是读本地缓存数据再提供给我们,真正做到了数据的复用。

在这里插入图片描述

更详细的可以查看这篇博客这是链接

我们打断点,查看下AndroidVideoCache返回的url

在这里插入图片描述

可以看到同一个视频,2次返回的url 是不一样的,再翻下AndroidVideoCache的源码,我们看到

  public Builder(Context context) {
            this.sourceInfoStorage = SourceInfoStorageFactory.newSourceInfoStorage(context);
            this.cacheRoot = StorageUtils.getIndividualCacheDirectory(context);
            this.diskUsage = new TotalSizeLruDiskUsage(DEFAULT_MAX_SIZE);
            this.fileNameGenerator = new Md5FileNameGenerator();
            this.headerInjector = new EmptyHeadersInjector();
        }

我们再查看Md5FileNameGenerator的源码

public class Md5FileNameGenerator implements FileNameGenerator {

    private static final int MAX_EXTENSION_LENGTH = 4;

    @Override
    public String generate(String url) {
        String extension = getExtension(url);
        String name = ProxyCacheUtils.computeMD5(url);
        return TextUtils.isEmpty(extension) ? name : name + "." + extension;
    }

    private String getExtension(String url) {
        int dotIndex = url.lastIndexOf('.');
        int slashIndex = url.lastIndexOf('/');
        return dotIndex != -1 && dotIndex > slashIndex && dotIndex + 2 + MAX_EXTENSION_LENGTH > url.length() ?
                url.substring(dotIndex + 1, url.length()) : "";
    }
}

这里我们可以看到,缓存的文件是上面url 进行md5之后的字符串,再加上原来的文件后缀名,这也是为什么缓存目录下同一个视频,会缓存多次的问题。

知道问题出在哪,就好解决了,我们可以对AndroidVideoCache 返回的路径进行截取,只取我们原先的路径,当做缓存的文件名就可以了

public class MyFileNameGenerator implements FileNameGenerator {
    private static final int MAX_EXTENSION_LENGTH = 4;

    @Override
    public String generate(String url) {
        String extension = getExtension(url);
        int dotIndex = url.lastIndexOf('.');

        if (url.length() > 18 && dotIndex > 18) {
            return url.substring(dotIndex - 18);
        }
        String name = ProxyCacheUtils.computeMD5(url);
        return TextUtils.isEmpty(extension) ? name : name + "." + extension;
    }

    private String getExtension(String url) {
        int dotIndex = url.lastIndexOf('.');
        int slashIndex = url.lastIndexOf('/');
        return dotIndex != -1 && dotIndex > slashIndex && dotIndex + 2 + MAX_EXTENSION_LENGTH > url.length() ?
                url.substring(dotIndex + 1, url.length()) : "";
    }
}

修改MyApp 中的代码如下

   private HttpProxyCacheServer proxy;

    public static HttpProxyCacheServer getProxy(Context context) {
        MyApp app = (MyApp) context.getApplicationContext();
        return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
    }

    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer.Builder(this)
                .maxCacheSize(1024 * 1024 * 1024)       // 1 Gb for cache
                .fileNameGenerator(new MyFileNameGenerator())
                .build();
    }

到这里,本篇文章也结束了

最后,献上完整代码。Github

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐