基于Retrofit+Rxjava實(shí)現(xiàn)帶進(jìn)度顯示的下載文件
本文實(shí)例為大家分享了Retrofit Rxjava實(shí)現(xiàn)下載文件的具體代碼,供大家參考,具體內(nèi)容如下
本文采用 :retrofit + rxjava
1.引入:
//rxJava compile 'io.reactivex:rxjava:latest.release' compile 'io.reactivex:rxandroid:latest.release' //network - squareup compile 'com.squareup.retrofit2:retrofit:latest.release' compile 'com.squareup.retrofit2:adapter-rxjava:latest.release' compile 'com.squareup.okhttp3:okhttp:latest.release' compile 'com.squareup.okhttp3:logging-interceptor:latest.release'
2.增加下載進(jìn)度監(jiān)聽(tīng):
public interface DownloadProgressListener { void update(long bytesRead, long contentLength, boolean done); }
public class DownloadProgressResponseBody extends ResponseBody { private ResponseBody responseBody; private DownloadProgressListener progressListener; private BufferedSource bufferedSource; public DownloadProgressResponseBody(ResponseBody responseBody, DownloadProgressListener progressListener) { this.responseBody = responseBody; this.progressListener = progressListener; } @Override public MediaType contentType() { return responseBody.contentType(); } @Override public long contentLength() { return responseBody.contentLength(); } @Override public BufferedSource source() { if (bufferedSource == null) { bufferedSource = Okio.buffer(source(responseBody.source())); } return bufferedSource; } private Source source(Source source) { return new ForwardingSource(source) { long totalBytesRead = 0L; @Override public long read(Buffer sink, long byteCount) throws IOException { long bytesRead = super.read(sink, byteCount); // read() returns the number of bytes read, or -1 if this source is exhausted. totalBytesRead += bytesRead != -1 ? bytesRead : 0; if (null != progressListener) { progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); } return bytesRead; } }; } }
public class DownloadProgressInterceptor implements Interceptor { private DownloadProgressListener listener; public DownloadProgressInterceptor(DownloadProgressListener listener) { this.listener = listener; } @Override public Response intercept(Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .body(new DownloadProgressResponseBody(originalResponse.body(), listener)) .build(); } }
3.創(chuàng)建下載進(jìn)度的元素類(lèi):
public class Download implements Parcelable { private int progress; private long currentFileSize; private long totalFileSize; public int getProgress() { return progress; } public void setProgress(int progress) { this.progress = progress; } public long getCurrentFileSize() { return currentFileSize; } public void setCurrentFileSize(long currentFileSize) { this.currentFileSize = currentFileSize; } public long getTotalFileSize() { return totalFileSize; } public void setTotalFileSize(long totalFileSize) { this.totalFileSize = totalFileSize; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(this.progress); dest.writeLong(this.currentFileSize); dest.writeLong(this.totalFileSize); } public Download() { } protected Download(Parcel in) { this.progress = in.readInt(); this.currentFileSize = in.readLong(); this.totalFileSize = in.readLong(); } public static final Parcelable.Creator<Download> CREATOR = new Parcelable.Creator<Download>() { @Override public Download createFromParcel(Parcel source) { return new Download(source); } @Override public Download[] newArray(int size) { return new Download[size]; } }; }
4.下載文件網(wǎng)絡(luò)類(lèi):
public interface DownloadService { @Streaming @GET Observable<ResponseBody> download(@Url String url); }
注:這里@Url是傳入完整的的下載URL;不用截取
public class DownloadAPI { private static final String TAG = "DownloadAPI"; private static final int DEFAULT_TIMEOUT = 15; public Retrofit retrofit; public DownloadAPI(String url, DownloadProgressListener listener) { DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(interceptor) .retryOnConnectionFailure(true) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .build(); retrofit = new Retrofit.Builder() .baseUrl(url) .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } public void downloadAPK(@NonNull String url, final File file, Subscriber subscriber) { Log.d(TAG, "downloadAPK: " + url); retrofit.create(DownloadService.class) .download(url) .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .map(new Func1<ResponseBody, InputStream>() { @Override public InputStream call(ResponseBody responseBody) { return responseBody.byteStream(); } }) .observeOn(Schedulers.computation()) .doOnNext(new Action1<InputStream>() { @Override public void call(InputStream inputStream) { try { FileUtils.writeFile(inputStream, file); } catch (IOException e) { e.printStackTrace(); throw new CustomizeException(e.getMessage(), e); } } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); } }
然后就是調(diào)用了:
該網(wǎng)絡(luò)是在service里完成的
public class DownloadService extends IntentService { private static final String TAG = "DownloadService"; private NotificationCompat.Builder notificationBuilder; private NotificationManager notificationManager; private String apkUrl = "http://download.fir.im/v2/app/install/595c5959959d6901ca0004ac?download_token=1a9dfa8f248b6e45ea46bc5ed96a0a9e&source=update"; public DownloadService() { super("DownloadService"); } @Override protected void onHandleIntent(Intent intent) { notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.mipmap.ic_download) .setContentTitle("Download") .setContentText("Downloading File") .setAutoCancel(true); notificationManager.notify(0, notificationBuilder.build()); download(); } private void download() { DownloadProgressListener listener = new DownloadProgressListener() { @Override public void update(long bytesRead, long contentLength, boolean done) { Download download = new Download(); download.setTotalFileSize(contentLength); download.setCurrentFileSize(bytesRead); int progress = (int) ((bytesRead * 100) / contentLength); download.setProgress(progress); sendNotification(download); } }; File outputFile = new File(Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS), "file.apk"); String baseUrl = StringUtils.getHostName(apkUrl); new DownloadAPI(baseUrl, listener).downloadAPK(apkUrl, outputFile, new Subscriber() { @Override public void onCompleted() { downloadCompleted(); } @Override public void onError(Throwable e) { e.printStackTrace(); downloadCompleted(); Log.e(TAG, "onError: " + e.getMessage()); } @Override public void onNext(Object o) { } }); } private void downloadCompleted() { Download download = new Download(); download.setProgress(100); sendIntent(download); notificationManager.cancel(0); notificationBuilder.setProgress(0, 0, false); notificationBuilder.setContentText("File Downloaded"); notificationManager.notify(0, notificationBuilder.build()); } private void sendNotification(Download download) { sendIntent(download); notificationBuilder.setProgress(100, download.getProgress(), false); notificationBuilder.setContentText( StringUtils.getDataSize(download.getCurrentFileSize()) + "/" + StringUtils.getDataSize(download.getTotalFileSize())); notificationManager.notify(0, notificationBuilder.build()); } private void sendIntent(Download download) { Intent intent = new Intent(MainActivity.MESSAGE_PROGRESS); intent.putExtra("download", download); LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent); } @Override public void onTaskRemoved(Intent rootIntent) { notificationManager.cancel(0); } }
MainActivity代碼:
public class MainActivity extends AppCompatActivity { public static final String MESSAGE_PROGRESS = "message_progress"; private AppCompatButton btn_download; private ProgressBar progress; private TextView progress_text; private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(MESSAGE_PROGRESS)) { Download download = intent.getParcelableExtra("download"); progress.setProgress(download.getProgress()); if (download.getProgress() == 100) { progress_text.setText("File Download Complete"); } else { progress_text.setText(StringUtils.getDataSize(download.getCurrentFileSize()) +"/"+ StringUtils.getDataSize(download.getTotalFileSize())); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_download = (AppCompatButton) findViewById(R.id.btn_download); progress = (ProgressBar) findViewById(R.id.progress); progress_text = (TextView) findViewById(R.id.progress_text); registerReceiver(); btn_download.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, DownloadService.class); startService(intent); } }); } private void registerReceiver() { LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(MESSAGE_PROGRESS); bManager.registerReceiver(broadcastReceiver, intentFilter); } }
本文源碼:Retrofit Rxjava實(shí)現(xiàn)下載文件
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java讀取文件顯示進(jìn)度條的實(shí)現(xiàn)方法
- java控制臺(tái)輸出百分比進(jìn)度條示例
- Java上傳文件進(jìn)度條的實(shí)現(xiàn)方法(附demo源碼下載)
- java實(shí)現(xiàn)在復(fù)制文件時(shí)使用進(jìn)度條(java實(shí)現(xiàn)進(jìn)度條)
- JavaWeb項(xiàng)目實(shí)現(xiàn)文件上傳動(dòng)態(tài)顯示進(jìn)度實(shí)例
- Java動(dòng)態(tài)顯示文件上傳進(jìn)度實(shí)現(xiàn)代碼
- Java Swing組件實(shí)現(xiàn)進(jìn)度監(jiān)視功能示例
- Java Swing JProgressBar進(jìn)度條的實(shí)現(xiàn)示例
- java實(shí)現(xiàn)模擬進(jìn)度計(jì)量器
相關(guān)文章
SpringMVC實(shí)現(xiàn)文件的上傳和下載實(shí)例代碼
本篇文章主要介紹了SpringMVC實(shí)現(xiàn)文件的上傳和下載實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05淺談Servlet的Cookie和Session機(jī)制
雖然session機(jī)制在web應(yīng)用程序中被采用已經(jīng)很長(zhǎng)時(shí)間了,但是仍然有很多人不清楚session機(jī)制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù).本文將詳細(xì)討論session以及cookie的工作機(jī)制,需要的朋友可以參考下2021-05-05Kotlin語(yǔ)法學(xué)習(xí)-變量定義、函數(shù)擴(kuò)展、Parcelable序列化等簡(jiǎn)單總結(jié)
這篇文章主要介紹了Kotlin語(yǔ)法學(xué)習(xí)-變量定義、函數(shù)擴(kuò)展、Parcelable序列化等簡(jiǎn)單總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-05-05java中的FileReader和FileWriter讀寫(xiě)流
這篇文章主要介紹了java中的FileReader和FileWriter讀寫(xiě)流,在java中對(duì)數(shù)據(jù)輸入輸出的操作陳作為流我們對(duì)不同的文件進(jìn)行操作,或者對(duì)操作文件進(jìn)行輸入和輸出時(shí)所用的流都是不同的,因此在java.io的包下存在很多流的類(lèi)或者接口提供給我們對(duì)應(yīng)的操作,需要的朋友可以參考下2023-10-10詳解Spring中@Component和@Configuration的區(qū)別
一直有同學(xué)搞不清Spring中@Component和@Configuration這兩個(gè)注解有什么區(qū)別,所以這篇文章小編就給大家簡(jiǎn)單介紹一下@Component和@Configuration的區(qū)別,需要的朋友可以參考下2023-07-07Java+Redis撤銷(xiāo)重做功能實(shí)現(xiàn)
這篇文章主要介紹了Java+Redis實(shí)現(xiàn)撤銷(xiāo)重做功能,需要考慮撤銷(xiāo)的最大步數(shù),撤銷(xiāo)之后穿插著其他操作則不能再重做,所以引入分布式鎖Redisson進(jìn)行加鎖處理,防止對(duì)圖表的操作有并發(fā)請(qǐng)求導(dǎo)致處理撤銷(xiāo)邏輯混亂,感興趣的朋友跟隨小編一起看看吧2023-05-05