1. 乱码问题
1.1. GET向服务器端提交中文数据乱码
服务器端返回中文数据乱码解决:
出现原因:由于tomcat服务器编码格式是ISO8859-1,所以当返回中文的时候,会默认使用此编码。但是此编码不包含中文,所以在这个码表中找不到会到本地码表查找,本地码表是gbk,安卓客户端是以UTF-8编码格式的,所以会出现乱码。
解决方案: (1) 服务器端:使用UTF-8编码URLEncoder.encode(name, "utf-8");
(2) 服务器端:
new String(name.getBytes("iso-8859-1"),"utf-8");
1.2. POST向服务器端提交中文数据乱码
解决方法:在客户端中对中文进行URL编码
URLEncoder.encode(name, "utf-8");
1.3. 总结
不管是使用GET还是POST方式提交,解决办法都是保证服务器端和客户端使用的字符集编码一致。
2. HttpClient
2.1. HttpClient开源项目简介
HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,使客户顿发送http请求变得容易。HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。
2.2. 使用HttpClient发送get请求
//拼接get请求路径String url = "http://192.168.14.79/Web2/servlet/LoginServlet?name=" + URLEncoder.encode(name) + "&pass=" + pass;//创建HttpClient客户端对象HttpClient client = new DefaultHttpClient();//创建Get请求对象,参数传入请求地址HttpGet get = new HttpGet(url);try { //调用客户端的execute()方法执行请求,获取HttpResponse响应对象。Response对象中有服务器返回的信息 HttpResponse response = client.execute(get); //获取响应中的状态行,根据状态行可以判断请求成功失败等信息 StatusLine line = response.getStatusLine(); if(line.getStatusCode() == 200){ //获去请求实体 HttpEntity entity = response.getEntity(); //从实体中获取输入流,也就是服务器返回给客户端的流信息 InputStream is = entity.getContent(); //获取流信息 String text = Tools.getTextFromStream(is); Message msg = handler.obtainMessage(); msg.obj = text; handler.sendMessage(msg); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }}
运行效果:
2.3. 使用HttpClient发送post请求
//封装请求提交的参数,创建NameValuePair对象用于封装要提交的参数String url = "http://192.168.14.79/Web2/servlet/LoginServlet";HttpClient client = new DefaultHttpClient();HttpPost post = new HttpPost(url);BasicNameValuePair bnvp1 = new BasicNameValuePair("name", name);BasicNameValuePair bnvp2 = new BasicNameValuePair("pass", pass);//创建集合用来存放封装后的提交参数Listparameters = new ArrayList ();//将封装后的提交参数存入到集合中parameters.add(bnvp1);parameters.add(bnvp2);try { //创建表单实体UrlEncodedFormEntity,参数1代表需要提交数据的集合,参数2代表编码格式 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,"utf-8"); //给post对象设置请求实体,post.setEntity(entity) post.setEntity(entity); //调用client的execute(post)方法获取响应对象 HttpResponse response = client.execute(post); if(response.getStatusLine().getStatusCode() == 200){ //从响应中获取响应体然后获取其中的内容,也就是我们的输入流。 InputStream is = response.getEntity().getContent(); String text = Tools.getTextFromStream(is); Message msg = handler.obtainMessage(); msg.obj = text; handler.sendMessage(msg); }} catch (Exception e) { e.printStackTrace();}
效果如下:
3. AsyncHttpClient
3.1. 简介以及框架下载
AsyncHttpClient是一个开源的网络请求框架,它是专门针对Android在Apache的HttpClient基础上构建的异步的callback based http client。所有的请求全在UI线程之外,而callback发生在创建它的线程中,应用了Android的Handler发送消息机制。
下载可以在github上面下载,使用的时候直接在Android工程中导入AsyncHttpClient的jar包或者源码。3.2. GET方式向服务器提交数据
EditText et_name = (EditText) findViewById(R.id.et_name);EditText et_pass = (EditText) findViewById(R.id.et_pass);final String name = et_name.getText().toString();final String pass = et_pass.getText().toString();String url = "http://192.168.14.79/Web2/servlet/LoginServlet";//创建AsyncHttpClient对象AsyncHttpClient client = new AsyncHttpClient();//创建RequestParams对象,封装需要提交的数据RequestParams params = new RequestParams();params.put("name", name);params.put("pass", pass);//调用AsyncHttpClient对象的get方法来提交get请求,参数1是请求Url,参数2是提交的参数,参数3是请求回调client.get(url, params, new MyHandler());
请求回调,继承自AsyncHttpResponseHandler
class MyHandler extends AsyncHttpResponseHandler{ //onSuccess()当请求成功时回调 @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { super.onSuccess(statusCode, headers, responseBody); Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } //onFailuure()当请求失败时回调 @Override public void onFailure(int statusCode, Header[] headers,byte[] responseBody, Throwable error) { super.onFailure(statusCode, headers, responseBody, error); Toast.makeText(MainActivity.this, "请求失败", 0).show(); }}
3.3. POST方式向服务器提交数据
//获取数据EditText et_name = (EditText) findViewById(R.id.et_name);EditText et_pass = (EditText) findViewById(R.id.et_pass);final String name = et_name.getText().toString();final String pass = et_pass.getText().toString();String url = "http://192.168.14.79/Web2/servlet/LoginServlet";AsyncHttpClient client = new AsyncHttpClient();RequestParams params = new RequestParams();params.put("name", name);params.put("pass", pass);//调用AsyncHttpClient的post方法来提交post请求,其中第一个参数是访问Url,第二个参数是提交的参数,第三个参数是请求响应回调client.post(url, params, new MyHandler());
创建请求处理类,继承自AsyncHttpResponseHandler:
class MyHandler extends AsyncHttpResponseHandler{ //当请求成功会回调onSuccess()方法 @Override public void onSuccess(int statusCode, Header[] headers,byte[] responseBody) { super.onSuccess(statusCode, headers, responseBody); Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } //当请求失败会回调onFailure()方法 @Override public void onFailure(int statusCode, Header[] headers,byte[] responseBody, Throwable error) { super.onFailure(statusCode, headers,responseBody, error); Toast.makeText(MainActivity.this, "请求失败", 0).show(); }}
4. 文件上传
分析服务器端Web工程UploadFileServlet接收上传文件的代码:
首先判断上传的数据是表单数据还是一个带文件的数据,如果是带文件的数据,拿到Servlet真实路径,创建目录,如果目录不存在则创建目录,然后利用ServletFileUpload进行上传文件。@WebServlet("/UploadServlet")public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; public UploadServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean isMultipart = ServletFileUpload.isMultipartContent(request); //判断上传的数据是表单数据还是一个带文件的数据 if (isMultipart) { //获取Servlet真实路径,在路径后面加上/files String realpath = request.getSession().getServletContext().getRealPath("/files"); //创建File对象,判断是否存在目录,如果不存在,则创建目录 File dir = new File(realpath); if (!dir.exists()) dir.mkdirs(); FileItemFactory factory = new DiskFileItemFactory(); //创建文件上传类,设置头的编码格式为utf-8 ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); try { //调用ServletFileUpLoad类的parserRequest()方法,解析请求,返回文件项的集合 Listitems = upload.parseRequest(request); //遍历集合,判断FileItem的类型,如果是表单数据(26-30),我们就获取请求参数,如果是文件类型(30-35行),我们就调用FileItem的write方法,将文件上传到指定目录。 for (FileItem item : items) { if (item.isFormField()) { String name1 = item.getFieldName(); String value = item.getString("UTF-8"); System.out.println(name1 + "=" + value); } else { item.write(new File(dir,System.currentTimeMillis() + item.getName().substring(item.getName().lastIndexOf(".")))); } } } catch (Exception e) { e.printStackTrace(); } } }}
以上是服务器的代码,那手机客户端如何上传文件呢?利用httpwatch查看上传文件时请求信息,如果是自己实现文件上传比较复杂。
4.1. 利用AsyncHttpClient上传文件
创建布局:
上传逻辑代码:
//获取EditText中输入的路径,创建File对象String path = et_path.getText().toString().trim();File file = new File(path);//判断file是否是存在并且file的长度不为0if (file.exists() && file.length() > 0) { String uploadUrl = "http://192.168.19.28:8080/upload/UploadServlet"; //创建AsyncHttpClient对象 AsyncHttpClient client = new AsyncHttpClient(); //创建请求参数类,加入请求参数 RequestParams params = new RequestParams(); params.put("username", "james"); params.put("password", "123456"); try { //传入file,就是我们需要上传的文件对象 params.put("profile_picture", file); } catch (FileNotFoundException e) { e.printStackTrace(); } client.post(uploadUrl, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { System.out.println("请求成功"); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { } });}}
运行结果:
服务器控制台输出:
5. 多线程加速下载的原理
司马光砸缸的例子:砸的口子越多,流出的水越快。
小细节:并不是说开的线程越多下载速度越快,如手机迅雷(简称手雷)推荐线程3-5;此外下载速度还受到真实带宽的影响。 在单位时间内,服务器更多的cpu资源给了你,速度越快。 那么我们如何实现多线程下载呢?下面这张图表示客户端开启3个线程去服务器端下载相对应部分的文件: 多线程下载步骤: 客户端: (a)创建一个文件,大小和服务器文件的大小一样; (b)开启多个线程去下载服务器上对应部分的资源。 这时候我们需要考虑以下几个问题: (c)如何等分服务器的资源? (d)如何创建一个大小和服务器一模一样的文件? (e)如何开启多个线程? (f)如何知道每个线程都下载完毕了?6. JavaSE多线程下载实现
步骤:
1. 部署服务端; 2. 获取服务器的资源; 3. 获取文件的大小,利用conn.getContentLength(); 4. 创建随机文件(RandomAccessFile),大小和服务器文件大小一致; 5. 计算出每个线程下载的大小,然后算出每个线程下载的开始位置以及结束位置; 6. 开启多个线程去下载。6.1. 部署服务端
运行tomcat服务器,在tomcat安装路径的ROOT目录下放置下载资源(参考:当前计算机的C:\软件\apache-tomcat-7.0.68\webapps\ROOT),如下图所示:
我们需要下载的资源是feiq.exe,启动tomcat,在浏览器中访问该下载资源(路径为:),效果如下图所示: 从上图可以看出,服务端部署完毕。6.2. 编写下载核心代码
在Eclipse中创建Java工程,工程名为“多线程下载”,实现多线程下载文件feiq.exe。
1. 创建工程 【File】->【new】->【Java Project】命名为:多线程下载 2. 使用默认包名,创建一个类MultiDownload,工程目录结构如下图所示: 3. 在MultiDownload类中编写下载方法。具体实现步骤如下: (a)联网获取网络资源,获取文件长度。public class MutilDownLoad { //定义服务器端资源访问路径 private static String path = "http://192.168.19.28:8080/feiq.exe"; //定义下载线程数为3 private static int threadCount = 3; public static void main(String[] args) { try { //网络请求数据 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { //通过getContentLenght()方法可以获取服务器文件的大小 int length = conn.getContentLength(); System.out.println(length); } } catch (Exception e) { e.printStackTrace(); } }}
运行结果如下图:
我们查看服务器上的文件详情,可以看到大小和我们网络获取得到的大小一样,如下图: (b)在本地创建一个文件,大小和服务器文件大小一样。//创建RandomAccessFile对象RandomAccessFile ras = new RandomAccessFile("temp.exe","rw");//setLength()方法设置文件的大小,传入的大小就是之前从服务器获取的文件的大小ras.setLength(length);
运行程序,可以看到工程目录下多了一个文件temp.exe,查看文件大小和我们服务器的文件大小一致,如下图:
我们使用编辑器打开temp.exe,可以看到里面没有数据,全部为null,这样证明了我们创建的文件是一个大小和服务器一样的空文件。如下图:
(c)定义下载线程的个数,根据文件总大小计算每个线程下载的开始位置和结束位置。
根据推理,我们可以得出以下公式:获取每个线程下载的开始位置和结束位置:
public class MutilDownLoad { private static String path = "http://192.168.19.28:8080/feiq.exe"; //定义下载的线程数为3 private static int threadCount = 3; public static void main(String[] args) { try { //联网获取服务器资源 ... ... if (code == 200) { int length = conn.getContentLength(); //计算每个线程需要下载的长度 int blockSize = length / threadCount; for (int i = 0; i < threadCount; i++) { //根据公式计算出每个线程的开始位置 int startIndex = i * blockSize; //根据公式计算出每个线程的结束位置(除去最后一个线程) int endIndex = (i + 1) * blockSize - 1; //如果是最后一个线程,根据公式,该线程的结束位置为(文件总长度-1) if (i == threadCount - 1) { endIndex = length - 1; } System.out.println("线程id:"+id+"下载位置:"+startindex+"~"+endindex); } } } catch (Exception e) { e.printStackTrace(); } }
运行结果如下图:
(d)定义下载子线程,下载对应区域的文件,写入到创建的本地文件中。该类由于是一个子线程,所以我们需要继承Thread类。
private static class DownLoadThread extends Thread { //定义下载路径 private String path; //定义当前线程下载的开始位置和结束位置 private int startIndex; private int endIndex; //定义threadId表示当前是哪一个线程 private int threadId; //定义构造函数 public DownLoadThread(String path, int startIndex, int endIndex, int threadId) { this.path = path; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; } //开启子线程下载文件 @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); //设置Range头信息,告诉服务器每个线程下载的开始位置和结束位置;第24行,判断请求码是否是206,代表请求服务器部分资源成功,200代表请求服务器全部资源成功 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); int code = conn.getResponseCode(); if (code == 206) { InputStream in = conn.getInputStream(); //创建RandomAccessFile对象,和我们之前创建的文件对接 RandomAccessFile ras = new RandomAccessFile("temp.exe", "rw"); //seek()方法设置文件写入的初始位置,由于每个线程开始下载的位置不一样,所以我们需要调用该方法指定线程下载数据开始存放的位置 ras.seek(startIndex); int len = -1; byte buffer[] = new byte[1024]; while ((len = in.read(buffer)) != -1) { ras.write(buffer, 0, len); } ras.close(); System.out.println("线程id" + threadId + "下载完毕了"); } } catch (Exception e) { e.printStackTrace(); } super.run(); }}
(e)在我们计算每个线程下载初始位置和结束位置时,调用下载线程下载对应区域的文件数据。
for (int i = 0; i < threadCount; i++) { int startIndex = i * blockSize; int endIndex = (i + 1) * blockSize - 1; if (i == threadCount - 1) { endIndex = length - 1; } //创建下载线程,参数1表示下载路径,参数2表示下载文件开始位置,参数3表示下载文件结束位置,参数4表示当前线程的标识 DownLoadThread downLoadThread = new DownLoadThread(path, startIndex, endIndex, i); //开启线程 downLoadThread.start();}
测试结果:
我们查看工程目录下的文件,点击可以使用,说明下载成功。如下图:7. 多线程下载断点续传
原理:把每次下载的位置给存起来,下次从这个位置继续下载。
本案例和上一节多线程下载有很多相似之处,不同点在于如何断点续传,所以这里将对断点续传代码做详细解释。 断点续传最关键的是下载的时候,要知道上次下载的位置。那么我们可以定一个变量total来记录当前线程已经下载的文件大小,每次往本地文件中写如lenth长度数据后,total也需要加上这个lenth长度变成新的total长度。此外,还需要定义一个变量来记录当前线程下载的位置currentThreadPosition,当前线程下载的位置currentThreadPosition=startIndex(初始位置)+total(已经下载的大小),将当前下载位置保存到文件中。(a)保存当前线程下载的位置
//total表示当前下载的总大小int total = 0; while ((len = in.read(buffer)) != -1) { ras.write(buffer, 0, len); //每次向本地文件写入数据时,total要加上写入数据的长度len total += len; //计算出当前线程下载的位置 int currentThreadPosition = startIndex + total; //创建保存当前线程下载位置的文件,getFileName(path)方法获取文件名称(见下方) RandomAccessFile rass = new RandomAccessFile(getFileName(path) + threadId + ".txt", "rwd"); rass.write(String.valueOf(currentThreadPosition).getBytes()); rass.close();}
获取文件名称,将路径截取最后一个/获取后面的文件名:
public static String getFileName(String path) { int start = path.lastIndexOf("/") + 1; return path.substring(start);}
我们这边模拟下载过程中断掉下载,查看下载目录:
从上图可以看出,我们第0个线程下载到的位置在4186000。那么我们下次下载的时候就需要读取文件中的这个位置,从这个位置继续下载。(b)读取文件中下载的位置,以这个位置为开始位置,以计算的每个线程的结束位置进行第n次下载。
private static class DownLoadThread extends Thread { @Override public void run() { try { //联网获取网络数据 ...... //创建我们保存线程读取数据大小的文件对象 File file = new File(getFileName(path) + threadId + ".txt"); //如过保存线程下载位置的文件存在并且大小大于0,就说明是断点续传 if (file.exists() && file.length() > 0) { //读取线程上次写入数据的大小 FileInputStream fis = new FileInputStream(file); BufferedReader bfr = new BufferedReader(new InputStreamReader(fis)); String lastPosition = bfr.readLine(); //设置当前线程下载的开始和结束位置 conn.setRequestProperty("Range", "bytes=" + lastPosition + "-" + endIndex); startIndex = Integer.parseInt(lastPosition); fis.close(); System.out.println("线程id真实的-" + threadId + ":" + startIndex + "----" + endIndex); } else { //如果是第一次开始下载,那么就从我们之前计算的开始位置和结束位置进行下载 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); } //下载逻辑 ...... } catch (Exception e) { e.printStackTrace(); } super.run(); }}
我们测试一下,当第一次下载时,我们断一下下载,我们查看控制台输出:
我们接下来继续下载,查看控制台输出:
从上面可以看出,第二次下载,线程的起始位置发生了改变。
(c)下载完毕删除记录当前线程下载位置的文件。
由于是多线程下载,我们需要知道是哪一个线程下载完成了。我们定义一个变量runningThread来记录运行的线程个数。runningThread初始化的值就是我们线程的数量,当下载完成之后runningThread自减,当runningThread小于等于0就表示全部下载完成,这时候删除记录文件。synchronized (DownLoadThread.class) { runningThread--; if (runningThread <= 0) { for (int i = 0; i < threadCount; i++) { File deleteFile = new File(getFileName(path) + i + ".txt"); deleteFile.delete(); } }}
由于是多线程,所以runningThread–;会有线程安全问题,所以我们需要将这句话加上同步语句。
8. Android上多线程下载
Android工程中多线程下载的逻辑和JavaSE中多线程下载逻辑类似。这里把JavaSE中已实现的功能代码移植到Android工程中,并且添加添加下载的进度条来实时查看线程下载进度。
界面布局:
MainActivity逻辑,EditText中输入下载线程个数,点击下载按钮开始下载,并且根据线程个数创建对应的ProgressBar。
public class MainActivity extends Activity { //定义成员变量 ...... //线性布局用来添加ProgressBar private LinearLayout ll_layout; //用来存放ProgressBar集合 private Listpbs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化控件 ...... pbs = new ArrayList (); } public void click(View v) { ...... ll_layout.removeAllViews(); pbs.clear(); //根据下载线程数量来创建ProgressBar添加到线性布局,并且添加到ProgressBar的集合 for (int i = 0; i < threadCount; i++) { ProgressBar pbBar = (ProgressBar) View.inflate(getApplicationContext(), R.layout.item, null); ll_layout.addView(pbBar); pbs.add(pbBar); } new Thread() { public void run() { try { //联网获取数据 ...... if (code == 200) { int length = conn.getContentLength(); RandomAccessFile ras = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath() + "/" + getFileName(path), "rw"); ras.setLength(length); runningThread = threadCount; int blockSize = length / threadCount; for (int i = 0; i < threadCount; i++) { int startIndex = i * blockSize; int endIndex = (i + 1) * blockSize - 1; if (i == threadCount - 1) { endIndex = length - 1; } DownLoadThread downLoadThread = new DownLoadThread(path, startIndex, endIndex, i); // 开启线程 downLoadThread.start(); } } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } private class DownLoadThread extends Thread { //成员变量 ...... private int pbmaxSize; private int pbCurrentSize; //构造函数 ...... @Override public void run() { try { pbmaxSize = endIndex - startIndex; //连接网络获取资源 ...... File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + getFileName(path) + threadId + ".txt"); if (file.exists() && file.length() > 0) { FileInputStream fis = new FileInputStream(file); BufferedReader bfr = new BufferedReader(new InputStreamReader(fis)); String lastPosition = bfr.readLine(); conn.setRequestProperty("Range", "bytes=" + lastPosition + "-" + endIndex); pbCurrentSize = Integer.parseInt(lastPosition) - startIndex; startIndex = Integer.parseInt(lastPosition); fis.close(); } else { conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); } int code = conn.getResponseCode(); if (code == 206) { InputStream in = conn.getInputStream(); RandomAccessFile ras = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath() + "/" + getFileName(path), "rw"); ras.seek(startIndex); int len = -1; byte buffer[] = new byte[1024 * 1024]; // 1kb int total = 0; while ((len = in.read(buffer)) != -1) { ras.write(buffer, 0, len); total += len; int currentThreadPosition = startIndex + total; RandomAccessFile rass = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath() + "/" + getFileName(path) + threadId + ".txt", "rwd"); rass.write(String.valueOf(currentThreadPosition).getBytes()); rass.close(); pbs.get(threadId).setMax(pbmaxSize); pbs.get(threadId).setProgress(pbCurrentSize + total); } ras.close(); ...... //删除保存线程下载位置文件 } } catch (Exception e) { e.printStackTrace(); } super.run(); } }}
9. 使用xUtils实现多线程下载
9.1. xUtils开源项目简介及框架下载
(1)xUtils包含了很多实用的android工具。
(2)xUtils最初源于Afinal框架,进行了大量重构,使得xUtils支持大文件上传,拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响。
(3)xUitls最低兼容android 2.2 (api level 8)
(4)xUtils主要有以下四大模块:
DbUtils模块、ViewUtils模块、HttpUtils模块、BitmapUtils模块。(5)xUtils可以在github上搜索进行下载:
9.2. 使用xUtils下载
界面布局:点击下载进行下载,下方progressbar显示下载进度。
下载逻辑:
public class MainActivity extends Activity { private ProgressBar pb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //更新下载的进度 pb = (ProgressBar) findViewById(R.id.progressBar1); } public void click(View v){ //创建HttpUtils对象 HttpUtils http = new HttpUtils(); String url = "http://192.168.19.28:8080/feiq.exe"; //调用HttpUtils的download方法下载文件,第一个参数是下载的路径,第二个参数是是否支持断点续传,第三个参数是下载回调 http.download(url, "/mnt/sdcard/fei.exe", true, new RequestCallBack() { //下载成功的回调 @Override public void onSuccess(ResponseInfo responseInfo) { Toast.makeText(getApplicationContext(), "sucess",0).show(); } //下载失败 @Override public void onFailure(HttpException error, String msg) { } //更新当前的进度 @Override public void onLoading(long total, long current, boolean isUploading) { pb.setMax((int) total); pb.setProgress((int) current); super.onLoading(total, current, isUploading); } }); }}
运行结果:
10. ProgressDialog的使用
点击按钮弹出ProgressDialog对话框。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v) { //创建ProgressDialog实例 final ProgressDialog dialog = new ProgressDialog(MainActivity.this); //设置标题 dialog.setTitle("正在玩命加载ing"); //设置ProgressDialog的样式是横向的样式 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); new Thread() { public void run() { //设置ProgressDialog的最大进度 dialog.setMax(100); for (int i = 0; i <= 100; i++) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } //设置ProgressDialog当前的进度 dialog.setProgress(i); } // 关闭对话框 dialog.dismiss(); }; }.start(); dialog.show(); }}