refactor: replace RxDownload with my own implementation
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package com.stardust.scriptdroid.network.api;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Streaming;
|
||||
import retrofit2.http.Url;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/12/6.
|
||||
*/
|
||||
|
||||
public interface DownloadApi {
|
||||
|
||||
@GET
|
||||
@Streaming
|
||||
Observable<ResponseBody> download(@Url String url);
|
||||
|
||||
}
|
||||
@@ -1,17 +1,24 @@
|
||||
package com.stardust.scriptdroid.network.download;
|
||||
|
||||
import android.content.Context;
|
||||
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.scriptdroid.network.NodeBB;
|
||||
import com.stardust.scriptdroid.network.api.DownloadApi;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
import retrofit2.http.Url;
|
||||
import zlc.season.rxdownload3.RxDownload;
|
||||
import zlc.season.rxdownload3.core.Failed;
|
||||
import zlc.season.rxdownload3.core.Mission;
|
||||
import zlc.season.rxdownload3.core.Succeed;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Retrofit;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/10/20.
|
||||
@@ -21,16 +28,36 @@ public class DownloadManager {
|
||||
|
||||
private static DownloadManager sInstance;
|
||||
|
||||
private Context mContext;
|
||||
private static final int RETRY_COUNT = 3;
|
||||
private Retrofit mRetrofit;
|
||||
private DownloadApi mDownloadApi;
|
||||
private ConcurrentHashMap<String, VolatileBox<Boolean>> mDownloadStatuses = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public DownloadManager(Context context) {
|
||||
mContext = context;
|
||||
public DownloadManager() {
|
||||
mRetrofit = new Retrofit.Builder()
|
||||
.baseUrl(NodeBB.BASE_URL)
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
.client(new OkHttpClient.Builder()
|
||||
.addInterceptor(chain -> {
|
||||
Request request = chain.request();
|
||||
Response response = chain.proceed(request);
|
||||
int tryCount = 0;
|
||||
while (!response.isSuccessful() && tryCount < RETRY_COUNT) {
|
||||
tryCount++;
|
||||
response = chain.proceed(request);
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
mDownloadApi = mRetrofit.create(DownloadApi.class);
|
||||
}
|
||||
|
||||
public static DownloadManager getInstance(Context context) {
|
||||
|
||||
public static DownloadManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new DownloadManager(context);
|
||||
sInstance = new DownloadManager();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
@@ -45,28 +72,89 @@ public class DownloadManager {
|
||||
}
|
||||
|
||||
public Observable<Integer> download(String url, String path) {
|
||||
File file = new File(path);
|
||||
Mission mission = new Mission(url, file.getName(), file.getParent());
|
||||
PublishSubject<Integer> progress = PublishSubject.create();
|
||||
RxDownload.INSTANCE.create(mission)
|
||||
.subscribe(status -> {
|
||||
if (status.getTotalSize() > 0) {
|
||||
int p = (int) Math.floor((float) status.getDownloadSize() / status.getTotalSize() * 100);
|
||||
progress.onNext(p);
|
||||
}
|
||||
if (status instanceof Succeed) {
|
||||
progress.onComplete();
|
||||
RxDownload.INSTANCE.delete(mission);
|
||||
} else if (status instanceof Failed) {
|
||||
progress.onError(((Failed) status).getThrowable());
|
||||
}
|
||||
});
|
||||
RxDownload.INSTANCE.start(mission).subscribe();
|
||||
return progress;
|
||||
DownloadTask task = new DownloadTask(url, path);
|
||||
mDownloadApi.download(url)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(task::start);
|
||||
return task.progress();
|
||||
}
|
||||
|
||||
public void cancelDownload(String url) {
|
||||
RxDownload.INSTANCE.stop(url);
|
||||
RxDownload.INSTANCE.delete(url);
|
||||
VolatileBox<Boolean> status = mDownloadStatuses.get(url);
|
||||
if (status != null) {
|
||||
status.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadTask {
|
||||
|
||||
private String mUrl;
|
||||
private String mPath;
|
||||
private VolatileBox<Boolean> mStatus;
|
||||
private InputStream mInputStream;
|
||||
private FileOutputStream mFileOutputStream;
|
||||
private PublishSubject<Integer> mProgress;
|
||||
|
||||
public DownloadTask(String url, String path) {
|
||||
mUrl = url;
|
||||
mPath = path;
|
||||
mStatus = new VolatileBox<>(true);
|
||||
VolatileBox<Boolean> previous = mDownloadStatuses.put(mUrl, mStatus);
|
||||
if (previous != null)
|
||||
previous.set(false);
|
||||
mProgress = PublishSubject.create();
|
||||
}
|
||||
|
||||
public void start(ResponseBody body) throws IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
mFileOutputStream = new FileOutputStream(mPath);
|
||||
mInputStream = body.byteStream();
|
||||
long total = body.contentLength();
|
||||
long read = 0;
|
||||
while (read < total) {
|
||||
if (!mStatus.get()) {
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
int len = mInputStream.read(buffer);
|
||||
if (len == -1) {
|
||||
break;
|
||||
}
|
||||
read += len;
|
||||
mFileOutputStream.write(buffer, 0, len);
|
||||
mProgress.onNext((int) (100 * read / total));
|
||||
}
|
||||
mProgress.onComplete();
|
||||
recycle();
|
||||
}
|
||||
|
||||
private void onCancel() throws IOException {
|
||||
recycle();
|
||||
// TODO: 2017/12/6 notify?
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
mDownloadStatuses.remove(mUrl);
|
||||
if (mInputStream != null) {
|
||||
try {
|
||||
mInputStream.close();
|
||||
} catch (IOException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
if (mFileOutputStream != null) {
|
||||
try {
|
||||
mFileOutputStream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Observable<Integer> progress() {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,13 +265,13 @@ public class ScriptOperations {
|
||||
.title(fileName)
|
||||
.cancelable(false)
|
||||
.positiveText(R.string.text_cancel_download)
|
||||
.onPositive((dialog, which) -> DownloadManager.getInstance(mContext).cancelDownload(url))
|
||||
.onPositive((dialog, which) -> DownloadManager.getInstance().cancelDownload(url))
|
||||
.show();
|
||||
}
|
||||
|
||||
public Observable<ScriptFile> download(String url, String path, MaterialDialog progressDialog) {
|
||||
PublishSubject<ScriptFile> subject = PublishSubject.create();
|
||||
DownloadManager.getInstance(mContext).download(url, path)
|
||||
DownloadManager.getInstance().download(url, path)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext(progressDialog::setProgress)
|
||||
.doOnComplete(() -> {
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.ui.common.NotAskAgainDialog;
|
||||
import com.stardust.scriptdroid.ui.common.ScriptOperations;
|
||||
import com.stardust.scriptdroid.ui.doc.DocsFragment_;
|
||||
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
|
||||
import com.stardust.scriptdroid.storage.file.StorageFileProvider;
|
||||
|
||||
Reference in New Issue
Block a user