• day05


    1使用httpurlconnection方式把数据提交到服务器
        基于什么协议?http
        get方式:组拼URL地址把数据拼到url上 有大小限制 1kb  4kb
        post方式: post方式提交安全  没有大小限制
        post方式和get方式区别:
            [1]路径不同
            [2]请求方式不同
            [3]post方式要自己组拼请求体的内容
                post方式比get方式多了2个头(content-length和content-type)

    get方式提交数据代码如下
    1. new Thread(){public void run() {
    2. try{
    3. //[2]获取用户名和密码
    4. String name = et_username.getText().toString().trim();
    5. String pwd = et_password.getText().toString().trim();
    6. //[2.1]定义get方式要提交的路径
    7. String path = "http://192.168.11.73:8000/login/loginServlet?username=" + name + "&password=" + pwd;
    8. //[2]
    9. URL url = new URL(path);
    10. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    11. conn.setRequestMethod("GET");
    12. conn.setConnectTimeout(5000);
    13. int code = conn.getResponseCode();
    14. if(code == 200){
    15. InputStream inputStream = conn.getInputStream();
    16. String content = StreamTools.readStream(inputStream);
    17. //把服务器的数据展示到Toast上
    18. showToast(content);
    19. }
    20. }
    21. catch(Exception e)
    22. {
    23. e.printStackTrace();
    24. }
    25. };}.start();

    post方式提交数据代码如下(主要☆☆☆☆☆处
    1. new Thread(){public void run() {
    2. try{
    3. //[2]获取用户名和密码
    4. String name = et_username.getText().toString().trim();
    5. String pwd = et_password.getText().toString().trim();
    6. //☆☆☆☆☆和get方式提交数据区别四:设置请求体
    7. //String data = "username=" + name + "&password=" + pwd;
    8. //[2.1]定义get方式要提交的路径
    9. //☆☆☆☆☆和get方式提交数据区别一:路径不同
    10. //String path = "http://192.168.11.73:8000/login/loginServlet";
    11. String path = "http://192.168.11.73:8000/login/loginServlet?username=" + name + "&password=" + pwd;
    12. //[2]
    13. URL url = new URL(path);
    14. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    15. //☆☆☆☆☆和get方式提交数据区别二:设置请求方式是post
    16. //conn.setRequestMethod("POST");
    17. conn.setRequestMethod("GET");
    18. conn.setConnectTimeout(5000);
    19. //☆☆☆☆☆和get方式提交数据区别三:多设置两个请求头信息
    20. //conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    21. //conn.setRequestProperty("Content-Length", data.length() + "");
    22. //☆☆☆☆☆和get方式提交数据区别五:向服务器提交数据
    23. //设置一个标记 允许输出
    24. //conn.setDoOutput(true);
    25. //conn.getOutputStream().write(data.getBytes());
    26. int code = conn.getResponseCode();
    27. if(code == 200){
    28. InputStream inputStream = conn.getInputStream();
    29. String content = StreamTools.readStream(inputStream);
    30. //把服务器的数据展示到Toast上
    31. showToast(content);
    32. }
    33. }
    34. catch(Exception e)
    35. {
    36. e.printStackTrace();
    37. }
    38. };}.start();



    2乱码问题解决

    3以httpclient方式把数据提交到服务器
        [1]开源项目
        [2]谷歌一般以 base default simple 进行命名
        [3]对http请求的封装

    get方式提交数据代码如下
    1. new Thread() {
    2. public void run() {
    3. try {
    4. // [2]获取用户名和密码
    5. String name = et_username.getText().toString().trim();
    6. String pwd = et_password.getText().toString().trim();
    7. name = URLEncoder.encode(name, "utf-8");
    8. pwd = URLEncoder.encode(pwd, "utf-8");
    9. String path = "http://192.168.11.73:8000/login/loginServlet?username="
    10. + name + "&password=" + pwd;
    11. // 获取httpclient实例
    12. DefaultHttpClient client = new DefaultHttpClient();
    13. // 准备get请求 定义一个httpget实现
    14. HttpGet get = new HttpGet(path);
    15. // 执行一个get请求
    16. HttpResponse response = client.execute(get);
    17. // 获取服务器返回的状态码
    18. int code = response.getStatusLine().getStatusCode();
    19. if (code == 200) {
    20. InputStream inputStream = response.getEntity()
    21. .getContent();
    22. String content = StreamTools.readStream(inputStream);
    23. showToast(content + "");
    24. }
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. }
    28. };
    29. }.start();
    post方式提交数据代码如下
    1. new Thread() {
    2. public void run() {
    3. try {
    4. // [2]获取用户名和密码
    5. String name = et_username.getText().toString().trim();
    6. String pwd = et_password.getText().toString().trim();
    7. // [3]以httpclient方式进行提交
    8. DefaultHttpClient client = new DefaultHttpClient();
    9. // [3.1]准备post请求
    10. String Path = "http://192.168.11.73:8080/login/LoginServlet";
    11. HttpPost post = new HttpPost(Path);
    12. //[3.1.0]准备parameters
    13. List<NameValuePair> lists = new ArrayList<NameValuePair>();
    14. //[3.1.1]准备NameValuePair 实际上就是我们要提交的用户名和密码
    15. BasicNameValuePair nameValuePair = new BasicNameValuePair("username", name);
    16. BasicNameValuePair pwdValuePair = new BasicNameValuePair("password", pwd);
    17. lists.add(nameValuePair);
    18. lists.add(pwdValuePair);
    19. //[3.1.2]准备entity
    20. UrlEncodedFormEntity entity = new UrlEncodedFormEntity(lists);
    21. post.setEntity(entity);
    22. HttpResponse response = client.execute(post);
    23. int code = response.getStatusLine().getStatusCode();
    24. if (code == 200) {
    25. InputStream inputStream = response.getEntity()
    26. .getContent();
    27. String content = StreamTools.readStream(inputStream);
    28. showToast(content + "");
    29. }
    30. } catch (Exception e) {
    31. e.printStackTrace();
    32. }
    33. };
    34. }.start();


    4开源项目方式把数据提交到服务器
    asynchttpclient
    get方式提交数据代码如下
    1. String name = et_username.getText().toString().trim();
    2. String pwd = et_password.getText().toString().trim();
    3. name = URLEncoder.encode(name, "utf-8");
    4. pwd = URLEncoder.encode(pwd, "utf-8");
    5. path = "http://192.168.11.73:8000/login/loginServlet?username=" + name
    6. + "&password=" + pwd;
    7. // [3]使用开源项目进行get请求
    8. // [3.1]创建asynchttpclient
    9. AsyncHttpClient client = new AsyncHttpClient();
    10. // [3.2]进行get请求
    11. client.get(path, new AsyncHttpResponseHandler() {
    12. //请求成功
    13. public void onSuccess(int statusCode, Header[] headers,
    14. byte[] responseBody) {
    15. Toast.makeText(getApplicationContext(), new String(responseBody,"gbk"), 1).show();
    16. }
    17. //请求失败
    18. public void onSuccess(int statusCode, Header[] headers,
    19. byte[] responseBody, Throwable error) {
    20. //Toast.makeText(getApplicationContext(), new String(responseBody,"gbk"), 1).show();
    21. }
    22. });

    post方式提交数据代码如下
    1. String name = et_username.getText().toString().trim();
    2. String pwd = et_password.getText().toString().trim();
    3. String Path = "http://192.168.11.73:8080/login/LoginServlet";
    4. //[3.1]创建asyncHttpClient
    5. AsyncHttpClient client = new AsyncHttpClient();
    6. //[3.1.0]准备请求体的内容
    7. RequestParams params = new RequestParams();
    8. params.put("username", name);
    9. params.put("password", pwd);
    10. //[3.2]进行post请求
    11. client.post(Path, params, new AsyncHttpResponseHandler() {
    12. //请求成功
    13. public void onSuccess(int statusCode, Header[] headers,
    14. byte[] responseBody) {
    15. Toast.makeText(getApplicationContext(), new String(responseBody,"gbk"), 1).show();
    16. }
    17. //请求失败
    18. public void onSuccess(int statusCode, Header[] headers,
    19. byte[] responseBody, Throwable error) {
    20. //Toast.makeText(getApplicationContext(), new String(responseBody,"gbk"), 1).show();
    21. }
    22. });

    总结:
        [1]    httpurlconnection
        [2]    httpclient    (了解 没人用)
        [3]    开源项目(asynchttpclient)

    5javase多线程下载
        设置请求服务器文件的位置
        conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);

    为什么多线程能加速下载?
        [1]不是说线程开的越多下载越快
        [2]还受服务器带宽的影响
        [3]获得更多的cup资源

     每个线程下载的计算公式
    1. package com.phone.download;
    2. import java.io.InputStream;
    3. import java.io.RandomAccessFile;
    4. import java.net.HttpURLConnection;
    5. import java.net.URL;
    6. public class MutiDownLoad {
    7. // 定义下载路径
    8. static String path = "http://192.168.11.73:8080/feiq.exe";
    9. private static final int threadCount = 3;//线程数
    10. public static void main(String[] args){
    11. //[2]获取服务器文件的大小
    12. try
    13. {
    14. URL url = new URL(path);
    15. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    16. conn.setRequestMethod("GET");
    17. conn.setReadTimeout(5000);
    18. int code = conn.getResponseCode();
    19. if(code == 200)
    20. {
    21. //[☆☆☆☆]一、获取服务器文件的大小 要计算每个线程下载的开始位置和结束位置
    22. int length = conn.getContentLength();
    23. //[☆☆☆☆]二、创建一个大小和服务器一模一样的文件 目的是提前把空间申请出来
    24. RandomAccessFile rafAccessFile = new RandomAccessFile("temp.exe", "rw");
    25. rafAccessFile.setLength(length);
    26. //算出每个线程下载的大小
    27. int blocksize = length / threadCount;
    28. //[☆☆☆☆]三、计算每个线程下载的开始位置和结束位置
    29. for(int i=0; i<threadCount; i++)
    30. {
    31. //每个线程下载的开始位置
    32. int startIndex = i*blocksize;
    33. //每个线程下载的结束位置
    34. int endIndex = (i+1)*blocksize - 1;
    35. if(i == threadCount - 1)
    36. {
    37. //说明是最后一个线程
    38. endIndex = length-1;
    39. }
    40. //[☆☆☆☆]四、开启线程去服务器下载文件
    41. DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
    42. downLoadThread.start();
    43. }
    44. }
    45. }
    46. catch(Exception e)
    47. {
    48. e.printStackTrace();
    49. }
    50. }
    51. //定义线程去服务器下载文件
    52. private static class DownLoadThread extends Thread
    53. {
    54. //通过构造方法把每个线程下载的开始位置和结束位置传递过来
    55. private int startIndex;
    56. private int endIndex;
    57. private int threadId;
    58. public DownLoadThread(int startIndex,int endIndex,int threadId){
    59. this.startIndex = startIndex;
    60. this.endIndex = endIndex;
    61. this.threadId = threadId;
    62. }
    63. public void run() {
    64. //四、开启线程去服务器下载文件
    65. try {
    66. URL url = new URL(path);
    67. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    68. conn.setRequestMethod("GET");
    69. conn.setConnectTimeout(5000);
    70. //设置一个请求头Range(作用告诉服务器每个线程下载的开始位置和结束位置)
    71. conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
    72. int code = conn.getResponseCode();
    73. //200代表获取服务器资源全部成功
    74. //206请求部分资源成功
    75. //if(code == 200)
    76. if(code == 206)
    77. {
    78. //[6]创建随机读写文件对象
    79. RandomAccessFile rafAccessFile = new RandomAccessFile("temp.exe", "rw");
    80. //[6]每个线程要从自己的位置开始写
    81. rafAccessFile.seek(startIndex);
    82. InputStream inputStream = conn.getInputStream();
    83. //[7]把数据写到文件中
    84. int len = -1;
    85. byte[] Buffer = new byte[1024];
    86. while((len = inputStream.read(Buffer))!=-1)
    87. {
    88. rafAccessFile.write(Buffer,0,len);
    89. }
    90. rafAccessFile.close();
    91. }
    92. } catch (Exception e) {
    93. e.printStackTrace();
    94. }
    95. }
    96. }
    97. }

    6断点续传实现
    1. package com.phone.download;
    2. import java.io.BufferedReader;
    3. import java.io.File;
    4. import java.io.FileInputStream;
    5. import java.io.FileOutputStream;
    6. import java.io.InputStream;
    7. import java.io.InputStreamReader;
    8. import java.io.RandomAccessFile;
    9. import java.net.HttpURLConnection;
    10. import java.net.URL;
    11. public class MutiDownLoad {
    12. // 定义下载路径
    13. static String path = "http://192.168.11.73:8080/feiq.exe";
    14. private static final int threadCount = 3;//线程数
    15. //代表当前正在运行的线程
    16. private static int runningThread;
    17. public static void main(String[] args){
    18. //[2]获取服务器文件的大小
    19. try
    20. {
    21. URL url = new URL(path);
    22. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    23. conn.setRequestMethod("GET");
    24. conn.setReadTimeout(5000);
    25. int code = conn.getResponseCode();
    26. if(code == 200)
    27. {
    28. //[☆☆☆☆]一、获取服务器文件的大小 要计算每个线程下载的开始位置和结束位置
    29. int length = conn.getContentLength();
    30. //把线程的数量赋值给正在运行的线程
    31. runningThread = threadCount;
    32. //[☆☆☆☆]二、创建一个大小和服务器一模一样的文件 目的是提前把空间申请出来
    33. RandomAccessFile rafAccessFile = new RandomAccessFile("temp.exe", "rw");
    34. rafAccessFile.setLength(length);
    35. //算出每个线程下载的大小
    36. int blocksize = length / threadCount;
    37. //[☆☆☆☆]三、计算每个线程下载的开始位置和结束位置
    38. for(int i=0; i<threadCount; i++)
    39. {
    40. //每个线程下载的开始位置
    41. int startIndex = i*blocksize;
    42. //每个线程下载的结束位置
    43. int endIndex = (i+1)*blocksize - 1;
    44. if(i == threadCount - 1)
    45. {
    46. //说明是最后一个线程
    47. endIndex = length-1;
    48. }
    49. //[☆☆☆☆]四、开启线程去服务器下载文件
    50. DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i);
    51. downLoadThread.start();
    52. }
    53. }
    54. }
    55. catch(Exception e)
    56. {
    57. e.printStackTrace();
    58. }
    59. }
    60. //定义线程去服务器下载文件
    61. private static class DownLoadThread extends Thread
    62. {
    63. //通过构造方法把每个线程下载的开始位置和结束位置传递过来
    64. private int startIndex;
    65. private int endIndex;
    66. private int threadId;
    67. public DownLoadThread(int startIndex,int endIndex,int threadId){
    68. this.startIndex = startIndex;
    69. this.endIndex = endIndex;
    70. this.threadId = threadId;
    71. }
    72. public void run() {
    73. //四、开启线程去服务器下载文件
    74. try {
    75. URL url = new URL(path);
    76. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    77. conn.setRequestMethod("GET");
    78. conn.setConnectTimeout(5000);
    79. //如果中间断过 继续上次的位置继续下载 从文件中读取上次下载的位置
    80. File file = new File(getFilename(path) + threadId + ".txt");
    81. if(file.exists() && file.length()>0)
    82. {
    83. FileInputStream fis = new FileInputStream(file);
    84. BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
    85. //读取出的内容就是上一次下载的位置
    86. String lastPositionn = bufr.readLine();
    87. int lastPosition = Integer.parseInt(lastPositionn);
    88. //改变startIndex位置
    89. startIndex = lastPosition;
    90. fis.close();
    91. }
    92. //设置一个请求头Range(作用告诉服务器每个线程下载的开始位置和结束位置)
    93. conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
    94. int code = conn.getResponseCode();
    95. //200代表获取服务器资源全部成功
    96. //206请求部分资源成功
    97. //if(code == 200)
    98. if(code == 206)
    99. {
    100. //[6]创建随机读写文件对象
    101. RandomAccessFile rafAccessFile = new RandomAccessFile(getFilename(path), "rw");
    102. //[6]每个线程要从自己的位置开始写
    103. rafAccessFile.seek(startIndex);
    104. InputStream inputStream = conn.getInputStream();
    105. //[7]把数据写到文件中
    106. int len = -1;
    107. byte[] Buffer = new byte[1024*1024];
    108. //代表当前线程下载的大小
    109. int total = 0;
    110. while((len = inputStream.read(Buffer))!=-1)
    111. {
    112. rafAccessFile.write(Buffer,0,len);
    113. total += len;
    114. //[8]实现断点续传 就是把当前线程下载的位置给存起来 下次再下载的时候按照上次下载的位置继续下载就可以了
    115. //存到一个普通的.txt文本中
    116. int currentThreadPosition = startIndex + total;
    117. //[9]用来存当前线程下载的位置
    118. RandomAccessFile raff = new RandomAccessFile(getFilename(path) + threadId + ".txt", "rwd");
    119. raff.write(String.valueOf(currentThreadPosition).getBytes());
    120. raff.close();
    1. /*
    2. * 用这种方法有时候可能存不成功,因为硬盘有个缓存区
    3. File file = new File(threadId + ".txt");
    4. FileOutputStream fos = new FileOutputStream(file);
    5. fos.write(String.valueOf(currentThreadPosition).getBytes());
    6. fos.close();
    7. */
    8. }
    9. rafAccessFile.close();
    10. synchronized(DownLoadThread.class){
    11. runningThread--;
    12. if(runningThread == 0)
    13. {
    14. //说明所有的线程都执行完毕了 就把.txt文件删除
    15. for(int i = 0; i < threadCount; i++)
    16. {
    17. File delFile = new File(getFilename(path) + i + ".txt");
    18. delFile.delete();
    19. }
    20. }
    21. }
    22. }
    23. } catch (Exception e) {
    24. e.printStackTrace();
    25. }
    26. }
    27. }
    28. /*
    29. * 获取文件的名字
    30. */
    31. public static String getFilename(String path){
    32. int start = path.lastIndexOf("/");
    33. return path.substring(start);
    34. }
    35. }

    7断点续传逻辑移植到Android上
    MainActivity.java
    1. package com.phone.download;
    2. import java.io.BufferedReader;
    3. import java.io.File;
    4. import java.io.FileInputStream;
    5. import java.io.InputStream;
    6. import java.io.InputStreamReader;
    7. import java.io.RandomAccessFile;
    8. import java.net.HttpURLConnection;
    9. import java.net.URL;
    10. import java.util.ArrayList;
    11. import java.util.List;
    12. import android.os.Bundle;
    13. import android.os.Environment;
    14. import android.support.v7.app.ActionBarActivity;
    15. import android.view.View;
    16. import android.widget.EditText;
    17. import android.widget.LinearLayout;
    18. import android.widget.ProgressBar;
    19. public class MainActivity extends ActionBarActivity {
    20. private EditText et_path;
    21. private String path;
    22. private EditText et_threadCount;
    23. private LinearLayout ll_pb_layout;
    24. // 代表当前正在运行的线程
    25. private static int runningThread;
    26. //用来存进度条的引用
    27. private List<ProgressBar> pbLists;
    28. @Override
    29. protected void onCreate(Bundle savedInstanceState) {
    30. super.onCreate(savedInstanceState);
    31. setContentView(R.layout.activity_main);
    32. // [1]获取控件
    33. et_path = (EditText) findViewById(R.id.et_path);
    34. et_threadCount = (EditText) findViewById(R.id.et_threadCount);
    35. ll_pb_layout = (LinearLayout) findViewById(R.id.ll_pb);
    36. pbLists = new ArrayList<ProgressBar>();
    37. }
    38. // 点击按钮实现下载的逻辑
    39. public void click(View v) {
    40. // 获取下载的路径
    41. path = et_path.getText().toString().trim();
    42. // [3]获取线程的数量
    43. String threadCountt = et_threadCount.getText().toString().trim();
    44. // [3.0]先移除进度条再添加
    45. ll_pb_layout.removeAllViews();
    46. final int threadCount = Integer.parseInt(threadCountt);
    47. pbLists.clear();
    48. for (int i = 0; i < threadCount; i++) {
    49. // [3.1]把我定义的item布局转换成一个View对象
    50. ProgressBar child = (ProgressBar) View.inflate(getApplicationContext(), R.layout.item,
    51. null);
    52. //把child添加到集合中
    53. pbLists.add(child);
    54. // [4]动态的添加进度条
    55. ll_pb_layout.addView(child);
    56. }
    57. // [5]开始移植
    58. new Thread() {
    59. public void run() {
    60. // [2]获取服务器文件的大小
    61. try {
    62. URL url = new URL(path);
    63. HttpURLConnection conn = (HttpURLConnection) url
    64. .openConnection();
    65. conn.setRequestMethod("GET");
    66. conn.setReadTimeout(5000);
    67. int code = conn.getResponseCode();
    68. if (code == 200) {
    69. // [☆☆☆☆]一、获取服务器文件的大小 要计算每个线程下载的开始位置和结束位置
    70. int length = conn.getContentLength();
    71. // 把线程的数量赋值给正在运行的线程
    72. runningThread = threadCount;
    73. // [☆☆☆☆]二、创建一个大小和服务器一模一样的文件 目的是提前把空间申请出来
    74. RandomAccessFile rafAccessFile = new RandomAccessFile(
    75. "temp.exe", "rw");
    76. rafAccessFile.setLength(length);
    77. // 算出每个线程下载的大小
    78. int blocksize = length / threadCount;
    79. // [☆☆☆☆]三、计算每个线程下载的开始位置和结束位置
    80. for (int i = 0; i < threadCount; i++) {
    81. // 每个线程下载的开始位置
    82. int startIndex = i * blocksize;
    83. // 每个线程下载的结束位置
    84. int endIndex = (i + 1) * blocksize - 1;
    85. if (i == threadCount - 1) {
    86. // 说明是最后一个线程
    87. endIndex = length - 1;
    88. }
    89. // [☆☆☆☆]四、开启线程去服务器下载文件
    90. DownLoadThread downLoadThread = new DownLoadThread(
    91. startIndex, endIndex, i);
    92. downLoadThread.start();
    93. }
    94. }
    95. } catch (Exception e) {
    96. e.printStackTrace();
    97. }
    98. };
    99. }.start();
    100. }
    101. // 定义线程去服务器下载文件
    102. private class DownLoadThread extends Thread {
    103. // 通过构造方法把每个线程下载的开始位置和结束位置传递过来
    104. private int startIndex;
    105. private int endIndex;
    106. private int threadId;
    107. //代表当前线程下载的最大值
    108. private int PbMaxSize;
    109. //如果中断过 获取上次下载的位置
    110. private int PbLastPosition;
    111. public DownLoadThread(int startIndex, int endIndex, int threadId) {
    112. this.startIndex = startIndex;
    113. this.endIndex = endIndex;
    114. this.threadId = threadId;
    115. }
    1. public void run() {
    2. // 四、开启线程去服务器下载文件
    3. try {
    4. //计算当前进度条的最大值
    5. PbMaxSize = endIndex - startIndex;
    6. URL url = new URL(path);
    7. HttpURLConnection conn = (HttpURLConnection) url
    8. .openConnection();
    9. conn.setRequestMethod("GET");
    10. conn.setConnectTimeout(5000);
    11. // 如果中间断过 继续上次的位置继续下载 从文件中读取上次下载的位置
    12. File file = new File(getFilename(path) + threadId + ".txt");
    13. if (file.exists() && file.length() > 0) {
    14. FileInputStream fis = new FileInputStream(file);
    15. BufferedReader bufr = new BufferedReader(
    16. new InputStreamReader(fis));
    17. // 读取出的内容就是上一次下载的位置
    18. String lastPositionn = bufr.readLine();
    19. int lastPosition = Integer.parseInt(lastPositionn);
    20. //赋值给我们定义的进度条进度位置
    21. PbLastPosition = lastPosition - startIndex;
    22. // 改变startIndex位置
    23. startIndex = lastPosition;
    24. fis.close();
    25. }
    26. // 设置一个请求头Range(作用告诉服务器每个线程下载的开始位置和结束位置)
    27. conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
    28. + endIndex);
    29. int code = conn.getResponseCode();
    30. // 200代表获取服务器资源全部成功
    31. // 206请求部分资源成功
    32. // if(code == 200)
    33. if (code == 206) {
    34. // [6]创建随机读写文件对象
    35. RandomAccessFile rafAccessFile = new RandomAccessFile(
    36. getFilename(path), "rw");
    37. // [6]每个线程要从自己的位置开始写
    38. rafAccessFile.seek(startIndex);
    39. InputStream inputStream = conn.getInputStream();
    40. // [7]把数据写到文件中
    41. int len = -1;
    42. byte[] Buffer = new byte[1024 * 1024];
    43. // 代表当前线程下载的大小
    44. int total = 0;
    45. while ((len = inputStream.read(Buffer)) != -1) {
    46. rafAccessFile.write(Buffer, 0, len);
    47. total += len;
    48. // [8]实现断点续传 就是把当前线程下载的位置给存起来 下次再下载的时候按照上次下载的位置继续下载就可以了
    49. // 存到一个普通的.txt文本中
    50. int currentThreadPosition = startIndex + total;
    51. // [9]用来存当前线程下载的位置
    52. RandomAccessFile raff = new RandomAccessFile(
    53. getFilename(path) + threadId + ".txt", "rwd");
    54. raff.write(String.valueOf(currentThreadPosition)
    55. .getBytes());
    56. raff.close();
    57. /*
    58. * 用这种方法有时候可能存不成功,因为硬盘有个缓存区 File file = new
    59. * File(threadId + ".txt"); FileOutputStream fos = new
    60. * FileOutputStream(file);
    61. * fos.write(String.valueOf(currentThreadPosition
    62. * ).getBytes()); fos.close();
    63. */
    64. //设置当前进度条的最大值和当前进度
    65. pbLists.get(threadId).setMax(PbMaxSize);
    66. pbLists.get(threadId).setProgress(PbLastPosition+total);
    67. }
    68. rafAccessFile.close();
    69. // 获取线程的数量
    70. String threadCountt = et_threadCount.getText().toString().trim();
    71. final int threadCount = Integer.parseInt(threadCountt);
    72. synchronized (DownLoadThread.class) {
    73. runningThread--;
    74. if (runningThread == 0) {
    75. // 说明所有的线程都执行完毕了 就把.txt文件删除
    76. for (int i = 0; i < threadCount; i++) {
    77. File delFile = new File(getFilename(path) + i
    78. + ".txt");
    79. delFile.delete();
    80. }
    81. }
    82. }
    83. }
    84. } catch (Exception e) {
    85. e.printStackTrace();
    86. }
    87. }
    88. }
    89. /*
    90. * 获取文件的名字
    91. */
    92. public static String getFilename(String path){
    93. int start = path.lastIndexOf("/");
    94. String substring = path.substring(start);
    95. String fileName = Environment.getExternalStorageDirectory().getPath() + "/" + substring;
    96. return fileName;
    97. }
    98. }
    activity_main.xml
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. xmlns:tools="http://schemas.android.com/tools"
    3. android:layout_width="match_parent"
    4. android:layout_height="match_parent"
    5. android:orientation="vertical"
    6. tools:context="com.phone.download.MainActivity" >
    7. <EditText
    8. android:id="@+id/et_path"
    9. android:layout_width="match_parent"
    10. android:layout_height="wrap_content"
    11. android:hint="请输入下载路径"/>
    12. <EditText
    13. android:id="@+id/et_threadCount"
    14. android:layout_width="match_parent"
    15. android:layout_height="wrap_content"
    16. android:hint="请输入线程的数量"/>
    17. <Button
    18. android:onClick="click"
    19. android:layout_width="wrap_content"
    20. android:layout_height="wrap_content"
    21. android:hint="下载"/>
    22. <LinearLayout
    23. android:id="@+id/ll_pb"
    24. android:layout_width="match_parent"
    25. android:layout_height="match_parent"
    26. android:orientation="vertical">
    27. </LinearLayout>
    28. </LinearLayout>

    item.xml
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
    3. android:id="@+id/progressBar1"
    4. style="?android:attr/progressBarStyleHorizontal"
    5. android:layout_width="match_parent"
    6. android:layout_height="wrap_content" />

    8开源项目实现多线程下载(xutils)
    1. package com.phone.opensourcedownload;
    2. import java.io.File;
    3. import android.app.Activity;
    4. import android.os.Bundle;
    5. import android.view.View;
    6. import android.widget.EditText;
    7. import android.widget.ProgressBar;
    8. import android.widget.Toast;
    9. import com.lidroid.xutils.HttpUtils;
    10. import com.lidroid.xutils.exception.HttpException;
    11. import com.lidroid.xutils.http.ResponseInfo;
    12. import com.lidroid.xutils.http.callback.RequestCallBack;
    13. public class MainActivity extends Activity {
    14. private EditText et_path;
    15. private ProgressBar pb;
    16. @Override
    17. protected void onCreate(Bundle savedInstanceState) {
    18. super.onCreate(savedInstanceState);
    19. setContentView(R.layout.activity_main);
    20. //[0]获取控件
    21. et_path = (EditText) findViewById(R.id.et_path);
    22. pb = (ProgressBar) findViewById(R.id.progressBar1);
    23. }
    24. //点击按钮实现断点续传下载逻辑
    25. public void click(View v){
    26. //[1]获取下载路径
    27. String path = et_path.getText().toString().trim();
    28. //[2]创建httputils对象HttpUtils http = new HttpUtils();
    29. HttpUtils http = new HttpUtils();
    30. //[3]实现断点下载
    31. /**
    32. * path:路径
    33. * target:下载文件的路径,即下载到哪
    34. * autoResume:是否支持断点续传的逻辑
    35. *
    36. */
    37. http.download(path, "/mnt/sdcard/haha.exe", true, new RequestCallBack<File>() {
    38. //下载成功
    39. @Override
    40. public void onSuccess(ResponseInfo<File> responseInfo) {
    41. Toast.makeText(getApplicationContext(), "下载成功", 1);
    42. }
    43. @Override
    44. /**
    45. * total:代表总进度
    46. * current:代表当前进度
    47. */
    48. public void onLoading(long total, long current, boolean isUploading) {
    49. pb.setMax((int)total);
    50. pb.setProgress((int)current);
    51. }
    52. //下载失败的回调函数
    53. @Override
    54. public void onFailure(HttpException error, String msg) {
    55. }
    56. });
    57. }
    58. }
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2. xmlns:tools="http://schemas.android.com/tools"
    3. android:layout_width="match_parent"
    4. android:layout_height="match_parent"
    5. android:orientation="vertical"
    6. tools:context="com.phone.download.MainActivity" >
    7. <EditText
    8. android:id="@+id/et_path"
    9. android:layout_width="match_parent"
    10. android:layout_height="wrap_content"
    11. android:hint="请输入下载路径" />
    12. <Button
    13. android:layout_width="wrap_content"
    14. android:layout_height="wrap_content"
    15. android:hint="下载"
    16. android:onClick="click" />
    17. <ProgressBar
    18. android:id="@+id/progressBar1"
    19. style="?android:attr/progressBarStyleHorizontal"
    20. android:layout_width="match_parent"
    21. android:layout_height="wrap_content" />
    22. </LinearLayout>
    9今日总结
       [1]httpurlConnection 用于发送或者接收数据(掌握)
            get    组拼url地址
            post    要自己组拼请求正文    请求头信息
       [2]httpClient(了解)
       [3]asyncHttpClient(掌握)
       [4]多线程下载
            1.获取文件大小
            2.在客户端创建一个大小和服务器一模一样的文件(为了提前申请控件)
            3.算出每个线程下载的开始位置和结束位置
                    需要考虑    最后一个线程    文件长度-1
            4.开启一个线程去实现下载逻辑    httpurlConnection
                    设置Range    还要注意服务器返回的状态码不是200而是206
            5.断点的逻辑    就是把当前线程下载的位置给保存起来    RandomAccessFile    直接同步到底层设备
            6.移植到Android    算出进度条的进度    集合存进度条的引用
            7.与进度有关的都可以在子线程直接更新UI




    只言片语任我说,提笔句句无需忖。落笔不知寄何人,唯有邀友共斟酌。
  • 相关阅读:
    Flexslider解决多图片刷新闪烁问题
    记一次MySQL授权问题
    AtCoder Beginner Contest 252
    021 指针思考
    Centos 7 添加Wifi驱动
    Java多线程对象内置锁(ObjectMonitor)
    卸载卸载
    mysql8.0安装终结版(mysql忘了密码操作步骤511步骤)
    Oracle实现统计一天的时候记录缺失哪一个时间(以分钟为单位处理的)
    腾讯云配置nginx跳转服务器内部服务
  • 原文地址:https://www.cnblogs.com/phonecom/p/e1e6e17f89d0c4d5e321744a9a169aa8.html
Copyright © 2020-2023  润新知