Android多线程实现文件断点下载
2018-07-20 来源:open-open
download_main_layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/down_load_edt" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:hint="请输入下载文件的网址!" /> <Button android:layout_marginTop="20dp" android:id="@+id/down_load_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="点击下载" /> <ProgressBar android:id="@+id/down_load_pbar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
下载入口Activity:
public class MainActivity extends Activity implements OnClickListener { /**下载文件按钮 */ private Button downLoadBtn; /**下载文件地址 */ private EditText downLoadEdt; /**下载进度 */ private ProgressBar downLoadPbar; /**定义发送消息的字段*/ private static final int MESSAGE_NUMBER = 1; /**所要下载文件总大小 */ private int fileSize; /**已下载大小 */ private int downLoadSize; /**所下载文件的保存路径 */ private String path; /**更新进度条的值 */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == MESSAGE_NUMBER) { /**设置进度*/ downLoadPbar.setProgress(Double.valueOf(downLoadSize * 1.0 / fileSize * 100).intValue()); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.download_activity_main); findViews(); setListeners(); initdata(); } private void findViews() { downLoadEdt=(EditText) findViewById(R.id.down_load_edt); downLoadBtn = (Button) findViewById(R.id.down_load_btn); downLoadPbar = (ProgressBar) findViewById(R.id.down_load_pbar); } private void setListeners() { downLoadBtn.setOnClickListener(this); } private void initdata() { downLoadPbar.setVisibility(View.GONE); downLoadPbar.setMax(100); downLoadPbar.setProgress(0); } @Override public void onClick(View v) { /**获取SDcard */ path = Environment.getExternalStorageDirectory() + "/downloads/"; File file = new File(path); if (!file.exists()) { file.mkdir(); } /**下载操作 */ new Thread(new DownLoadTask()).start(); /**显示进度条 */ downLoadPbar.setVisibility(View.VISIBLE); } /**子线程,计算下载量,更新UI */ class DownLoadTask implements Runnable { /**线程块大小,每个线程的下载量 */ private int blockSize; /** 默认为5个线程 */ private int threadNum = 5; /** 下载后的文件名 */ private String fileName = "myDownLoad.zip"; @Override public void run() { /**数组保存线程对象,便于后面的每个线程下载量计算总和 */ DownLoadThread[] fileDownLoads = new DownLoadThread[threadNum]; /** 计算总大小 */ URL url; try { url = new URL(downLoadEdt.getText().toString().trim()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); /**计算下载量 */ fileSize = conn.getContentLength(); /** 计算每个线程的下载量 */ blockSize = fileSize / threadNum; /** 执行下载操作 */ for (int i = 0; i < threadNum; i++) { /** 每个线程的开始位置 */ int begin = i * blockSize; /** 每个线程的结束位置 */ int end = (i + 1) * blockSize - 1; DownLoadThread thread = new DownLoadThread(url, begin, end, path + fileName); thread.start(); fileDownLoads[i] = thread; } /** 更新UI */ boolean flag = false; while (!flag) { flag = true; for (int i = 0; i < threadNum; i++) { downLoadSize += fileDownLoads[i].getDownloadsize(); if (!fileDownLoads[i].isFinish()) { flag = false; } } MainActivity.this.handler.sendEmptyMessage(MESSAGE_NUMBER); Thread.sleep(1000); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 下载线程工具类: public class DownLoadThread extends Thread { /**文件年在Url*/ private URL url; /**文件下载开始位置*/ private int startPostion; /**文件下载结束位置*/ private int endPostion; /**文件下载当前位置*/ private int currentPostion; /**文件名*/ private String filename; /**缓冲输入流*/ private BufferedInputStream buffin; /**写入流,支持断点*/ private RandomAccessFile raf; /**缓冲大小*/ byte[] buffsize = new byte[1024]; /**已经下载大小*/ private int downloadsize; /**下载是否完成*/ private boolean isFinish; public int getDownloadsize() { return downloadsize; } public boolean isFinish() { return isFinish; } public DownLoadThread(URL url, int begin, int end, String filename) { super(); this.url = url; this.startPostion = begin; this.endPostion = end; this.filename = filename; } @Override public void run() { try { /** * 抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。通常,创建一个到 URL 的连接需要几个步骤: * openConnection() connect()对影响到远程资源连接的参数进行操作。 与资源交互;查询头字段和内容。 * 通过在 URL 上调用 openConnection 方法创建连接对象。 处理设置参数和一般请求属性。 使用 connect 方法建立到远程对象的实际连接。 远程对象变为可用。远程对象的头字段和内容变为可访问。 */ URLConnection conn = url.openConnection(); /**指定下载的范围*/ conn.setRequestProperty("Range", "bytes="+startPostion+"-"+endPostion); /**此URL将在一定的上下文环境中被检验,是否允许用户交互,比如弹出一个认证对话框。如果为 false,那么不允许用户交互。*/ conn.setAllowUserInteraction(true); /**做缓冲优化处理*/ buffin = new BufferedInputStream(conn.getInputStream()); /**写入本地文件*/ raf = new RandomAccessFile(new File(filename), "rw"); /**移动到新的位置*/ raf.seek(startPostion); while(currentPostion<endPostion){//如果当前下载没有结束 int size = buffin.read(buffsize, 0, 1024); /**已经读完*/ if(size==-1){ break; } raf.write(buffsize, 0, size); currentPostion+=size; /**下载量*/ downloadsize+=size; } isFinish = true; /**下载完成就要关闭输入流与写入流*/ buffin.close(); raf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } super.run(); } }
不要忘记在清单文件AndroidManifest.xml中设置相应权限:
<!-- 网络访问权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- sdcard权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点!
本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。
最新资讯
热门推荐