基于NoHttp+RxBus实现文件下载(带下载进度)

自己挖的坑早晚都是要填的。


首先,这是个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就可以实现下载了。见代码:
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");
    }
}
就这样,我们在Service中注册了RxBus,接收从Activity传过来的下载请求,一旦有请求Service马上就下载,再通过RxBus将下载结果发送出去,我么就可以在Activity中接收Service返回的结果来更新UI。
 
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接收的代码基本完全一样。
 
源码路径在这里。点击打开链接
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值