1. 程式人生 > >【Android 進階】仿抖音系列之列表播放視訊(三)

【Android 進階】仿抖音系列之列表播放視訊(三)

在上一篇【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