DownLoad--OKHttp3

使用OKHttp3进行下载和断点续传;(详细内容,请下载源码)

文件的存储和写入;

// 写文件到本地

try {

is = response.body().byteStream();

fileOutputStream = new FileOutputStream(file, true);

byte[] buffer = new byte[2048];//缓冲数组2kB

int len;

while ((len = is.read(buffer)) != -1) {

fileOutputStream.write(buffer, 0, len);

downloadLength += len;

downloadInfo.setProgress(downloadLength);

e.onNext(downloadInfo);

}

fileOutputStream.flush();

downCalls.remove(url);

} finally {

//关闭IO流

IOUtil.closeAll(is, fileOutputStream);

}

e.onComplete();//完成

集成RXJava和RxAndroid进行线程切换;

//RxJava和RxAndroid 用来做线程切换的

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

compile 'io.reactivex.rxjava2:rxjava:2.0.1'

// 下载

case R.id.main_btn_down3:

DownloadManager.getInstance().download(url3, new DownLoadObserver() {

@Override

public void onNext(DownloadInfo value) {

super.onNext(value);

info3 = value;

// 设置进度

float v1 = value.getProgress() * 100 / value.getTotal();

progress3.setProgress((int) ++v1);

}

@Override

public void onComplete() {

if (downloadInfo != null) {

ToastUtils.showShort(mContext, downloadInfo.getFileName() + "下载完成");

// 调出安装界面

installAPK(downloadInfo);

}

}

});

break;

// 取消3

case R.id.main_btn_cancel3:

DownloadManager.getInstance().cancel(url3);

progress3.setProgress(0);

// 删除本地文件

DownloadManager.getInstance().deleteFile(info3);

break;

// 暂停3

case R.id.main_btn_pause3:

DownloadManager.getInstance().cancel(url3);

break;

****************************************

/**

* 下载管理类

*/

public class DownloadManager {

private static final AtomicReference INSTANCE = new AtomicReference<>();

private HashMap downCalls;//用来存放各个下载的请求

private OkHttpClient mClient;//OKHttpClient;

// 文件下载的保存路径

public static final String apkPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();

/**

* 获得一个单例类

*

* @return

*/

public static DownloadManager getInstance() {

for (; ; ) {

DownloadManager current = INSTANCE.get();

if (current != null) {

return current;

}

current = new DownloadManager();

if (INSTANCE.compareAndSet(null, current)) {

return current;

}

}

}

private DownloadManager() {

downCalls = new HashMap<>();

mClient = new OkHttpClient.Builder().build();

}

/**

* 开始下载

*

* @param url 下载请求的网址

* @param downLoadObserver 用来回调的接口

*/

public void download(String url, DownLoadObserver downLoadObserver) {

Observable.just(url)

.filter(s -> !downCalls.containsKey(s))//call的map已经有了,就证明正在下载,则这次不下载

.flatMap(s -> Observable.just(createDownInfo(s)))

.map(this::getRealFileName)//检测本地文件夹,生成新的文件名

.flatMap(downloadInfo -> Observable.create(new DownloadSubscribe(downloadInfo, downCalls, mClient)))//下载

.observeOn(AndroidSchedulers.mainThread())//在主线程回调

.subscribeOn(Schedulers.io())//在子线程执行

.subscribe(downLoadObserver);//添加观察者

}

/**

* 取消

*

* @param url

*/

public void cancel(String url) {

Call call = downCalls.get(url);

if (call != null) {

call.cancel();

}

downCalls.remove(url);

}

/**

* 取消后 删除本地下载文件

*

* @param info

*/

public void deleteFile(DownloadInfo info) {

String fileName = info.getFileName();

File file = new File(apkPath, fileName);

if (file.exists()) {

file.delete();

}

}

/**

* 创建DownInfo

*

* @param url 请求网址

* @return DownInfo

*/

private DownloadInfo createDownInfo(String url) {

DownloadInfo downloadInfo = new DownloadInfo(url);

long contentLength = getContentLength(url);//获得文件大小

downloadInfo.setTotal(contentLength);

String fileName = url.substring(url.lastIndexOf("/"));

downloadInfo.setFileName(fileName);

return downloadInfo;

}

/**

* 获取真实文件名

*

* @param downloadInfo

* @return

*/

private DownloadInfo getRealFileName(DownloadInfo downloadInfo) {

String fileName = downloadInfo.getFileName();

long downloadLength = 0, contentLength = downloadInfo.getTotal();

File file = new File(apkPath, fileName);

if (file.exists()) {

//找到了文件,代表已经下载过,则获取其长度

downloadLength = file.length();

}

//之前下载过,需要重新来一个文件

int i = 1;

while (downloadLength >= contentLength) {

int dotIndex = fileName.lastIndexOf(".");

String fileNameOther;

if (dotIndex == -1) {

fileNameOther = fileName + "(" + i + ")";

} else {

fileNameOther = fileName.substring(0, dotIndex)

+ "(" + i + ")" + fileName.substring(dotIndex);

}

File newFile = new File(apkPath, fileNameOther);

file = newFile;

downloadLength = newFile.length();

i++;

}

//设置改变过的文件名/大小

downloadInfo.setProgress(downloadLength);

downloadInfo.setFileName(file.getName());

return downloadInfo;

}

/**

* 获取下载长度

*

* @param downloadUrl

* @return

*/

private long getContentLength(String downloadUrl) {

Request request = new Request.Builder()

.url(downloadUrl)

.build();

try {

Response response = mClient.newCall(request).execute();

if (response != null && response.isSuccessful()) {

long contentLength = response.body().contentLength();

response.close();

return contentLength == 0 ? DownloadInfo.TOTAL_ERROR : contentLength;

}

} catch (IOException e) {

e.printStackTrace();

}

return DownloadInfo.TOTAL_ERROR;

}

}

开启java8,使用Lambada表达式简化代码;

apply plugin: 'com.android.application'

android {

compileSdkVersion 24

buildToolsVersion "24.0.3"

defaultConfig {

applicationId "com.bill.download"

minSdkVersion 15

targetSdkVersion 24

versionCode 1

versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

//为了开启Java8

jackOptions {

enabled true;

}

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

}

}

//开启Java1.8 能够使用lambda表达式

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

}

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])

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:24.1.1'

testCompile 'junit:junit:4.12'

//OKHttp

compile 'com.squareup.okhttp3:okhttp:3.6.0'

//RxJava和RxAndroid 用来做线程切换的

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

compile 'io.reactivex.rxjava2:rxjava:2.0.1'

}

下载完成的安装,增加7.0文件权限的判定;

// 判断是否是7.0

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

Uri uriForFile = FileProvider.getUriForFile(mContext, "com.lanou3g.com.bill.downdemo.fileProvider", file); //在AndroidManifest中的android:authorities值

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件

intent.setDataAndType(uriForFile, "application/vnd.android.package-archive");

intent.setAction("android.intent.action.VIEW");

} else {

intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");

intent.setAction("android.intent.action.VIEW");

intent.addCategory("android.intent.category.DEFAULT");

}

自定义横向进度条;

/**

* 自定义横向进度条 (仿鸿洋的)

* Created by Bill on 2017/3/14.

*/

public class HorizontalProgressBarWithNumber extends ProgressBar {

private static final int DEFAULT_TEXT_SIZE = 10;

private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;

private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;

private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;

private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;

private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;

/**

* painter of all drawing things

*/

protected Paint mPaint = new Paint();

/**

* color of progress number

*/

protected int mTextColor = DEFAULT_TEXT_COLOR;

/**

* size of text (sp)

*/

protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);

/**

* offset of draw progress

*/

protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);

/**

* height of reached progress bar

*/

protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);

/**

* color of reached bar

*/

protected int mReachedBarColor = DEFAULT_TEXT_COLOR;

/**

* color of unreached bar

*/

protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;

/**

* height of unreached progress bar

*/

protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);

/**

* view width except padding

*/

protected int mRealWidth;

protected boolean mIfDrawText = true;

protected static final int VISIBLE = 0;

public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

obtainStyledAttributes(attrs);

mPaint.setTextSize(mTextSize);

mPaint.setColor(mTextColor);

}

@Override

protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = MeasureSpec.getSize(widthMeasureSpec);

int height = measureHeight(heightMeasureSpec);

setMeasuredDimension(width, height);

mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();

}

/**

* 测量高度

*

* @param measureSpec

* @return

*/

private int measureHeight(int measureSpec) {

int result = 0;

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {

result = specSize;

} else {

float textHeight = (mPaint.descent() - mPaint.ascent());

result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(

Math.max(mReachedProgressBarHeight,

mUnReachedProgressBarHeight), Math.abs(textHeight)));

if (specMode == MeasureSpec.AT_MOST) {

result = Math.min(result, specSize);

}

}

return result;

}

/**

* 获取自定义属性

*

* @param attrs

*/

private void obtainStyledAttributes(AttributeSet attrs) {

// init values from custom attributes

final TypedArray attributes = getContext().obtainStyledAttributes(

attrs, R.styleable.HorizontalProgressBarWithNumber);

mTextColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_text_color,

DEFAULT_TEXT_COLOR);

mTextSize = (int) attributes.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_text_size,

mTextSize);

mReachedBarColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,

mTextColor);

mUnReachedBarColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,

DEFAULT_COLOR_UNREACHED_COLOR);

mReachedProgressBarHeight = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,

mReachedProgressBarHeight);

mUnReachedProgressBarHeight = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,

mUnReachedProgressBarHeight);

mTextOffset = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,

mTextOffset);

int textVisible = attributes

.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,

VISIBLE);

if (textVisible != VISIBLE) {

mIfDrawText = false;

}

attributes.recycle();

}

@Override

protected synchronized void onDraw(Canvas canvas) {

canvas.save();

canvas.translate(getPaddingLeft(), getHeight() / 2);

boolean noNeedBg = false;

float radio = getProgress() * 1.0f / getMax();

float progressPosX = (int) (mRealWidth * radio);

String text = getProgress() + "%";

// mPaint.getTextBounds(text, 0, text.length(), mTextBound);

float textWidth = mPaint.measureText(text);

float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

if (progressPosX + textWidth > mRealWidth) {

progressPosX = mRealWidth - textWidth;

noNeedBg = true;

}

// draw reached bar

float endX = progressPosX - mTextOffset / 2;

if (endX > 0) {

mPaint.setColor(mReachedBarColor);

mPaint.setStrokeWidth(mReachedProgressBarHeight);

canvas.drawLine(0, 0, endX, 0, mPaint);

}

// draw progress bar

// measure text bound

if (mIfDrawText) {

mPaint.setColor(mTextColor);

canvas.drawText(text, progressPosX, -textHeight, mPaint);

}

// draw unreached bar

if (!noNeedBg) {

float start = progressPosX + mTextOffset / 2 + textWidth;

mPaint.setColor(mUnReachedBarColor);

mPaint.setStrokeWidth(mUnReachedProgressBarHeight);

canvas.drawLine(start, 0, mRealWidth, 0, mPaint);

}

canvas.restore();

}

/**

* dp 2 px

*

* @param dpVal

*/

protected int dp2px(int dpVal) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

dpVal, getResources().getDisplayMetrics());

}

/**

* sp 2 px

*

* @param spVal

* @return

*/

protected int sp2px(int spVal) {

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,

spVal, getResources().getDisplayMetrics());

}

}

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