//初始化SD卡
private void initSD() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED) {
readSD();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission
.WRITE_EXTERNAL_STORAGE}, 100);
}
}
//权限处理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 100:
if (grantResults.length > 0 && grantResults[0] == PackageManager
.PERMISSION_GRANTED) {
readSD();
}
break;
}
}
//读取SD卡
private void readSD() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
sd = Environment.getExternalStorageDirectory();
}
}
private void moreHttp() {
ThreadManager.getThreadManager().execute(new Runnable() {
@Override
public void run() {
try {
//1.通过网络加载获取文件长度
URL urlStr = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlStr.openConnection();
int contentLength = con.getContentLength();
Log.e(TAG, "run: " + contentLength);
//2.c创建空白文件,指定长度
RandomAccessFile rw = new RandomAccessFile(mDownPath, "rw");
rw.setLength(contentLength);
//3.各自线程设置下载对应的长度
long block = contentLength / THREAD_COUNT;
//4.创建指定个数的线程并给定下载范围下载
for (int i = 0; i < THREAD_COUNT; i++) {
long start = i * block;
long end = (i + 1) * block - 1;
if (i == THREAD_COUNT - 1) {
end = contentLength - 1;
}
//4.开始各自线程的下载即可(加请求范围头,判断状态码206,从对应线程开始位置写入数据)
//down(i, start, end);//多线程下载
downContinue(i, start, end);//多线程断点下载
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
//断点下载
private void downContinue(final int threadId, final long start, final long end) {
Log.d(TAG, "线程: " + threadId + ",下载范围:" + start + "--" + end);
ThreadManager.getThreadManager().execute(new Runnable() {
@Override
public void run() {
//记录当前线程下载位置
long currentPosition = start;
//获取sp中的下载位置,如果为0,说明没有下载过或者下载完成过
long position = (long)SharedPreferencesUtils.getParam(MainActivity.this, threadId + "",
0L);
if (position == 0){//没有下载记录
currentPosition = start;
Log.d(TAG, "非断点续传: "+threadId+",currentPosition:"+currentPosition);
}else{//有级录
currentPosition = position;
Log.d(TAG, "断点续传: "+threadId+",currentPosition:"+currentPosition);
}
URL urlStr = null;
try {
urlStr = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlStr.openConnection();
//设置请求部分数据资源:Range:bytes=10-30
con.setRequestProperty("Range", "bytes=" + currentPosition + "-" + end);
int responseCode = con.getResponseCode();
Log.d(TAG, "responseCode: " + responseCode);
//206,请求部分资源
if (responseCode == 206) {
InputStream inputStream = con.getInputStream();
RandomAccessFile rw = new RandomAccessFile(mDownPath, "rw");
//设置当前线程写入的位置
rw.seek(currentPosition);
int length = -1;
byte[] bys = new byte[1024 * 10];
while ((length = inputStream.read(bys)) != -1) {
rw.write(bys, 0, length);
currentPosition += length;
Log.d(TAG, "线程: " + threadId + "开始:" + start + " 当前下载:" + currentPosition + " " +
"结束:" + end);
//将当前写入的位置保存
SharedPreferencesUtils.setParam(MainActivity.this,threadId+"",currentPosition);
if (threadId == 0){
pb.setMax((int)end);
pb.setProgress((int)currentPosition);
}else if (threadId == 1){
pb1.setMax((int)end);
pb1.setProgress((int)currentPosition);
}else if (threadId == 2){
pb2.setMax((int)end);
pb2.setProgress((int)currentPosition);
}
}
inputStream.close();
rw.close();
Log.d(TAG, "线程: " + threadId + "下载玩完毕");
//完成下载后将当前的写入位置置零
SharedPreferencesUtils.setParam(MainActivity.this,threadId+"",0L);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
private void down(final int threadId, final long start, final long end) {
Log.d(TAG, "线程: " + threadId + ",下载范围:" + start + "--" + end);
ThreadManager.getThreadManager().execute(new Runnable() {
@Override
public void run() {
URL urlStr = null;
try {
urlStr = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlStr.openConnection();
//设置请求部分数据资源:Range:bytes=10-30
con.setRequestProperty("Range", "bytes=" + start + "-" + end);
int responseCode = con.getResponseCode();
Log.d(TAG, "responseCode: " + responseCode);
//206,请求部分资源
if (responseCode == 206) {
InputStream inputStream = con.getInputStream();
RandomAccessFile rw = new RandomAccessFile(mDownPath, "rw");
rw.seek(start);
int count = (int) start;
int length = -1;
byte[] bys = new byte[1024 * 10];
while ((length = inputStream.read(bys)) != -1) {
rw.write(bys, 0, length);
count += length;
Log.d(TAG, "线程: " + threadId + "开始:" + start + " 当前下载:" + count + " " +
"结束:" + end);
if (threadId == 0){
pb.setMax((int)end);
pb.setProgress((int)count);
}else if (threadId == 1){
pb1.setMax((int)end);
pb1.setProgress((int)count);
}else if (threadId == 2){
pb2.setMax((int)end);
pb2.setProgress((int)count);
}
}
inputStream.close();
rw.close();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
//Http下载
private void http(final String path) {
ThreadManager.getThreadManager().execute(new Runnable() {
@Override
public void run() {
try {
URL urlStr = new URL(url);
HttpURLConnection con = (HttpURLConnection) urlStr.openConnection();
int responseCode = con.getResponseCode();
if (responseCode == 200) {
InputStream inputStream = con.getInputStream();
int max = con.getContentLength();
saveFile(inputStream, path, max);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
//retrofit下载
private void retrofit(final String path) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MyServer.Url)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
MyServer myServer = retrofit.create(MyServer.class);
Observable
download.subscribeOn(Schedulers.io())
.subscribe(new Observer
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody responseBody) {
long max = responseBody.contentLength();
InputStream inputStream = responseBody.byteStream();
saveFile(inputStream, path, max);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
@Override
public void onComplete() {
}
});
}
//OkHttp下载
private void ok(final String path) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
Request request = new Request.Builder()
.url(url)
.get()
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody body = response.body();
InputStream inputStream = body.byteStream();
long max = body.contentLength();
//文件下载保存
saveFile(inputStream, path, max);
}
});
}
//保存文件
private void saveFile(InputStream inputStream, final String path, long max) {
try {
FileOutputStream fos = new FileOutputStream(new File(path));
long count = 0;
int length = -1;
byte[] bys = new byte[1024 * 10];
while ((length = inputStream.read(bys)) != -1) {
fos.write(bys, 0, length);
count += length;
Log.e(TAG, "count: " + count + ", max:" + max);
//进度条和视频播放SurfaceView可以直接在子线程中刷新
pb.setMax((int) max);
pb.setProgress((int) count);
}
inputStream.close();
fos.close();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "下载完毕", Toast.LENGTH_SHORT).show();
//apk安装处理
mPath = path;
InstallUtil.installApk(MainActivity.this, path);
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 8.0安装处理 下载完自动安装
*/
private String mPath = null;
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == InstallUtil.UNKNOWN_CODE) {
InstallUtil.installApk(MainActivity.this, mPath);//再次执行安装流程,包含权限判等
}
}
}
//自动安装工具类
public class InstallUtil {
public static final int UNKNOWN_CODE = 2019;
public static void installApk(Context context, String path) {
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
startInstallO(context,path);
}else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
startInstallN(context,path);
}else {
startInstall(context,path);
}
}
/**
*android1.x-6.x
*@param path 文件的路径
*/
private static void startInstall(Context context, String path) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
}
/**
* android7.x
* @param path 文件路径
*
* 清单文件配置
* * android:authorities="com.baidu.download.provider" * android:name="android.support.v4.content.FileProvider" * android:exported="false" * android:grantUriPermissions="true"> * * android:name="android.support.FILE_PROVIDER_PATHS" * android:resource="@xml/file_paths"/> *
*
*
*
*
*
*/
@RequiresApi(api = Build.VERSION_CODES.N)
private static void startInstallN(Context context, String path) {
//参数1 上下文, 参数2 在AndroidManifest中的android:authorities值, 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(context, "com.baidu.download.provider", new File(path));
Intent install = new Intent(Intent.ACTION_VIEW);
//由于没有在Activity环境下启动Activity,设置下面的标签
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(install);
}
/**
* android8.x
*
*
*
* 调起未知应用来源
* 回调处理:
*
* private String mPath = null;
* @Override
* protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
* super.onActivityResult(requestCode, resultCode, data);
* if (resultCode == RESULT_OK && requestCode == InstallUtil.UNKNOWN_CODE) {
* InstallUtil.installApk(MainActivity.this,mPath);//再次执行安装流程,包含权限判等
* }
* }
*
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private static void startInstallO(final Context context, String path) {
boolean isGranted = context.getPackageManager().canRequestPackageInstalls();
if (isGranted) startInstallN(context,path);//安装应用的逻辑(写自己的就可以)
else new AlertDialog.Builder(context)
.setCancelable(false)
.setTitle("安装应用需要打开未知来源权限,请去设置中开启权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int w) {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
Activity act = (Activity) context;
act.startActivityForResult(intent, UNKNOWN_CODE);
}
})
.show();
}
}