自己挖的坑早晚都是要填的。
首先,这是个AS工程就需要导入NoHttp和RxBus的库:
在工程的build.gradle文件的dependencies节点添加下面两项,compile'io.reactivex:rxjava:1.1.6'和compile'com.yolanda.nohttp:nohttp:1.1.0'
如下:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'
testCompile 'junit:junit:4.12'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.6'
compile 'com.yolanda.nohttp:nohttp:1.1.0'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.trello:rxlifecycle:0.3.0'
compile 'com.trello:rxlifecycle-components:0.3.0'
compile 'com.android.support:cardview-v7:25.0.1'
}
一、下载实现思路:
1.文件下载我们使用NoHttp在Service中进行下载
2.利用RxBus做为桥梁,让Activity和Service进行通讯
二、下面就细说一下具体怎么实现:
2.1 在工程的Application中初始化Nohttp:
(没有使用过Nohttp的同学可以先看看严大神的github:点击打开链接)
private void initNoHttp() {
NoHttp.Config config = new NoHttp.Config();
config.setConnectTimeout(5 * 1000);
config.setReadTimeout(5 * 1000);
config.setCacheStore(new DiskCacheStore(this));
config.setCookieStore(new DBCookieStore(this).setEnable(true));
config.setNetworkExecutor(new URLConnectionNetworkExecutor());
NoHttp.initialize(this, config);
}
2.2 创建我们自己的RxBus:
public class RxBus {
private static RxBus instance;
private static CompositeSubscription mCompositeSubscription;
private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.<Object>create());
private RxBus() {
}
public static RxBus getInstance() {
if (instance == null)
synchronized (RxBus.class) {
if (instance == null)
instance = new RxBus();
mCompositeSubscription = new CompositeSubscription();
}
return instance;
}
public void send(Object o) {
_bus.onNext(o);
}
public Observable<Object> toObservable() {
return _bus;
}
public boolean hasObservers() {
return _bus.hasObservers();
}
public void receive(Func1<Object, Boolean> func1, Action1<Object> onNext, Action1<Throwable> onError, Action0 onCompleted) {
mCompositeSubscription.add(RxBus.getInstance().toObservable().filter(func1).subscribe(onNext, onError == null ? new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
} : onError, onCompleted));
}
public void unsubscribe() {
if (instance.hasObservers() && mCompositeSubscription.isUnsubscribed())
mCompositeSubscription.unsubscribe();
}
}
我们的RxBus中重要的就是:
PublishSubject:源码中你会发现PublishSubjet继承抽象类Subject,Subject而又继承了Observable,实现了Observer。所以可以说PublishSubject既是Observable,又是Observer。意思就是说既可以发送信息又可以接收信息
send():用来发送信息的
receive():用来接收信息的。receive方法具体可以看看前面写的一个小功能有说到点击打开链接,如果觉得还够可以在看看我转载的其他大神关于RxBus的文章。
2.3 Nohttp实现下载:
在Nohttp中实现下载很简单。首先创建一个DownloadRequest,然后创建一个请求队列:DownloadQueue,再然后创建一个DownloadListener就可以实现下载了。见代码:
就这样,我们在Service中注册了RxBus,接收从Activity传过来的下载请求,一旦有请求Service马上就下载,再通过RxBus将下载结果发送出去,我么就可以在Activity中接收Service返回的结果来更新UI。public class DownLoadService extends Service { /** * 下载队列. */ private DownloadQueue downloadQueue; private RxBus rxBus; // private List<DownLoadBean> downLoadBeans; private DownLoadBean downLoadTask; @Override public void onCreate() { super.onCreate(); Log.e("info", "DownLoadService:" + "Start"); // downLoadBeans = new ArrayList<DownLoadBean>(); if (downloadQueue == null) downloadQueue = NoHttp.getDownloadQueueInstance(); rxBus = RxBus.getInstance(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("info", "onStartCommand"); rxBus.receive(new Func1<Object, Boolean>() { @Override public Boolean call(Object o) { if (o instanceof DownLoadBean) { DownLoadBean downLoadBean = (DownLoadBean) o; return downLoadBean.getStatus() == DownLoadBean.DOWNLOCADBEAN_STATUS_NOMAL ? true : false; } return false; } }, new Action1<Object>() { @Override public void call(Object o) { DownLoadBean downLoadBean = (DownLoadBean) o; // downLoadBeans.add(downLoadBean); downLoadTask = downLoadBean; download(downLoadBean.getId(), downLoadBean, downloadListener); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.e("info", "RxBus---receive出错了!"); } }, new Action0() { @Override public void call() { } }); return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } /** * 开始下载。 */ private void download(int what, DownLoadBean downLoadBean, DownloadListener downloadListener) { DownloadRequest downloadRequest = null; // 开始下载了,但是任务没有完成,代表正在下载,那么暂停下载。 if (downloadRequest != null && downloadRequest.isStarted() && !downloadRequest.isFinished()) { // 暂停下载。 downloadRequest.cancel(); } else if (downloadRequest == null) {// 没有开始就重新下载。 /** * 这里不传文件名称、不断点续传,则会从响应头中读取文件名自动命名,如果响应头中没有则会从url中截取。 */ // url 下载地址。 // fileFolder 文件保存的文件夹。 // isDeleteOld 发现文件已经存在是否要删除重新下载。 // mDownloadRequest = NoHttp.createDownloadRequest(Constants.URL_DOWNLOADS[0], AppConfig.getInstance().APP_PATH_ROOT, true); /** * 如果使用断点续传的话,一定要指定文件名喔。 */ // url 下载地址。 // fileFolder 保存的文件夹。 // fileName 文件名。 // isRange 是否断点续传下载。 // isDeleteOld 如果发现存在同名文件,是否删除后重新下载,如果不删除,则直接下载成功。 //Log.e("info", "downLoadBean:" + downLoadBean.toString()); downloadRequest = NoHttp.createDownloadRequest(downLoadBean.getUrl(), downLoadBean.getFileFolder(), downLoadBean.getFilename(), true, false); if (downloadRequest.isStarted()) { Toast.makeText(DownLoadService.this, "文件正在下载!!", Toast.LENGTH_SHORT).show(); return; } // what 区分下载。 // downloadRequest 下载请求对象。 // downloadListener 下载监听。 downloadQueue.add(what, downloadRequest, downloadListener); } } /** * 下载监听 */ private DownloadListener downloadListener = new DownloadListener() { @Override public void onStart(int what, boolean isResume, long beforeLength, Headers headers, long allCount) { int progress = 0; if (allCount != 0) { progress = (int) (beforeLength * 100 / allCount); } Log.e("info", what + "----onStart:"); // downLoadBeans.get(what).setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_START); // rxBus.send(downLoadBeans.get(what)); downLoadTask.setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_START); downLoadTask.setMsg("开始下载!"); rxBus.send(downLoadTask); } @Override public void onDownloadError(int what, Exception exception) { String message = getString(R.string.download_error); String messageContent; if (exception instanceof ServerError) { messageContent = getString(R.string.download_error_server); } else if (exception instanceof NetworkError) { messageContent = getString(R.string.download_error_network); } else if (exception instanceof StorageReadWriteError) { messageContent = getString(R.string.download_error_storage); } else if (exception instanceof StorageSpaceNotEnoughError) { messageContent = getString(R.string.download_error_space); } else if (exception instanceof TimeoutError) { messageContent = getString(R.string.download_error_timeout); } else if (exception instanceof UnKnownHostError) { messageContent = getString(R.string.download_error_un_know_host); } else if (exception instanceof URLError) { messageContent = getString(R.string.download_error_url); } else { messageContent = getString(R.string.download_error_un); } message = String.format(Locale.getDefault(), message, messageContent); Log.e("info", what + "----onDownloadError:" + message); downLoadTask.setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_ERROR); downLoadTask.setMsg(message); rxBus.send(downLoadTask); // downLoadBeans.get(what).setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_ERROR); // rxBus.send(downLoadBeans.get(what)); } @Override public void onProgress(int what, int progress, long fileCount) { Log.e("info", what + "--progress:" + progress); downLoadTask.setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_PROGRESS); downLoadTask.setDownProgress(progress); downLoadTask.setMsg("正在下载。。。"); rxBus.send(downLoadTask); // downLoadBeans.get(what).setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_PROGRESS); // downLoadBeans.get(what).setDownProgress(progress); // rxBus.send(downLoadBeans.get(what)); } @Override public void onFinish(int what, String filePath) { Log.e("info", "onFinish:" + what + "--filePath:" + filePath); downLoadTask.setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_FINISH); downLoadTask.setMsg("下载完成下载完成!"); rxBus.send(downLoadTask); // downLoadBeans.get(what).setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_FINISH); // rxBus.send(downLoadBeans.get(what)); } @Override public void onCancel(int what) { Log.e("info", what + "---onCancel:"); downLoadTask.setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_CANCEL); rxBus.send(downLoadTask); // downLoadBeans.get(what).setStatus(DownLoadBean.DOWNLOCADBEAN_STATUS_CANCEL); // rxBus.send(downLoadBeans.get(what)); } }; @Override public void onDestroy() { super.onDestroy(); rxBus.unsubscribe(); Log.e("info", "DownLoadService---stop"); } }
2.4 更新UI主要代码:
private void initRxBus() { rxBus = RxBus.getInstance(); rxBus.receive(new Func1<Object, Boolean>() { @Override public Boolean call(Object baseBean) { if (baseBean instanceof DownLoadBean) { DownLoadBean d = (DownLoadBean) baseBean; return d.getStatus() != DownLoadBean.DOWNLOCADBEAN_STATUS_NOMAL ? true : false; } return false; } }, new Action1<Object>() { @Override public void call(Object baseBean) { DownLoadBean receiveBaseBean = (DownLoadBean) baseBean; //这里跟新UI status.setText(receiveBaseBean.getMsg()); progressBar.setProgress(receiveBaseBean.getDownProgress()); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Log.e("info", "RxBus 接收出错了!"); } }, new Action0() { @Override public void call() { Log.e("info", "RxBus 接收结束了!"); } }); }
这里的代码和Service中RxBus接收的代码基本完全一样。
源码路径在这里。点击打开链接