Android网络资源下载时断点续传

2024-05-14 19:48

本文主要是介绍Android网络资源下载时断点续传,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自http://blog.csdn.net/sodino/article/details/6535278

断点续传用到的知识点:
1.使用RandomAccessFile设定文件大小并于指定位置开始读数据[randomAccessFile.seek(position)]。   
2.请求资源链接时指定所请求数据的返回范围。
    httpURLConnection.setRequestProperty("Range", "bytes=" + start + "-" + (contentLength - 1));

 

效果图如下[CSDN]:

下载gif

(相当抱歉,这个动画的时间太长了)

以下代码中的NetworkTool为通过个人编程经验封装好的网络工具类,强力推荐,当然也欢迎拍砖。
使用NetworkTool访问一个网络链接并获取数据的小示例为:

[java] view plaincopy
  1. HttpURLConnection httpConn = NetworkTool.openUrl(context, url);  
  2. int respondCode = NetworkTool.connect(httpConn);  
  3. if (respondCode == HttpURLConnection.HTTP_OK) {  
  4. byte[] data = NetworkTool.fetchData_doClose(httpConn);  
  5. String content = new String(data);  
  6. data = null;  
  7. // parse content  
  8. else {  
  9. // handles something  
  10. }  
  11. NetworkTool.disconnect(httpConn);  

代码中的DontPressWithParentButton可用于ListView中,当点击该Button时不会触发ListView中的OnItemClickListener。实现方法为重写Button的setPressed(boolean)方法:

[java] view plaincopy
  1. @Override  
  2. public void setPressed(boolean pressed) {  
  3.     if (pressed && ((View) getParent()).isPressed()) {  
  4.         return;  
  5.     }  
  6.     super.setPressed(pressed);  
  7. }  

 

代码如下:
lab.sodino.downloadbreak.ActDownload.java

[java] view plaincopy
  1. package lab.sodino.downloadbreak;  
  2. import java.io.File;  
  3. import java.text.DecimalFormat;  
  4. import lab.sodino.downloadbreak.bean.BeanDownload;  
  5. import lab.sodino.downloadbreak.util.LogOut;  
  6. import lab.sodino.downloadbreak.util.NetworkTool;  
  7. import android.app.Activity;  
  8. import android.content.Intent;  
  9. import android.net.Uri;  
  10. import android.os.Bundle;  
  11. import android.os.Handler;  
  12. import android.os.Message;  
  13. import android.view.View;  
  14. import android.widget.Button;  
  15. import android.widget.ProgressBar;  
  16. import android.widget.TextView;  
  17. public class ActDownload extends Activity {  
  18.     /** 下载存放地:"/sdcard/sodino/"。 */  
  19.     public static final String RES_LOAD_FOLDER = File.separator + "sdcard" + File.separator  
  20.             + "sodino" + File.separator;  
  21.     /** 刷新进度。 */  
  22.     public static final int REFRESH = 1;  
  23.     public static final int CODE = 10;  
  24.     private BeanDownload bean;  
  25.     private TextView txtName;  
  26.     private TextView txtProgress;  
  27.     private TextView txtSize;  
  28.     private ProgressBar progressBar;  
  29.     private Button btnAction;  
  30.     private Handler handler;  
  31.     private BtnListener btnListener;  
  32.     public void onCreate(Bundle savedInstanceState) {  
  33.         super.onCreate(savedInstanceState);  
  34.         setContentView(R.layout.l_download);  
  35.         initBeanDownload();  
  36.         initViews$Handler();  
  37.     }  
  38.     private void initBeanDownload() {  
  39.         bean = new BeanDownload();  
  40.         bean.name = "微信.apk";  
  41.         // 请找个可以无需跳转直接下载的地址  
  42.         bean.url = "http://XXOO.com/weixin20android16.apk";  
  43.         bean.state = BeanDownload.STATE_INTERRUPTED;  
  44.         bean.size = bean.loadedSize = 0l;  
  45.         bean.enable = true;  
  46.     }  
  47.     private void initViews$Handler() {  
  48.         txtName = (TextView) findViewById(R.id.txtName);  
  49.         txtName.setText(bean.name);  
  50.         txtProgress = (TextView) findViewById(R.id.txtProgress);  
  51.         txtProgress.setText(getProgressTxt(bean));  
  52.         txtSize = (TextView) findViewById(R.id.txtSize);  
  53.         txtSize.setText(formatSizeTxt(bean.size));  
  54.         progressBar = (ProgressBar) findViewById(R.id.progressBar);  
  55.         progressBar.setProgress(getProgressInt(bean, progressBar.getMax()));  
  56.         btnListener = new BtnListener();  
  57.         btnAction = (Button) findViewById(R.id.btnAction);  
  58.         btnAction.setOnClickListener(btnListener);  
  59.         btnAction.setText(getTxt(bean));  
  60.         btnAction.setEnabled(isEnable(bean));  
  61.         // handler  
  62.         handler = new Handler() {  
  63.             public void handleMessage(Message msg) {  
  64.                 txtProgress.setText(getProgressTxt(bean));  
  65.                 txtSize.setText(formatSizeTxt(bean.size));  
  66.                 progressBar.setProgress(getProgressInt(bean, progressBar.getMax()));  
  67.                 btnAction.setText(getTxt(bean));  
  68.                 btnAction.setEnabled(isEnable(bean));  
  69.             }  
  70.         };  
  71.     }  
  72.     private void pauseDownload() {  
  73.         bean.enable = false;  
  74.         handler.sendEmptyMessage(REFRESH);  
  75.     }  
  76.     private void doDownload() {  
  77.         handler.sendEmptyMessage(REFRESH);  
  78.         new DownloadThread().start();  
  79.     }  
  80.     private void reloadDownload() {  
  81.         bean.size = bean.loadedSize = 0;  
  82.         bean.enable = true;  
  83.         doDownload();  
  84.     }  
  85.     private void installDownload() {  
  86.         Intent intent = new Intent(Intent.ACTION_VIEW);  
  87.         String filePath = RES_LOAD_FOLDER + bean.name;  
  88.         intent.setDataAndType(Uri.parse("file://" + filePath),  
  89.                 "application/vnd.android.package-archive");  
  90.         // 如果仅是简单的startActivity(intent),会造成onCreate()再执行一次。  
  91.         ActDownload.this.startActivityForResult(intent, CODE);  
  92.     }  
  93.     class BtnListener implements Button.OnClickListener {  
  94.         public void onClick(View v) {  
  95.             LogOut.out(this"state:" + bean.state);  
  96.             switch (bean.state) {  
  97.             case BeanDownload.STATE_LOADING:  
  98.                 // 点击了"暂停"  
  99.                 pauseDownload();  
  100.                 break;  
  101.             case BeanDownload.STATE_INTERRUPTED:  
  102.                 // 点击了"继续"  
  103.                 doDownload();  
  104.                 break;  
  105.             case BeanDownload.STATE_DOWNLOAD_FAIL:  
  106.                 // 点击了"重载"  
  107.                 reloadDownload();  
  108.                 break;  
  109.             case BeanDownload.STATE_COMPLETED:  
  110.                 // 点击了"安装"  
  111.                 installDownload();  
  112.                 break;  
  113.             }  
  114.         }  
  115.     }  
  116.     class DownloadThread extends Thread {  
  117.         public void run() {  
  118.             bean.state = BeanDownload.STATE_LOADING;  
  119.             bean.enable = true;  
  120.             NetworkTool.download2File(ActDownload.this, bean, handler);  
  121.             LogOut.out(this"size:" + bean.size + " loaded:" + bean.loadedSize + " enable:"  
  122.                     + bean.enable);  
  123.             // 测试“重载”请释放下面代码的注释然后等待下载正常结束  
  124.             // bean.loadedSize = 0;  
  125.             if (bean.size > 0 && bean.loadedSize == bean.size) {  
  126.                 String localPath = RES_LOAD_FOLDER + bean.name;  
  127.                 File tmpFile = new File(localPath + ".tmp");  
  128.                 tmpFile.renameTo(new File(localPath));  
  129.                 bean.enable = false;  
  130.                 bean.state = BeanDownload.STATE_COMPLETED;  
  131.             } else {  
  132.                 if (bean.enable == false) {  
  133.                     bean.state = BeanDownload.STATE_INTERRUPTED;  
  134.                 } else {  
  135.                     bean.state = BeanDownload.STATE_DOWNLOAD_FAIL;  
  136.                 }  
  137.             }  
  138.             LogOut.out(this"state=" + bean.state);  
  139.             handler.sendEmptyMessage(REFRESH);  
  140.         }  
  141.     }  
  142.     public static String getProgressTxt(BeanDownload bean) {  
  143.         String resStr = "0%";  
  144.         if (bean.size != 0) {  
  145.             double result = bean.loadedSize * 1.0 / bean.size;  
  146.             DecimalFormat decFormat = new DecimalFormat("#.#%");  
  147.             resStr = decFormat.format(result);  
  148.         }  
  149.         return resStr;  
  150.     }  
  151.     private String formatSizeTxt(long size) {  
  152.         String sizeTxt = "未知";  
  153.         if (size > 0) {  
  154.             size = size >> 10;  
  155.             sizeTxt = String.valueOf(size) + "k";  
  156.         }  
  157.         return sizeTxt;  
  158.     }  
  159.     public static int getProgressInt(BeanDownload bean, int max) {  
  160.         int result = (bean.size > 0) ? (int) (bean.loadedSize * max * 1.0 / bean.size) : 0;  
  161.         return result;  
  162.     }  
  163.     private String getTxt(BeanDownload bean) {  
  164.         String txt = "安装";  
  165.         switch (bean.state) {  
  166.         case BeanDownload.STATE_COMPLETED:  
  167.             txt = "安装";  
  168.             break;  
  169.         case BeanDownload.STATE_LOADING:  
  170.             txt = "暂停";  
  171.             break;  
  172.         case BeanDownload.STATE_INTERRUPTED:  
  173.             txt = "继续";  
  174.             break;  
  175.         case BeanDownload.STATE_DOWNLOAD_FAIL:  
  176.             txt = "重载";  
  177.             break;  
  178.         }  
  179.         return txt;  
  180.     }  
  181.     private boolean isEnable(BeanDownload bean) {  
  182.         boolean enable = true;  
  183.         if (bean.enable == false && bean.state == BeanDownload.STATE_LOADING) {  
  184.             enable = false;  
  185.         }  
  186.         return enable;  
  187.     }  
  188. }  


lab.sodino.downloadbreak.bean.BeanDownload.java

[java] view plaincopy
  1. package lab.sodino.downloadbreak.bean;  
  2. /** 
  3.  * @author Sodino E-mail:sodinoopen@hotmail.com 
  4.  * @version Time:2011-6-8 下午11:33:10 
  5.  */  
  6. public class BeanDownload {  
  7.     /** 正在下载数据。Button应显示“暂停”。 */  
  8.     public static final int STATE_LOADING = 0;  
  9.     /** 数据全部下载完成。Button应显示“安装”。 */  
  10.     public static final int STATE_COMPLETED = 1;  
  11.     /** 数据下载过程中被暂停。Button应显示“继续”。 */  
  12.     public static final int STATE_INTERRUPTED = 2;  
  13.     /** 下载安装包失败。Button应显示“失败”。 */  
  14.     public static final int STATE_DOWNLOAD_FAIL = 3;  
  15.     public String name;  
  16.     public long size;  
  17.     public long loadedSize;  
  18.     public String url;  
  19.     public int state;  
  20.     public boolean enable;  
  21. }  

 

lab.sodino.downloadbreak.ui.DontPressWithParentButton.java

[java] view plaincopy
  1. package lab.sodino.downloadbreak.ui;  
  2. import android.content.Context;  
  3. import android.util.AttributeSet;  
  4. import android.view.View;  
  5. import android.widget.Button;  
  6. /** 
  7.  * @author Sodino E-mail:sodinoopen@hotmail.com 
  8.  * @version Time:2011-6-5 下午08:37:27 
  9.  */  
  10. public class DontPressWithParentButton extends Button {  
  11.     public DontPressWithParentButton(Context context, AttributeSet attrs) {  
  12.         super(context, attrs);  
  13.     }  
  14.     @Override  
  15.     public void setPressed(boolean pressed) {  
  16.         if (pressed && ((View) getParent()).isPressed()) {  
  17.             return;  
  18.         }  
  19.         super.setPressed(pressed);  
  20.     }  
  21. }  


lab.sodino.downloadbreak.util.NetworkTool.java

[java] view plaincopy
  1. package lab.sodino.downloadbreak.util;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.RandomAccessFile;  
  8. import java.net.HttpURLConnection;  
  9. import java.net.InetSocketAddress;  
  10. import java.net.MalformedURLException;  
  11. import java.net.URL;  
  12. import lab.sodino.downloadbreak.ActDownload;  
  13. import lab.sodino.downloadbreak.bean.BeanDownload;  
  14. import android.content.Context;  
  15. import android.net.ConnectivityManager;  
  16. import android.net.NetworkInfo;  
  17. import android.os.Handler;  
  18. /** 
  19.  * 管理联网操作,包括管理url参数、下载APK包、获取任务字符串。<br/> 
  20.  *  
  21.  * @author Sodino E-mail:sodinoopen@hotmail.com 
  22.  * @version Time:2011-4-6 下午03:42:50 
  23.  */  
  24. public class NetworkTool {  
  25.     /** 
  26.      * 开启一个HTTP链接。 
  27.      */  
  28.     public static HttpURLConnection openUrl(Context context, String urlStr) {  
  29.         LogOut.out("Network""urlStr[" + urlStr + "]");  
  30.         URL urlURL = null;  
  31.         HttpURLConnection httpConn = null;  
  32.         try {  
  33.             urlURL = new URL(urlStr);  
  34.             // 需要android.permission.ACCESS_NETWORK_STATE  
  35.             // 在没有网络的情况下,返回值为null。  
  36.             NetworkInfo networkInfo = ((ConnectivityManager) context  
  37.                     .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();  
  38.             // 如果是使用的运营商网络  
  39.             if (networkInfo != null) {  
  40.                 if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {  
  41.                     // 获取默认代理主机ip  
  42.                     String host = android.net.Proxy.getDefaultHost();  
  43.                     // 获取端口  
  44.                     int port = android.net.Proxy.getDefaultPort();  
  45.                     if (host != null && port != -1) {  
  46.                         // 封装代理連接主机IP与端口号。  
  47.                         InetSocketAddress inetAddress = new InetSocketAddress(host, port);  
  48.                         // 根据URL链接获取代理类型,本链接适用于TYPE.HTTP  
  49.                         java.net.Proxy.Type proxyType = java.net.Proxy.Type.valueOf(urlURL  
  50.                                 .getProtocol().toUpperCase());  
  51.                         java.net.Proxy javaProxy = new java.net.Proxy(proxyType, inetAddress);  
  52.                         httpConn = (HttpURLConnection) urlURL.openConnection(javaProxy);  
  53.                     } else {  
  54.                         httpConn = (HttpURLConnection) urlURL.openConnection();  
  55.                     }  
  56.                 } else {  
  57.                     httpConn = (HttpURLConnection) urlURL.openConnection();  
  58.                 }  
  59.                 httpConn.setDoInput(true);  
  60.             } else {  
  61.                 // LogOut.out(this, "No Avaiable Network");  
  62.             }  
  63.         } catch (NullPointerException npe) {  
  64.             npe.printStackTrace();  
  65.         } catch (MalformedURLException e) {  
  66.             e.printStackTrace();  
  67.         } catch (IOException e) {  
  68.             e.printStackTrace();  
  69.         }  
  70.         return httpConn;  
  71.     }  
  72.     /** 启动链接并将RespondCode值返回。 */  
  73.     public static int connect(HttpURLConnection httpConn) {  
  74.         int code = -1;  
  75.         if (httpConn != null) {  
  76.             try {  
  77.                 httpConn.connect();  
  78.                 code = httpConn.getResponseCode();  
  79.             } catch (IOException e) {  
  80.                 e.printStackTrace();  
  81.             }  
  82.         }  
  83.         LogOut.out("NetworkTool""respond_code=" + code);  
  84.         return code;  
  85.     }  
  86.     /** 
  87.      * 将指定的HTTP链接内容存储到指定的的文件中。<br/> 
  88.      * 返回值仅当参考。<br/> 
  89.      *  
  90.      * @param httpConn 
  91.      * @param filePath 
  92.      *            指定存储的文件路径。 
  93.      */  
  94.     public static boolean download2File(HttpURLConnection httpConn, String filePath) {  
  95.         boolean result = true;  
  96.         File file = new File(filePath);  
  97.         FileOutputStream fos = null;  
  98.         byte[] data = new byte[1024];  
  99.         int readLength = -1;  
  100.         InputStream is = null;  
  101.         try {  
  102.             fos = new FileOutputStream(file);  
  103.             is = httpConn.getInputStream();  
  104.             while ((readLength = is.read(data)) != -1) {  
  105.                 fos.write(data, 0, readLength);  
  106.                 fos.flush();  
  107.             }  
  108.             fos.flush();  
  109.         } catch (IOException ie) {  
  110.             result = false;  
  111.             ie.printStackTrace();  
  112.         } finally {  
  113.             try {  
  114.                 if (is != null) {  
  115.                     is.close();  
  116.                 }  
  117.                 if (fos != null) {  
  118.                     fos.close();  
  119.                 }  
  120.             } catch (IOException ie) {  
  121.                 ie.printStackTrace();  
  122.             }  
  123.         }  
  124.         return result;  
  125.     }  
  126.     /** 
  127.      * 将bean资源下载。<br/> 
  128.      * 支持断点续传。 
  129.      *  
  130.      */  
  131.     public static void download2File(Context context, BeanDownload bean, Handler handler) {  
  132.         String filePath = ActDownload.RES_LOAD_FOLDER + bean.name + ".tmp";  
  133.         HttpURLConnection httpConn = null;  
  134.         File file = new File(filePath);  
  135.         RandomAccessFile randomFile = null;  
  136.         FileOutputStream fos = null;  
  137.         int dataBlockLength = 2048;  
  138.         byte[] data = new byte[dataBlockLength];  
  139.         int readLength = -1;  
  140.         InputStream is = null;  
  141.         try {  
  142.             if (bean.size <= 0) {  
  143.                 bean.loadedSize = 0;  
  144.                 if (file.getParentFile().exists() == false) {  
  145.                     file.getParentFile().mkdirs();  
  146.                 }  
  147.                 if (file.exists() == false) {  
  148.                     file.createNewFile();  
  149.                 }  
  150.                 // 采用普通的下载方式  
  151.                 fos = new FileOutputStream(file);  
  152.                 httpConn = openUrl(context, bean.url);  
  153.                 int respondCode = connect(httpConn);  
  154.                 LogOut.out("NetworkTool""respondCode=" + respondCode);  
  155.                 if (respondCode == HttpURLConnection.HTTP_OK) {  
  156.                     bean.size = httpConn.getContentLength();  
  157.                     is = httpConn.getInputStream();  
  158.                     while ((readLength = is.read(data)) != -1 && bean.enable) {  
  159.                         fos.write(data, 0, readLength);  
  160.                         bean.loadedSize += readLength;  
  161.                         handler.sendEmptyMessage(ActDownload.REFRESH);  
  162.                     }  
  163.                 }  
  164.             } else {  
  165.                 // 采用断点续传方式  
  166.                 randomFile = new RandomAccessFile(file, "rw");  
  167.                 randomFile.setLength(bean.size);  
  168.                 httpConn = openUrl(context, bean.url);  
  169.                 httpConn.setRequestProperty("Range""bytes=" + bean.loadedSize + "-"  
  170.                         + (bean.size - 1));  
  171.                 int respondCode = connect(httpConn);  
  172.                 if (respondCode == HttpURLConnection.HTTP_PARTIAL) {  
  173.                     is = httpConn.getInputStream();  
  174.                     while ((readLength = is.read(data)) != -1 && bean.enable) {  
  175.                         randomFile.seek(bean.loadedSize);  
  176.                         randomFile.write(data, 0, readLength);  
  177.                         bean.loadedSize += readLength;  
  178.                         handler.sendEmptyMessage(ActDownload.REFRESH);  
  179.                     }  
  180.                 }  
  181.             }  
  182.         } catch (Exception e) {  
  183.             e.printStackTrace();  
  184.         } finally {  
  185.             try {  
  186.                 if (is != null) {  
  187.                     is.close();  
  188.                 }  
  189.                 if (httpConn != null) {  
  190.                     disconnect(httpConn);  
  191.                 }  
  192.                 if (fos != null) {  
  193.                     fos.close();  
  194.                 }  
  195.                 if (randomFile != null) {  
  196.                     randomFile.close();  
  197.                 }  
  198.             } catch (Exception e) {  
  199.                 e.printStackTrace();  
  200.             }  
  201.         }  
  202.     }  
  203.     /** 读取HttpURLConnection的数据并关闭相关流。 */  
  204.     public static byte[] fetchData_doClose(HttpURLConnection httpConn) {  
  205.         byte[] data = null;  
  206.         ByteArrayOutputStream baos = null;  
  207.         InputStream is = null;  
  208.         int read = -1;  
  209.         try {  
  210.             baos = new ByteArrayOutputStream();  
  211.             is = httpConn.getInputStream();  
  212.             while ((read = is.read()) != -1) {  
  213.                 baos.write(read);  
  214.             }  
  215.             data = baos.toByteArray();  
  216.         } catch (IOException ie) {  
  217.             ie.printStackTrace();  
  218.         } finally {  
  219.             try {  
  220.                 if (is != null) {  
  221.                     is.close();  
  222.                 }  
  223.                 if (baos != null) {  
  224.                     baos.close();  
  225.                 }  
  226.                 if (httpConn != null) {  
  227.                     httpConn.disconnect();  
  228.                 }  
  229.             } catch (IOException ie) {  
  230.                 ie.printStackTrace();  
  231.             }  
  232.         }  
  233.         return data;  
  234.     }  
  235.     public static void disconnect(HttpURLConnection httpConn) {  
  236.         if (httpConn != null) {  
  237.             httpConn.disconnect();  
  238.         }  
  239.     }  
  240. }  


/res/drawable/l_download.xml

[xhtml] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="horizontal"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="wrap_content"  
  6.     android:layout_marginTop="20dip"  
  7.     android:layout_marginBottom="0dip">  
  8.     <LinearLayout android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:orientation="vertical"  
  11.         android:layout_weight="1"  
  12.         android:layout_marginLeft="10dip"  
  13.         android:layout_marginRight="10dip">  
  14.         <LinearLayout android:layout_width="fill_parent"  
  15.             android:layout_height="wrap_content"  
  16.             android:layout_marginTop="10dip"  
  17.             android:layout_marginBottom="10dip"  
  18.             android:orientation="horizontal">  
  19.             <TextView android:layout_width="wrap_content"  
  20.                 android:layout_height="wrap_content"  
  21.                 android:layout_weight="1"  
  22.                 android:id="@+id/txtName"  
  23.                 android:singleLine="true"  
  24.                 android:ellipsize="middle"  
  25.                 android:textColor="#ffffffff"  
  26.                 android:textSize="15sp"  
  27.             ></TextView>  
  28.             <TextView android:layout_width="wrap_content"  
  29.                 android:layout_height="wrap_content"  
  30.                 android:id="@+id/txtProgress"  
  31.                 android:textColor="#ffffffff"  
  32.                 android:textSize="10sp"  
  33.                 android:layout_marginRight="10dip"  
  34.             ></TextView>  
  35.             <TextView android:layout_width="wrap_content"  
  36.                 android:layout_height="wrap_content"  
  37.                 android:id="@+id/txtSize"  
  38.                 android:textColor="#ffffffff"  
  39.                 android:textSize="10sp"  
  40.             ></TextView>  
  41.         </LinearLayout>  
  42.         <ProgressBar android:layout_width="fill_parent"  
  43.             android:layout_height="wrap_content"  
  44.             android:id="@+id/progressBar"  
  45.             style="?android:attr/progressBarStyleHorizontal" mce_style="?android:attr/progressBarStyleHorizontal"  
  46.         ></ProgressBar>  
  47.     </LinearLayout>  
  48.     <lab.sodino.downloadbreak.ui.DontPressWithParentButton  
  49.         android:layout_width="wrap_content"  
  50.         android:layout_height="wrap_content"  
  51.         android:minWidth="60dip"  
  52.         android:minHeight="30dip"  
  53.         android:id="@+id/btnAction"  
  54.         android:textColor="#ff000000"  
  55.         android:textStyle="bold"  
  56.         android:layout_marginRight="5dip"  
  57.         android:layout_marginLeft="5dip"  
  58.         android:layout_marginTop="10dip"  
  59.         android:layout_marginBottom="10dip"  
  60.         android:focusable="false"  
  61.         android:focusableInTouchMode="false"  
  62.     ></lab.sodino.downloadbreak.ui.DontPressWithParentButton>  
  63. </LinearLayout>  

 

所要添加的权限:

[xhtml] view plaincopy
  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  3. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  

 

本文内容归CSDN博客博主Sodino 所有
转载请注明出处: http://blog.csdn.net/sodino/archive/2011/06/09/6535278.aspx

 

 

附:HTTP1.1 Range与Content-Range范例说明

    假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如4个部分,然后创建4个线程,每个线程负责下载一个部分,如果文件大小为403个byte,那么你的分割方式可以为:0-99 (前100个字节),100-199(第二个100字节),200-299(第三个100字节),300-402(最后103个字节)。

    分割完成,每个线程都明白自己的任务,比如线程3的任务是负责下载200-299这部分文件,现在的问题是:线程3发送一个什么样的请求报文,才能够保证只请求文件的200-299字节,而不会干扰其他线程的任务。这时,我们可以使用HTTP1.1的Range头。Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的:
    表示头500个字节:Range: bytes=0-499
    表示第二个500字节:Range: bytes=500-999
    表示最后500个字节:Range: bytes=-500
    表示500字节以后的范围:Range: bytes=500-
    第一个和最后一个字节:Range: bytes=0-0,-1
    同时指定几个范围:Range: bytes=500-600,601-999
    所以,线程3发送的请求报文必须有这一行:
    Range: bytes=200-299

    服务器接收到线程3的请求报文,发现这是一个带有Range头的GET请求,如果一切正常,服务器的响应报文会有下面这行:
    HTTP/1.1 206 OK
    表示处理请求成功,响应报文还有这一行:
    Content-Range: bytes 200-299/403
    斜杠后面的403表示文件的大小,通常Content-Range的用法为:
    . The first 500 bytes:
     Content-Range: bytes 0-499/1234
    . The second 500 bytes:
     Content-Range: bytes 500-999/1234
    . All except for the first 500 bytes:
     Content-Range: bytes 500-1233/1234
    . The last 500 bytes:
     Content-Range: bytes 734-1233/1234


这篇关于Android网络资源下载时断点续传的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/989689

相关文章

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

2. 下载rknn-toolkit2项目

官网链接: https://github.com/airockchip/rknn-toolkit2 安装好git:[[1. Git的安装]] 下载项目: git clone https://github.com/airockchip/rknn-toolkit2.git 或者直接去github下载压缩文件,解压即可。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR