1、 先创建布局文件
<RelativeLayout
android:layout_below="@+id/headFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerInParent="true"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progressBar"
android:layout_marginTop="50dp"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/downInfo"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:text="正在下载..."
android:gravity="center"
android:layout_weight="1"
android:clickable="true" />
<LinearLayout/>
<RelativeLayout/>
2、 获得权限
在AndroidManifest.xml文件里添加外部存储的权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
对于android高版本,要动态获取权限:
public static void verifyStoragePermissions(android.app.Activity activity) {
try {
//检测是否有写的权限
int permission = android.support.v4.app.ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != android.content.pm.PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
android.support.v4.app.ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
在onCreate里调用该函数即可。
3、 下载文件代码
/**
* 开始下载
*/
public void down(){
//获取下载资源的路径
final String path = "http://www.wave12.com/bigfish/tmp/autoAcid.apk";
//开启一个线程进行下载
new Thread(){
public void run() {
try {
//构造URL地址
URL url=new URL(path);
//打开连接
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
//设置请求超时的时间
conn.setConnectTimeout(5000);
//设置请求方式
conn.setRequestMethod("GET");
//获取相应码
int code=conn.getResponseCode();
if (code==200) {//请求成功
//获取请求数据的长度
int length=conn.getContentLength();
//设置进度条的最大值
mProgressBar.setMax(length);
//在客户端创建一个跟服务器文件大小相同的临时文件
//String path =Environment.getExternalStorageDirectory().getPath();
File pathDir = getFilesDir();
File Folder = new File(getBaseContext().getFilesDir(), "download");
if (!Folder.exists())//判断文件夹是否存在,不存在则创建文件夹,已经存在则跳过
{
Folder.mkdir();//创建文件夹
}
String pathRet = pathDir.getAbsolutePath();
RandomAccessFile raf=new RandomAccessFile( Environment.getExternalStorageDirectory() + "/autoAcid.apk", "rwd");
//指定临时文件的长度
raf.setLength(length);
raf.close();
//假设3个线程去下载资源
//平均每一个线程要下载的文件的大小
int blockSize=length/threadCount;
for (int threadId = 1; threadId <= threadCount; threadId++) {
//当前线程下载数据的开始位置
int startIndex=blockSize*(threadId-1);
//当前线程下载数据的结束位置
int endIndex=blockSize*threadId-1;
//确定最后一个线程要下载数据的最大位置
if (threadId==threadCount) {
endIndex=length;
}
//显示下载数据的区间
System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex);
//开启下载的子线程
new DownloadThread(path, threadId, startIndex, endIndex).start();
//当前下载活动的线程数加1
activeThread++;
System.out.println("当前活动的线程数:"+activeThread);
}
}else{//请求失败
System.out.println("服务器异常,下载失败!");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("服务器异常,下载失败!");
}
};
}.start();
}
/**
* 下载文件的子线程 每一个文件都下载对应的数据
* @author YUANYUAN
*
*/
public class DownloadThread extends Thread{
private String path;
private int threadId;
private int startIndex;
private int endIndex;
/**
* 构造方法
* @param path 下载文件的路径
* @param threadId 下载文件的线程
* @param startIndex 下载文件开始的位置
* @param endIndex 下载文件结束的位置
*/
public DownloadThread(String path, int threadId, int startIndex,
int endIndex) {
this.path = path;
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
//构造URL地址
try {
File tempFile=new File("sdcard/"+threadId+".txt");
//检查记录是否存在,如果存在读取数据,设置真实下载开始的位置
if (tempFile.exists()) {
FileInputStream fis=new FileInputStream(tempFile);
byte[] temp=new byte[1024];
int length=fis.read(temp);
//读取到已经下载的位置
int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
//计算出已经下载的数据长度
int areadyDown=downloadNewIndex-startIndex;
//累加已经下载的数据量
curDownCount+=areadyDown;
//设置进度条已经下载的数据量
mProgressBar.setProgress(curDownCount);
//设置重新开始下载的开始位置
startIndex=downloadNewIndex;
fis.close();
//显示真实下载数据的区间
System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex);
}
URL url = new URL(path);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
//设置请求属性,请求部分资源
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
int code=conn.getResponseCode();
if (code==206) {//下载部分资源,正常返回的状态码为206
InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源
//构建随机访问文件
//String path =Environment.getExternalStorageDirectory().getPath();
File pathDir = getFilesDir();
String pathRet = pathDir.getAbsolutePath();
RandomAccessFile raf=new RandomAccessFile(Environment.getExternalStorageDirectory() + "/autoAcid.apk", "rwd");
//设置 每一个线程随机写文件开始的位置
raf.seek(startIndex);
//开始写文件
int len=0;
byte[] buffer=new byte[1024];
//该线程已经下载数据的长度
int total=0;
while((len=is.read(buffer))!=-1){//读取输入流
//记录当前线程已下载数据的长度
RandomAccessFile file=new RandomAccessFile("sdcard/"+threadId+".txt","rwd");
raf.write(buffer,0,len);//写文件
total+=len;//更新该线程已下载数据的总长度
System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex));
//将已下载数据的位置记录写入到文件
file.write((startIndex+total+"").getBytes());
//累加已经下载的数据量
curDownCount+=len;
//更新进度条【进度条的更新可以在非UI线程直接更新,具体见底层源代码】
mProgressBar.setProgress(curDownCount);
//更新下载进度
Message msg=Message.obtain();
msg.what=UPDATE_PROGRESS;
msg.obj = curDownCount;
handler.sendMessage(msg);
file.close();
}
is.close();
raf.close();
//提示下载完毕
System.out.println("线程【"+threadId+"】下载完毕");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("线程【"+threadId+"】下载出现异常!!");
}finally{
//活动的线程数减少
activeThread--;
if (activeThread==0) {
for (int i = 1; i <= threadCount; i++) {
File tempFile=new File("sdcard/"+i+".txt");
tempFile.delete();
}
System.out.println("下载完毕,已清除全部临时文件");
//界面消息提示下载完毕
Message msg=new Message();
msg.what=downloadOver;
handler.sendMessage(msg);
}
}
}
}
4、 下载完成后执行安装
//加入消息处理机制
private Handler handler;
{
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case downloadOver:
Toast.makeText(UpgradeActivity.this, "文件已下载完毕!", Toast.LENGTH_LONG).show();
mDownInfo.setText("下载完成");
Intent intent = new Intent(Intent.ACTION_VIEW);
//String path =Environment.getExternalStorageDirectory().getPath();
File pathDir = getFilesDir();
String pathRet = pathDir.getAbsolutePath();
String apkPath = Environment.getExternalStorageDirectory() + "/autoAcid.apk";
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
File file = (new File(apkPath));
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//参数1:上下文, 参数2:Provider主机地址 和配置文件中保持一致,参数3:共享的文件
Uri apkUri = FileProvider.getUriForFile(getApplicationContext(),
"com.wave12.autoacid.fileProvider", file);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(new File(apkPath)),
"application/vnd.android.package-archive");
}
startActivity(intent);
break;
case UPDATE_PROGRESS:
//更新进度显示
int curProgressValue = (int) (msg.obj);
int maxValue = mProgressBar.getMax();
int percent = (int) ((curProgressValue * 100.0) / maxValue);
mDownInfo.setText("当前进度:" + (curProgressValue * 100.0 / maxValue) + "%");
break;
default:
break;
}
}
};
}
对于高版本,要配置FileProvider,在 AndroidManifest.xml文件的application节内部添加
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.wave12.autoacid.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
<provider/>
com.wave12.autoacid是包名,要和handler里的getUriForFile函数代码处的第二个参数一致。





评论