Android視頻/音頻緩存框架AndroidVideoCache(Okhttp)詳解
關于安卓邊下邊播功能,供大家參考,具體內容如下
對于視頻/音頻軟件,音樂軟件,視頻軟件,都有緩存這個功能,那如何實現邊下邊播功能:
- 如何實現這個邊下邊播功能?
- 文件是否支持同時讀寫?(Mediaplayer 播放文件,從網絡上下載文件)
- 播放與下載進度如何協(xié)調?
- 已緩存的文件需及時清理
經過一番折騰,我 find 了 : [ AndroidVideoCache ],這個庫是 danikula 大神寫,看完源碼后收益匪淺。實現流媒體邊下邊播原理利用socket 開啟一個本機的代理服務器
結合自身需求,修改了該庫,使用okhttp進行網絡請求:
AndroidVideoCache (改成 okhttp 緩存)
package com.danikula.videocache; import android.text.TextUtils; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.util.Map; import java.util.concurrent.TimeUnit; import com.danikula.videocache.file.MyLog; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE; import static com.danikula.videocache.ProxyCacheUtils.LOG_TAG; import static java.net.HttpURLConnection.HTTP_OK; import static java.net.HttpURLConnection.HTTP_PARTIAL; /** * {@link Source} that uses http resource as source for {@link ProxyCache}. * * @author Alexey Danilov (danikula@gmail.com). * * 從URL 獲取數據 */ public class HttpUrlSource implements Source { private static final int MAX_REDIRECTS = 5; public final String url; private static OkHttpClient okHttpClient = new OkHttpClient(); private Call requestCall = null; private InputStream inputStream; private volatile int length = Integer.MIN_VALUE; private volatile String mime; private Map<String, String> headers; public HttpUrlSource(String url) { this(url, ProxyCacheUtils.getSupposablyMime(url)); } public HttpUrlSource(String url, Map<String, String> headers) { this(url, ProxyCacheUtils.getSupposablyMime(url)); this.headers = headers; } public HttpUrlSource(String url, String mime) { this.url = Preconditions.checkNotNull(url); this.mime = mime; } public HttpUrlSource(HttpUrlSource source) { this.url = source.url; this.mime = source.mime; this.length = source.length; } @Override public synchronized int length() throws ProxyCacheException { if (length == Integer.MIN_VALUE) { fetchContentInfo(); } return length; } @Override public void open(int offset) throws ProxyCacheException { try { Response response = openConnection(offset, -1); mime = response.header("Content-Type"); inputStream = new BufferedInputStream(response.body().byteStream(), DEFAULT_BUFFER_SIZE); length = readSourceAvailableBytes(response, offset, response.code()); } catch (IOException e) { throw new ProxyCacheException("Error opening okHttpClient for " + url + " with offset " + offset, e); } } private int readSourceAvailableBytes(Response response, int offset, int responseCode) throws IOException { int contentLength = Integer.valueOf(response.header("Content-Length", "-1")); return responseCode == HTTP_OK ? contentLength : responseCode == HTTP_PARTIAL ? contentLength + offset : length; } @Override public void close() throws ProxyCacheException { if (okHttpClient != null && inputStream != null && requestCall != null) { try { inputStream.close(); requestCall.cancel(); } catch (IOException e) { e.printStackTrace(); } } } @Override public int read(byte[] buffer) throws ProxyCacheException { if (inputStream == null) { throw new ProxyCacheException("Error reading data from " + url + ": okHttpClient is absent!"); } try { return inputStream.read(buffer, 0, buffer.length); } catch (InterruptedIOException e) { throw new InterruptedProxyCacheException("Reading source " + url + " is interrupted", e); } catch (IOException e) { throw new ProxyCacheException("Error reading data from " + url, e); } } private void fetchContentInfo() throws ProxyCacheException { MyLog.d(LOG_TAG, "Read content info from " + url); Response response = null; InputStream inputStream = null; try { response = openConnection(0, 20000); length = Integer.valueOf(response.header("Content-Length", "-1")); mime = response.header("Content-Type"); inputStream = response.body().byteStream(); MyLog.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + length); } catch (IOException e) { MyLog.e(LOG_TAG, "Error fetching info from " + url, e); } finally { ProxyCacheUtils.close(inputStream); if (response != null) { requestCall.cancel(); } } } private Response openConnection(int offset, int timeout) throws IOException, ProxyCacheException { boolean redirected; int redirectCount = 0; String url = this.url; Request request = null; //do { MyLog.d(LOG_TAG, "Open okHttpClient " + (offset > 0 ? " with offset " + offset : "") + " to " + url); // okHttpClient = (HttpURLConnection) new URL(url).openConnection(); Request.Builder builder = new Request.Builder(); builder.url(url); //flac if(headers != null) { //設置請求頭 for (Map.Entry<String, String> entry : headers.entrySet()) { MyLog.i(LOG_TAG, "請求頭信息 key:" + entry.getKey() +" Value" + entry.getValue()); // okHttpClient.setRequestProperty(entry.getKey(), entry.getValue()); builder.addHeader(entry.getKey(), entry.getValue()); } } if (offset > 0) { builder.addHeader("Range", "bytes=" + offset + "-"); } request = builder.build(); requestCall = okHttpClient.newCall(request); /*if (redirected) { url = okHttpClient.getHeaderField("Location"); redirectCount++; okHttpClient.disconnect(); } if (redirectCount > MAX_REDIRECTS) { throw new ProxyCacheException("Too many redirects: " + redirectCount); }*/ //} while (redirected); return requestCall.execute(); } public synchronized String getMime() throws ProxyCacheException { if (TextUtils.isEmpty(mime)) { fetchContentInfo(); } return mime; } public String getUrl() { return url; } @Override public String toString() { return "HttpUrlSource{url='" + url + "}"; } }
下載地址:Android視頻音頻緩存框架AndroidVideoCache
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- OkHttp攔截器在Android網絡中的使用和工作原理
- Android入門之使用OKHttp多線程下載文件
- Android 使用 okhttp3和retrofit2 進行單文件和多文件上傳
- Android基于OkHttp實現文件上傳功能
- Android使用OKhttp3實現登錄注冊功能+springboot搭建后端的詳細過程
- Android的簡單前后端交互(okHttp+springboot+mysql)
- Android Okhttp斷點續(xù)傳面試深入解析
- Android使用OkHttp發(fā)送post請求
- Android使用OkHttp進行網絡同步異步操作
- Android OkHttp實現全局過期token自動刷新示例
- OkHttp原理分析小結
相關文章
ListView的View回收引起的checkbox狀態(tài)改變監(jiān)聽等問題解決方案
之前講到了自定義Adapter傳遞給ListView時,因為ListView的View回收,需要注意當ListView列表項中包含有帶有狀態(tài)標識控件的問題,感興趣的朋友可以祥看本文,或許會有意外的收獲哦2013-01-01android和服務器的URLEncodedUtils亂碼編碼問題的解決方案
今天小編就為大家分享一篇關于android和服務器的URLEncodedUtils亂碼編碼問題的解決方案,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03Android TextView顯示Html類解析的網頁和圖片及自定義標簽用法示例
這篇文章主要介紹了Android TextView顯示Html類解析的網頁和圖片及自定義標簽用法,實例分析了Android中TextView控件的使用技巧,需要的朋友可以參考下2016-07-07