赞
踩
ExoPlayer的缓存-- 四 Cache 的使用
同一文件 内容服务器 生成的链接有时效性,如果用URL做缓存ID,会出现同一首无法命中缓存的情况。Exoplayer 的缓存默认使用 URL
public static final CacheKeyFactory DEFAULT_CACHE_KEY_FACTORY =
(dataSpec) -> dataSpec.key != null ? dataSpec.key : generateKey(dataSpec.uri);
每首歌曲有一个SongID, 如果使用SongID, 每首歌曲的有伴奏 原唱 视频三种文件,也有冲突的可能。
因此使用URL 的path 作为SongID 是比较合适的。
Exoplayer 在创建CacheDataSourceFactory 的时候 传入CacheKeyFactory
return new CacheDataSourceFactory(
cache,
new DefaultHttpDataSourceFactory("user-agent"),
new FileDataSource.Factory(),
new CacheDataSinkFactory(cache, CacheDataSink.DEFAULT_FRAGMENT_SIZE),
CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, null,
new CacheKeyFactory() {
@Override
public String buildCacheKey(DataSpec dataSpec) {
return dataSpec.key != null ? dataSpec.key : dataSpec.uri.getLastPathSegment();
}
});
}
缓存的时候 生成DownloadRequest 直接使用URL 的path 最为ID参数传入
DownloadRequest request = CacheDownloadManager.buildDownloadRequest(uri.getLastPathSegment(), uri);
K歌播放的文件时加密类型的,在缓存的时候 直接使用DefaultHttpDataSourceFactory 下载流。
因此缓存的文件是加密的。
private static synchronized HttpDataSource.Factory getHttpDataSourceFactory( ) {
if (sHttpDataSourceFactory == null) {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
sHttpDataSourceFactory = new DefaultHttpDataSourceFactory("user-agent");
}
return sHttpDataSourceFactory;
}
在播放的时候需要先解密数据,使用 CryptoHttpDataSourceFactory,但是CryptoHttpDataSourceFactory 使用缓存后保存在缓存中的是解密后的数据,播放中导致数据无法识别。
那能不能在播放的时候 送到播放器的数据解密但是下载保存的时候是原始数据呢。Exoplayer 的DataSource 设计使用了装饰模式,参考这个思路,在CacheDataSource 外面再装饰一层解密的CryptoWrapDataSource。 这样Cache 缓存的时候是加密的数据,送到Exoplayer 的CryptoWrapDataSource 是解密以后的数据。
return new ProgressiveMediaSource.Factory(
new CryptoWrapDataSource.Factory(buildCacheDataSourceFactory(cache)),
.createMediaSource(uri);
默认的分片大小为5M,CacheDataSink.DEFAULT_FRAGMENT_SIZE
在生成DownloadManager 的时候,传入自定义参数,CacheDataSinkFactory 定义 分片大小。
DownloaderConstructorHelper downloaderConstructorHelper = new DownloaderConstructorHelper( getDownloadCache(context), getHttpDataSourceFactory(), null, new CacheDataSinkFactory( getDownloadCache(context), (sParameters != null && sParameters.mSegmentSize > 0) ? sParameters.mSegmentSize:CacheDataSink.DEFAULT_FRAGMENT_SIZE ), null ); DefaultDownloaderFactory downloaderFactory = new DefaultDownloaderFactory(downloaderConstructorHelper); sDownloadManager = new DownloadManager( context, new DefaultDownloadIndex(getDatabaseProvider(context)), downloaderFactory );
在Exoplayer 的官方文档中 对下载速度的 需要通过DownloadManager 定期查询。DownloadService 支持Notification 通知,默认实现了一个 ForegroundNotificationUpdater 定期通知 Notification。
下载进度更新不会触发对
DownloadManager.Listener
. 要更新显示下载进度的 UI 组件,您应该DownloadManager
以所需的更新速率定期查询。DownloadService
包含一个示例,它会定期更新服务前台通知。
参考这个实现 实现我们的网速监听。
注册自定义的DownloadManagerListener
mDownloadManagerListener = new DownloadManagerListener(mHandlerListener);
CacheDownloadService.getDownloadManager(mContext).addListener(mDownloadManagerListener);
onDownloadChanged 中监听是否有下载开始,如果有下载开始,开始抛出消息计算网速。
private class DownloadManagerListener implements com.google.android.exoplayer2.offline.DownloadManager.Listener { private Handler mHandler; public DownloadManagerListener(Handler handler){ mHandler = handler; } @Override public void onInitialized(com.google.android.exoplayer2.offline.DownloadManager downloadManager) { mDownloadManager = downloadManager; initHandler(); } @Override public void onDownloadChanged(com.google.android.exoplayer2.offline.DownloadManager downloadManager, Download download) { if(mHandler != null){ if (download.state == Download.STATE_DOWNLOADING) { Message message = Message.obtain(); message.what = MSG_START; message.obj = download; if (download.contentLength > 0) { mHandler.sendMessage(message); } } else if (download.state == Download.STATE_COMPLETED) { Message message = Message.obtain(); message.what = MSG_FINISH; message.obj = download; mHandler.sendMessage(message); } } }
initHandler() 中 初始化一个线程 用于处理消息和和计算网速
private void initHandler(){ mHandlerThreadListener = new HandlerThread("DownloadManagerListener"); mHandlerThreadListener.start(); mHandlerListener = new Handler(mHandlerThreadListener.getLooper(), new Handler.Callback(){ @Override public boolean handleMessage(@NonNull Message msg) { switch (msg.what) { case MSG_START: { Download download = (Download) msg.obj; DownloadInfo downloadInfo = mHashDownloadInfo.get(download.request.id); if (downloadInfo == null) { downloadInfo = new DownloadInfo(); downloadInfo.id = download.request.id; downloadInfo.updateTimeMs = download.startTimeMs; downloadInfo.bytesDownloaded = download.getBytesDownloaded(); mHashDownloadInfo.put(downloadInfo.id, downloadInfo); } if (!mRunning) { mRunning = true; mHandlerListener.sendEmptyMessage(MSG_UPDATE); } } break; case MSG_UPDATE: { List<Download> downloadList = mDownloadManager.getCurrentDownloads(); if (downloadList != null && downloadList.size() > 0) { long nowMs = Clock.DEFAULT.elapsedRealtime(); for (Download dl : downloadList) { DownloadInfo downloadInfo = mHashDownloadInfo.get(dl.request.id); long speed = (dl.getBytesDownloaded() - downloadInfo.bytesDownloaded) / ((nowMs - downloadInfo.updateTimeMs) / 1000); downloadInfo.updateTimeMs = nowMs; downloadInfo.bytesDownloaded = dl.getBytesDownloaded(); for (NetworkSpeedListener li : sListener) { li.onProgress(dl, speed, dl.getPercentDownloaded()); } } mHandlerListener.sendEmptyMessageDelayed(MSG_UPDATE, 1000); } else { mRunning = false; } } break; case MSG_FINISH: Download download = (Download) msg.obj; DownloadInfo downloadInfo = mHashDownloadInfo.get(download.request.id); long nowMs = Clock.DEFAULT.elapsedRealtime(); long speed = (download.getBytesDownloaded() - downloadInfo.bytesDownloaded ) / (nowMs - downloadInfo.updateTimeMs); mHashDownloadInfo.remove(((Download) msg.obj).request.id); for (NetworkSpeedListener li : sListener) { li.onProgress((Download) msg.obj, speed, download.getPercentDownloaded()); } break; } return false; } }); }
下载参数的设置使用了 Builder 设计模式
class ParametersBase { protected long mMaxCacheSize = 512 * 1025 * 1025; protected long mSegmentSize = mMaxCacheSize; protected String mCachePath; protected int mMaxParallelDownloads; ParametersBase(ParametersBase base){ this.mMaxCacheSize = base.mMaxCacheSize; this.mSegmentSize = base.mSegmentSize; this.mCachePath = base.mCachePath; this.mMaxParallelDownloads = base.mMaxParallelDownloads; } ParametersBase() { } ...... }
public static class Builder extends ParametersBase{
public Builder(){
super();
}
public Builder(ParametersBase base) {
super(base);
}
......
public CacheDownloadParameters build(){
CacheDownloadParameters parameters = new CacheDownloadParameters(this);
return parameters;
}
public class CacheDownloadParameters extends ParametersBase {
private CacheDownloadParameters(ParametersBase base) {
super(base);
}
public Builder buildUpon(){
return new Builder(this);
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。