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函数代码处的第二个参数一致。
评论