【文件下载】Rxjava+Retrofit+Mvp完成文件下载

【文件下载】Rxjava+retrofit+MVP完成文件下载

RxJava跟retrofit实现网络请求真的是太方便了,代码走起,实现下载文件、断点续传功能。
1、导入需要的jar包
/* rxjava */
    /* retrofit */
    /* okhttp  */
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
    compile 'de.greenrobot:eventbus:2.4.0'
    compile 'com.daimajia.numberprogressbar:library:1.4@aar'
2、定义Retrofit请求接口
package com.example.a75213.testdownloaddemo.API;

import okhttp3.ResponseBody;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
import retrofit2.http.Url;
import rx.Observable;

/**
 * Created by 75213 on 2017/10/31.
 */

public interface RetrofitApiService {

    @Streaming
    @GET
    Observable<ResponseBody> downloadFileWithDynamicUrlSync(@Url String fileUrl);
}

3、实现接口逻辑封装
package com.example.a75213.testdownloaddemo.helper;

import com.example.a75213.testdownloaddemo.API.RetrofitApiService;
import com.example.a75213.testdownloaddemo.network.download.DownloadProgressInterceptor;
import com.example.a75213.testdownloaddemo.network.download.DownloadProgressListener;
import com.example.a75213.testdownloaddemo.network.exception.CustomizeException;
import com.example.a75213.testdownloaddemo.utils.FileUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * Created by 75213 on 2017/10/31.
 */

public class RetrofitManager {
    private static final int DEFAULT_TIMEOUT = 15;
    private RetrofitApiService downloadRetrofitApiService;
    private static RetrofitManager sInstace = null;

    public static RetrofitManager builder() {
        if (sInstace == null) {
            synchronized (RetrofitManager.class) {
                sInstace = new RetrofitManager();
            }
        }
        return sInstace;
    }

    public RetrofitApiService getDownloadService(String url , DownloadProgressListener listener , File file){
        DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener , file);
        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(interceptor)
                .retryOnConnectionFailure(true)
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .client(client)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        downloadRetrofitApiService = retrofit.create(RetrofitApiService.class);
        return downloadRetrofitApiService;
    }

    //下载
    public void downApkFile(Subscription subscription, String path , final File file){
        Observable observable = downloadRetrofitApiService.
                downloadFileWithDynamicUrlSync(path)
                .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);
                        }
                    }
                })
                ;
        toSubscribe(observable, (Subscriber) subscription);
    }


    public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) {
        o.subscribeOn(Schedulers.io())  // 被观察者的实现线程
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())  // 观察者的实现线程
                .subscribe(s);
    }

}
3.1、断点续传实现代码
package com.example.a75213.testdownloaddemo.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.view.View;

import com.example.a75213.testdownloaddemo.network.exception.CustomizeException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

public class FileUtils {
 
    /**
     * 写入文件
     * 断点续传
     * @param in
     * @param file
     */
    public static void writeFile(InputStream in, File file) throws IOException {
        RandomAccessFile savedFile = null;
        long ltest = 0;
        if (!file.getParentFile().exists())
            file.getParentFile().mkdirs();
        if (file != null && file.exists()){
            ltest = file.length();
        }
        if (in != null){
            savedFile = new RandomAccessFile(file , "rw");
            savedFile.seek(ltest);
            byte[] buffer = new byte[1024 * 128];
            int len = -1;
            while ((len = in.read(buffer)) != -1) {
                savedFile.write(buffer, 0, len);
            }
            in.close();
        }else {
            throw new CustomizeException("下载失败" , new Throwable("检查网网咯"));
        }
    }

    /**
     * 读取文件长度
     */
    public static long readFile(File file){
        if (file != null && file.exists()){
            return file.length();
        }else {
            return 0;
        }
    }



}

3.2、自定义拦截器【获取下载进度】
package com.example.a75213.testdownloaddemo.network.download;

import com.example.a75213.testdownloaddemo.ResponseBody.DownloadProgressResponseBody;
import com.example.a75213.testdownloaddemo.utils.FileUtils;

import java.io.File;
import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Interceptor for download
 */
public class DownloadProgressInterceptor implements Interceptor {
    private long startpos;
    private DownloadProgressListener listener;

    public DownloadProgressInterceptor(DownloadProgressListener listener , File file){
        this.listener = listener;
        startpos = FileUtils.readFile(file);
    }


    @Override
    public Response intercept(Chain chain) throws IOException {
        //断点续传
        Request request = chain.request().newBuilder().addHeader("Range" , "bytes=" + startpos + "-").build();
        Response originalResponse = chain.proceed(request);
        return originalResponse.newBuilder()
                .body(new DownloadProgressResponseBody(originalResponse.body(), listener))
                .build();
    }
}

4、M层
package com.example.a75213.testdownloaddemo.M;

import android.content.Context;
import android.util.Log;

import com.example.a75213.testdownloaddemo.API.RetrofitApiService;
import com.example.a75213.testdownloaddemo.contant.comm;
import com.example.a75213.testdownloaddemo.helper.RetrofitManager;
import com.example.a75213.testdownloaddemo.network.download.DownloadProgressListener;
import com.example.a75213.testdownloaddemo.utils.StringUtils;

import java.io.File;

import rx.Subscriber;
import rx.Subscription;

/**
 * Created by 75213 on 2017/10/31.
 */

public class HomeModelImpl implements HomeModel{
    private RetrofitApiService dRetrofitService;
    private RetrofitManager retrofitManager;

    public HomeModelImpl(){
        retrofitManager = retrofitManager.builder();
    }


