下面是要实现的效果
。
这个demo,主要实现的功能有:多线程上传,断点续传, Notification的使用。多线程下载的主要原理是,对要下载的文件进行分割,每个线程取一个独立的区域进行下载。
URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); //startIndex和endIndex表示当前需要下载的文件的开始和结束的字节 conn.setRequestProperty("Range", "bytes="+startIndex+""+endIndex);
写入的时候是通过java的RandomAccessFile 类来获取写入的开始位置,获取了开始的位置后,由于已经对服务器的文件大小进行了分割,依次写入流文件即可。
对于单线程情况下的断点续传,一般情况下是通过计算已经下载的文件的大小,然后从末尾处选择开始下载。多线程情况下,感觉应该是对于每个线程下的位置进行记录,然后从记录的位置开始下载。
本文并没有从头到尾写一个这样的过程,android开源框架Xutils提供了这一整套的类库和方法,github地址是https://github.com/wyouflf/xUtils。使用该类库需要网络和读写SD卡的权限,
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
下面呈现核心的代码。布局文件只有一个按钮没什么好说的。首先初始化这样一些变量:
int id =1; private Button mButton; private NotificationManager mNotifyManager; NotificationCompat.Builder mBuilder ;
然后在onCreate方法中,对它们进行初始化。
mButton = (Button) findViewById(R.id.id_bt_startNotificationDownload); mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(this); mBuilder.setContentTitle("内容下载").setContentText("下载中,请骚等").setSmallIcon(R.drawable.notification);
//点击按钮,开始下载 mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { download("https://github.com/wyouflf/xCombine/archive/master.zip", "/sdcard/xCombine_master.zip"); } });
下面是使用Xutil的类库进行多线程下载的方法。
private void download(String url, String filePath){ HttpUtils httpUtils = new HttpUtils(); //可以设置线程池的大小,下载充实的次数,超时时间等等。 HttpHandler hanlder = httpUtils.configRequestThreadPoolSize(5).download(url, filePath, true, true, new RequestCallBack<File>() { @Override public void onSuccess(ResponseInfo<File> responseInfo) { //成功后将setProgress的两个变量设置为0,progress就会消失。setProgerss第三个参数的含义是,如果能确定进度条执行的时间,就传入true,否则是false,此处直接传入false即可。 mBuilder.setProgress(0, 0,false).setContentText("已经下载完成"); mNotifyManager.notify(id, mBuilder.build()); } @Override public void onFailure(HttpException e, String s) { //失败后执行的方法 Toast.makeText(MainActivity.this,"fali , try again",Toast.LENGTH_LONG).show(); } @Override public void onStart() { //开始时候,初始化进度条 mBuilder.setProgress(100, 0,false); mNotifyManager.notify(id, mBuilder.build()); } @Override public void onLoading(long total, long current, boolean isUploading) { //更新进度条 int currentNum = (int) (100*current/total); mBuilder.setProgress(100, currentNum,false); mNotifyManager.notify(id, mBuilder.build()); } }); }