    @Override
    public void downFile(String apkPath , DownloadProgressListener listener, final OnResult lister) {
        String baseUrl = StringUtils.getHostName(apkPath);
        File outputFile = comm.getPathFile(apkPath);
        dRetrofitService = retrofitManager.builder().getDownloadService(baseUrl , listener , outputFile);
        Subscription subscription = new Subscriber() {
            @Override
            public void onCompleted() {
                lister.onS();
            }

            @Override
            public void onError(Throwable e) {
                Log.e("测试错误" , e.getMessage());
                lister.onE(e);
            }

            @Override
            public void onNext(Object o) {

            }
        };
       retrofitManager.downApkFile(subscription , apkPath , outputFile);
    }
}

5、P层
package com.example.a75213.testdownloaddemo.P;

import android.os.Environment;

import com.example.a75213.testdownloaddemo.M.HomeModel;
import com.example.a75213.testdownloaddemo.M.HomeModelImpl;
import com.example.a75213.testdownloaddemo.contant.comm;
import com.example.a75213.testdownloaddemo.network.download.DownloadProgressListener;
import com.example.a75213.testdownloaddemo.utils.StringUtils;

import java.io.File;

/**
 * Created by 75213 on 2017/11/1.
 */

public class HomePresenterImpl implements HomePresenter , HomeModel.OnResult{
    private HomeModel model ;
    private onPResult lister;
    private DownloadProgressListener listener;

    public HomePresenterImpl(DownloadProgressListener listener , onPResult lister){
       this.lister =  lister;
        this.listener = listener;
    }

    //下载
    @Override
    public void downApkFile(String path) {
        model = new HomeModelImpl();
        model.downFile(path, listener , this);
    }

    @Override
    public void onS() {
        lister.onSuu();
    }

    @Override
    public void onE(Throwable throwable) {
        lister.onTh(throwable);
    }
}

6、V层
package com.example.a75213.testdownloaddemo.TestDemo;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.daimajia.numberprogressbar.NumberProgressBar;
import com.example.a75213.testdownloaddemo.P.HomePresenter;
import com.example.a75213.testdownloaddemo.P.HomePresenterImpl;
import com.example.a75213.testdownloaddemo.R;
import com.example.a75213.testdownloaddemo.bean.TestBean;
import com.example.a75213.testdownloaddemo.contant.comm;
import com.example.a75213.testdownloaddemo.network.download.DownloadProgressListener;
import com.example.a75213.testdownloaddemo.utils.StringUtils;

import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;

public class ATestActivity extends AppCompatActivity implements DownloadProgressListener ,HomePresenter.onPResult{
    /**
     * 
     */
    private HomePresenter homePresenter;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    TestBean bean = msg.getData().getParcelable("data");
                    activityfilebar.setProgress(bean.getPorBar());
                    String strF = getResources().getString(R.string.down_content);
                    String result = String.format(strF , bean.getByteStr() , bean.getContentStr());
                    activityfilesize.setText(result);
                    break;
            }
        }
    };

    private android.widget.TextView activitydowntitle;
    private android.widget.TextView activitydowncontent;
    private android.widget.TextView activitydowngo;
    private com.daimajia.numberprogressbar.NumberProgressBar activityfilebar;
    private android.widget.LinearLayout activitydownshow;
    private android.widget.FrameLayout activitydowning;
    private TextView activityfilesize;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_atest);
        this.activitydowning = (FrameLayout) findViewById(R.id.activity_downing);
        this.activitydownshow = (LinearLayout) findViewById(R.id.activity_down_show);
        this.activityfilesize = (TextView) findViewById(R.id.activity_file_size);
        this.activityfilebar = (NumberProgressBar) findViewById(R.id.activity_file_bar);
        homePresenter = new HomePresenterImpl(this ,this);
        this.activitydowngo = (TextView) findViewById(R.id.activity_down_go);
        this.activitydowncontent = (TextView) findViewById(R.id.activity_down_content);
        this.activitydowntitle = (TextView) findViewById(R.id.activity_down_title);

        activitydowngo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                downFileApk();
            }
        });
    }

    private int progressNext = -1;
    @Override
    public void update(long bytesRead, long contentLength, boolean done) {
        int progress = 0;
        if (0 != contentLength){
            progress = (int) (((bytesRead * 100) / contentLength)) ;
        }
        Log.e("数据回调" , "bytesRead : " + StringUtils.getDataSize(bytesRead) + "\n contentLength" + StringUtils.getDataSize(contentLength) + "\n done " + done + "\n 进度条 " + progress);
       if (progressNext != progress){
           TestBean bean = new TestBean();
           bean.setPorBar(progress);
           bean.setByteStr(StringUtils.getDataSize(bytesRead));
           bean.setContentStr( StringUtils.getDataSize(contentLength));
           Bundle bundle = new Bundle();
           bundle.putParcelable("data" , bean);
           Message msg = new Message();
           msg.what = 1;
           msg.setData(bundle);
           handler.sendMessage(msg);
           progressNext = progress;
       }else {
           return;
       }
    }

    private void downFileApk(){
        activitydownshow.setVisibility(View.GONE);
        activitydowning.setVisibility(View.VISIBLE);
        homePresenter.downApkFile(url);
    }

    String url = "http://imtt.dd.qq.com/16891/7C7BB50B68B684A36339AF1F615E2848.apk";

    @Override
    public void onSuu() {
        //安装apk
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(comm.getPathFile(url)), "application/vnd.android.package-archive");
        startActivity(intent);
        finish();
    }

    @Override
    public void onTh(Throwable throwable) {

    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK){
            moveTaskToBack(true);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值