3. Android框架和工具之 xUtils(HttpUtils)
1. HttpUtils 作用:
- 支持同步,异步方式的请求;
- 支持大文件上传,上传大文件不会oom;
- 支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD请求;
- 下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
- 返回文本内容的GET请求支持缓存,可设置默认过期时间和针对当前请求的过期时间。
2. HttpUtils全面注释:
1 /* 2 3 4 /** 5 * 网络请求工具类 6 * @author 阿福 7 * 8 */ 9 public class HttpUtils { 10 11 public final static HttpCache sHttpCache = new HttpCache(); 12 13 private final DefaultHttpClient httpClient; 14 private final HttpContext httpContext = new BasicHttpContext(); 15 16 private HttpRedirectHandler httpRedirectHandler; 17 18 /** 19 * 构造方法,默认联网15秒超时 20 */ 21 public HttpUtils() { 22 this(HttpUtils.DEFAULT_CONN_TIMEOUT, null); 23 } 24 25 /** 26 * 构造方法设置超时时间 27 * @param connTimeout 超时时间毫秒 28 */ 29 public HttpUtils(int connTimeout) { 30 this(connTimeout, null); 31 } 32 33 /** 34 * 构造方法,浏览器的信息包 35 * @param userAgent 36 */ 37 public HttpUtils(String userAgent) { 38 this(HttpUtils.DEFAULT_CONN_TIMEOUT, userAgent); 39 } 40 41 /** 42 * 构造方法 43 * @param connTimeout 链接超时时间,毫秒单位 44 * @param userAgent 浏览器的信息包 45 */ 46 public HttpUtils(int connTimeout, String userAgent) { 47 HttpParams params = new BasicHttpParams(); 48 49 ConnManagerParams.setTimeout(params, connTimeout); 50 HttpConnectionParams.setSoTimeout(params, connTimeout); 51 HttpConnectionParams.setConnectionTimeout(params, connTimeout); 52 53 if (TextUtils.isEmpty(userAgent)) { 54 userAgent = OtherUtils.getUserAgent(null); 55 } 56 HttpProtocolParams.setUserAgent(params, userAgent); 57 58 ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10)); 59 ConnManagerParams.setMaxTotalConnections(params, 10); 60 61 HttpConnectionParams.setTcpNoDelay(params, true); 62 HttpConnectionParams.setSocketBufferSize(params, 1024 * 8); 63 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 64 65 SchemeRegistry schemeRegistry = new SchemeRegistry(); 66 schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 67 schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory.getSocketFactory(), 443)); 68 69 httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params); 70 71 httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_RETRY_TIMES)); 72 73 httpClient.addRequestInterceptor(new HttpRequestInterceptor() { 74 @Override 75 public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException { 76 if (!httpRequest.containsHeader(HEADER_ACCEPT_ENCODING)) { 77 httpRequest.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); 78 } 79 } 80 }); 81 82 httpClient.addResponseInterceptor(new HttpResponseInterceptor() { 83 @Override 84 public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException { 85 final HttpEntity entity = response.getEntity(); 86 if (entity == null) { 87 return; 88 } 89 final Header encoding = entity.getContentEncoding(); 90 if (encoding != null) { 91 for (HeaderElement element : encoding.getElements()) { 92 if (element.getName().equalsIgnoreCase("gzip")) { 93 response.setEntity(new GZipDecompressingEntity(response.getEntity())); 94 return; 95 } 96 } 97 } 98 } 99 }); 100 } 101 102 // ************************************ default settings & fields **************************** 103 104 105 private String responseTextCharset = HTTP.UTF_8; 106 107 private long currentRequestExpiry = HttpCache.getDefaultExpiryTime(); 108 109 private final static int DEFAULT_CONN_TIMEOUT = 1000 * 15; // 15s 110 111 private final static int DEFAULT_RETRY_TIMES = 3; 112 113 private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; 114 private static final String ENCODING_GZIP = "gzip"; 115 116 private final static int DEFAULT_POOL_SIZE = 3; 117 private final static PriorityExecutor EXECUTOR = new PriorityExecutor(DEFAULT_POOL_SIZE); 118 119 public HttpClient getHttpClient() { 120 return this.httpClient; 121 } 122 123 // ***************************************** config ******************************************* 124 125 /** 126 * 配置请求文本编码,默认UTF-8 127 * @param charSet 128 * @return 129 */ 130 public HttpUtils configResponseTextCharset(String charSet) { 131 if (!TextUtils.isEmpty(charSet)) { 132 this.responseTextCharset = charSet; 133 } 134 return this; 135 } 136 137 /** 138 * http重定向处理 139 * @param httpRedirectHandler 140 * @return 141 */ 142 public HttpUtils configHttpRedirectHandler(HttpRedirectHandler httpRedirectHandler) { 143 this.httpRedirectHandler = httpRedirectHandler; 144 return this; 145 } 146 147 /** 148 * 配置http缓存大小 149 * @param httpCacheSize 150 * @return 151 */ 152 public HttpUtils configHttpCacheSize(int httpCacheSize) { 153 sHttpCache.setCacheSize(httpCacheSize); 154 return this; 155 } 156 157 /** 158 * 配置默认http缓存失效 ,默认是60秒 159 * @param defaultExpiry 160 * @return 161 */ 162 public HttpUtils configDefaultHttpCacheExpiry(long defaultExpiry) { 163 HttpCache.setDefaultExpiryTime(defaultExpiry); 164 currentRequestExpiry = HttpCache.getDefaultExpiryTime(); 165 return this; 166 } 167 168 /** 169 * 配置当前http缓存失效,时间默认60秒 170 * @param currRequestExpiry 171 * @return 172 */ 173 public HttpUtils configCurrentHttpCacheExpiry(long currRequestExpiry) { 174 this.currentRequestExpiry = currRequestExpiry; 175 return this; 176 } 177 178 /** 179 * cookie存储配置 180 * @param cookieStore 181 * @return 182 */ 183 public HttpUtils configCookieStore(CookieStore cookieStore) { 184 httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); 185 return this; 186 } 187 188 /** 189 * 配置浏览器信息包 190 * @param userAgent 191 * @return 192 */ 193 public HttpUtils configUserAgent(String userAgent) { 194 HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent); 195 return this; 196 } 197 198 /** 199 * 配置时间链接超时 200 * @param timeout 201 * @return 202 */ 203 public HttpUtils configTimeout(int timeout) { 204 final HttpParams httpParams = this.httpClient.getParams(); 205 ConnManagerParams.setTimeout(httpParams, timeout); 206 HttpConnectionParams.setConnectionTimeout(httpParams, timeout); 207 return this; 208 } 209 210 /** 211 * 配置socket时间连接溢出 212 * @param timeout 213 * @return 214 */ 215 public HttpUtils configSoTimeout(int timeout) { 216 final HttpParams httpParams = this.httpClient.getParams(); 217 HttpConnectionParams.setSoTimeout(httpParams, timeout); 218 return this; 219 } 220 221 /** 222 * 配置注册Scheme 223 * @param scheme 224 * @return 225 */ 226 public HttpUtils configRegisterScheme(Scheme scheme) { 227 this.httpClient.getConnectionManager().getSchemeRegistry().register(scheme); 228 return this; 229 } 230 231 /** 232 * 配置SSLSocketFactory 233 * @param sslSocketFactory 234 * @return 235 */ 236 public HttpUtils configSSLSocketFactory(SSLSocketFactory sslSocketFactory) { 237 Scheme scheme = new Scheme("https", sslSocketFactory, 443); 238 this.httpClient.getConnectionManager().getSchemeRegistry().register(scheme); 239 return this; 240 } 241 242 /** 243 * 配置请求重试次数 244 * @param count 重试次数 245 * @return 246 */ 247 public HttpUtils configRequestRetryCount(int count) { 248 this.httpClient.setHttpRequestRetryHandler(new RetryHandler(count)); 249 return this; 250 } 251 252 /** 253 * 配置请求线程池个数 254 * @param threadPoolSize 线程池个数 255 * @return 256 */ 257 public HttpUtils configRequestThreadPoolSize(int threadPoolSize) { 258 HttpUtils.EXECUTOR.setPoolSize(threadPoolSize); 259 return this; 260 } 261 262 // ***************************************** send request 发送请求******************************************* 263 264 /** 265 * 发送异步网络请求 -重要 266 * @param method get或者post请求等等 267 * @param url 网络请求路径 268 * @param callBack 回调 269 * @return 270 */ 271 public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url, 272 RequestCallBack<T> callBack) { 273 return send(method, url, null, callBack); 274 } 275 276 /** 277 * 发送异步网络请求 -重要 278 * @param method get或者post请求等等 279 * @param url 网络请求路径 280 * @param params 请求参数 281 * @param callBack 回调 282 * @return 283 */ 284 public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url, RequestParams params, 285 RequestCallBack<T> callBack) { 286 if (url == null) throw new IllegalArgumentException("url may not be null"); 287 288 HttpRequest request = new HttpRequest(method, url); 289 return sendRequest(request, params, callBack); 290 } 291 292 /** 293 * 发送同步网络请求 -用得不多 294 * @param method get或者post等方法 295 * @param url 联网网络url 296 * @return 297 * @throws HttpException 298 */ 299 public ResponseStream sendSync(HttpRequest.HttpMethod method, String url) throws HttpException { 300 return sendSync(method, url, null); 301 } 302 303 /** 304 * 发送同步网络请求 -用得不多 305 * @param method get或者post等方法 306 * @param url 联网网络url 307 * @param params 请求参数 308 * @return 309 * @throws HttpException 310 */ 311 public ResponseStream sendSync(HttpRequest.HttpMethod method, String url, RequestParams params) throws HttpException { 312 if (url == null) throw new IllegalArgumentException("url may not be null"); 313 314 HttpRequest request = new HttpRequest(method, url); 315 return sendSyncRequest(request, params); 316 } 317 318 // ***************************************** download 下载******************************************* 319 320 /** 321 * 下载文件方法 322 * @param url 下载文件的url 323 * @param target 下载保存的目录 324 * @param callback 回调 325 * @return 326 */ 327 public HttpHandler<File> download(String url, String target, 328 RequestCallBack<File> callback) { 329 return download(HttpRequest.HttpMethod.GET, url, target, null, false, false, callback); 330 } 331 332 /** 333 * 下载文件方法 334 * @param url 下载文件的url 335 * @param target 下载保存的目录 336 * @param autoResume 是否自动恢复下载 337 * @param callback 回调 338 * @return 339 */ 340 public HttpHandler<File> download(String url, String target, 341 boolean autoResume, RequestCallBack<File> callback) { 342 return download(HttpRequest.HttpMethod.GET, url, target, null, autoResume, false, callback); 343 } 344 345 /** 346 * 下载文件方法 347 * @param url 下载文件的url 348 * @param target 下载保存的目录 349 * @param autoResume 是否自动恢复下载 350 * @param autoRename 是否自动重命名 351 * @param callback 回调 352 * @return 353 */ 354 public HttpHandler<File> download(String url, String target, 355 boolean autoResume, boolean autoRename, RequestCallBack<File> callback) { 356 return download(HttpRequest.HttpMethod.GET, url, target, null, autoResume, autoRename, callback); 357 } 358 359 /** 360 * 下载文件方法 361 * @param url 下载文件的url 362 * @param target 下载保存的目录 363 * @param params 参数类 364 * @param callback 回调 365 * @return 366 */ 367 public HttpHandler<File> download(String url, String target, 368 RequestParams params, RequestCallBack<File> callback) { 369 return download(HttpRequest.HttpMethod.GET, url, target, params, false, false, callback); 370 } 371 372 /** 373 * 下载文件方法 374 * @param url 下载文件的url 375 * @param target 下载保存的目录 376 * @param params 参数类 377 * @param autoResume 是否自动恢复下载 378 * @param callback 回调 379 * @return 380 */ 381 public HttpHandler<File> download(String url, String target, 382 RequestParams params, boolean autoResume, RequestCallBack<File> callback) { 383 return download(HttpRequest.HttpMethod.GET, url, target, params, autoResume, false, callback); 384 } 385 386 /** 387 * 下载文件方法 388 * @param url 下载文件的url 389 * @param target 下载保存的目录 390 * @param params 参数 391 * @param autoResume 是否自动恢复 392 * @param autoRename 是否自动命名 393 * @param callback 回调 394 * @return 395 */ 396 public HttpHandler<File> download(String url, String target, 397 RequestParams params, boolean autoResume, boolean autoRename, RequestCallBack<File> callback) { 398 return download(HttpRequest.HttpMethod.GET, url, target, params, autoResume, autoRename, callback); 399 } 400 401 /** 402 * 下载文件方法 403 * @param method 请求用get还是post等 404 * @param url 下载文件的url 405 * @param target 下载保存的目录 406 * @param params 参数 407 * @param callback 回调 408 * @return 409 */ 410 public HttpHandler<File> download(HttpRequest.HttpMethod method, String url, String target, 411 RequestParams params, RequestCallBack<File> callback) { 412 return download(method, url, target, params, false, false, callback); 413 } 414 415 /** 416 * 下载文件方法 417 * @param method 请求用get还是post等 418 * @param url 下载文件的url 419 * @param target 下载保存的目录 420 * @param params 参数 421 * @param autoResume 是否自动恢复下载 422 * @param callback 回调 423 * @return 424 */ 425 public HttpHandler<File> download(HttpRequest.HttpMethod method, String url, String target, 426 RequestParams params, boolean autoResume, RequestCallBack<File> callback) { 427 return download(method, url, target, params, autoResume, false, callback); 428 } 429 430 /** 431 * 下载文件方法 432 * @param method 请求用get还是post等 433 * @param url 下载文件的url 434 * @param target 下载保存的目录 435 * @param params 参数 436 * @param autoResume 是否自动恢复下载 437 * @param autoRename 是否自动重命名 438 * @param callback 回调 439 * @return 440 */ 441 public HttpHandler<File> download(HttpRequest.HttpMethod method, String url, String target, 442 RequestParams params, boolean autoResume, boolean autoRename, RequestCallBack<File> callback) { 443 444 if (url == null) throw new IllegalArgumentException("url may not be null"); 445 if (target == null) throw new IllegalArgumentException("target may not be null"); 446 447 HttpRequest request = new HttpRequest(method, url); 448 449 HttpHandler<File> handler = new HttpHandler<File>(httpClient, httpContext, responseTextCharset, callback); 450 451 handler.setExpiry(currentRequestExpiry); 452 handler.setHttpRedirectHandler(httpRedirectHandler); 453 454 if (params != null) { 455 request.setRequestParams(params, handler); 456 handler.setPriority(params.getPriority()); 457 } 458 handler.executeOnExecutor(EXECUTOR, request, target, autoResume, autoRename); 459 return handler; 460 } 461 462 //////////////////////////////////////////////////////////////////////////////////////////////// 463 private <T> HttpHandler<T> sendRequest(HttpRequest request, RequestParams params, RequestCallBack<T> callBack) { 464 465 HttpHandler<T> handler = new HttpHandler<T>(httpClient, httpContext, responseTextCharset, callBack); 466 467 handler.setExpiry(currentRequestExpiry); 468 handler.setHttpRedirectHandler(httpRedirectHandler); 469 request.setRequestParams(params, handler); 470 471 if (params != null) { 472 handler.setPriority(params.getPriority()); 473 } 474 handler.executeOnExecutor(EXECUTOR, request); 475 return handler; 476 } 477 478 private ResponseStream sendSyncRequest(HttpRequest request, RequestParams params) throws HttpException { 479 480 SyncHttpHandler handler = new SyncHttpHandler(httpClient, httpContext, responseTextCharset); 481 482 handler.setExpiry(currentRequestExpiry); 483 handler.setHttpRedirectHandler(httpRedirectHandler); 484 request.setRequestParams(params); 485 486 return handler.sendRequest(request); 487 } 488 }
3. HttpUtils使用post/get 方法访问网络:
(1)新建一个Android工程,命名为"HttpUtils",如下:
(2)首先我们来到主布局文件,如下:
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.himi.httputils.MainActivity" > 7 8 <Button 9 android:id="@+id/net" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:text="@string/replynet" /> 13 14 <TextView 15 android:id="@+id/loading" 16 android:layout_width="match_parent" 17 android:layout_height="wrap_content"/> 18 19 <ScrollView 20 android:layout_width="fill_parent" 21 android:layout_height="wrap_content"> 22 23 <TextView 24 android:id="@+id/success" 25 android:layout_width="match_parent" 26 android:layout_height="wrap_content"/> 27 28 </ScrollView> 29 30 </LinearLayout>
(3)下面来到AndroidManifest.xml配置文件,添加权限。如下:
(4)来到MainActivity,如下:
1 package com.himi.httputils; 2 3 import com.lidroid.xutils.HttpUtils; 4 import com.lidroid.xutils.ViewUtils; 5 import com.lidroid.xutils.exception.HttpException; 6 import com.lidroid.xutils.http.ResponseInfo; 7 import com.lidroid.xutils.http.callback.RequestCallBack; 8 import com.lidroid.xutils.http.client.HttpRequest; 9 import com.lidroid.xutils.view.annotation.ViewInject; 10 import com.lidroid.xutils.view.annotation.event.OnClick; 11 12 import android.app.Activity; 13 import android.os.Bundle; 14 import android.os.Handler; 15 import android.os.Message; 16 import android.view.View; 17 import android.widget.Button; 18 import android.widget.TextView; 19 20 public class MainActivity extends Activity { 21 22 @ViewInject(R.id.net) 23 private Button net; 24 25 @ViewInject(R.id.loading) 26 private TextView loading; 27 28 @ViewInject(R.id.success) 29 private TextView success; 30 31 /** 32 * handler线程是主要用来和UI主线程进行交互的 33 *//* 34 private Handler handler = new Handler(){ 35 public void handleMessage(Message msg) { 36 super.handleMessage(msg); 37 switch (msg.what) { 38 case 1: 39 40 break; 41 default: 42 break; 43 } 44 }; 45 };*/ 46 47 48 @Override 49 protected void onCreate(Bundle savedInstanceState) { 50 super.onCreate(savedInstanceState); 51 setContentView(R.layout.activity_main); 52 ViewUtils.inject(this); 53 } 54 55 @OnClick(R.id.net) 56 public void reply(View v) { 57 58 HttpUtils http = new HttpUtils(); 59 http.send(HttpRequest.HttpMethod.GET, "http://www.lidroid.com", new RequestCallBack<String>() { 60 @Override 61 public void onLoading(long total, long current, boolean isUploading) { 62 System.out.println("数据加载中……"); 63 //System.out.println(current + "/" + total); 64 loading.setText(current + "/" + total); 65 } 66 67 @Override 68 public void onSuccess(ResponseInfo<String> responseInfo) { 69 System.out.println("数据加载完毕……"); 70 //System.out.println(responseInfo.result); 71 success.setText(responseInfo.result); 72 } 73 74 @Override 75 public void onStart() { 76 System.out.println("数据开始加载……"); 77 } 78 79 @Override 80 public void onFailure(HttpException error, String msg) { 81 System.out.println("数据加载失败……"); 82 } 83 }); 84 85 } 86 87 }
布署程序到手机中,如下:
我们可以知道使用 HttpUtils 访问网络的时候不用new Thread一个子线程,HttpUtils内部自己实现了子线程。
同时我们在RequestCallBack回调的方法中可以直接操作UI界面的更新。
4. HttpUtils使用Get方法提交数据到服务器:
(1)首先我们搭建一个服务器平台,如下:
(2)我们先看看LoginServlet,如下:
1 package web; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.WebServlet; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * Servlet implementation class LoginServlet 13 */ 14 @WebServlet("/LoginServlet") 15 public class LoginServlet extends HttpServlet { 16 private static final long serialVersionUID = 1L; 17 18 19 /** 20 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 21 */ 22 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 23 String qq = request.getParameter("qq"); 24 String password = request.getParameter("password"); 25 System.out.println("qq:"+qq); 26 System.out.println("password:"+password); 27 28 /** 29 * 模拟服务器操作,查询数据库,看qq和密码是否正确. 30 * response.getOutputStream()获得一个输出流,向浏览器写入数据(提示数据). 31 * 这里是输出Output,服务器输出到浏览器 32 */ 33 if("10086".equals(qq) && "123456".equals(password)) { 34 response.getOutputStream().write("Login Success".getBytes()); 35 }else { 36 response.getOutputStream().write("Login Failed".getBytes()); 37 } 38 39 } 40 41 42 }
布署上面的web工程到Tomcat服务器上。
(3)接下来我们来到客户端,我们新建一个Android工程,如下:
(4)首先我们这里写了一个工具类StreamTools,如下:
1 package com.himi.httputils01; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.InputStream; 5 6 /** 7 * 流的工具类 8 * @author Administrator 9 * 10 */ 11 public class StreamTools { 12 /** 13 * 把输入流的内容转换成字符串 14 * @param is 15 * @return null解析失败, string读取成功 16 */ 17 public static String readStream(InputStream is) throws Exception { 18 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 19 byte[] buffer = new byte[1024]; 20 int len = 0; 21 while((len = is.read(buffer)) != -1) { 22 baos.write(buffer, 0, len); 23 } 24 is.close(); 25 String result = baos.toString(); 26 baos.close(); 27 return result; 28 29 30 } 31 }
(5)我们首先来到主布局文件activity_main.xml,如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:gravity="center_horizontal" 5 android:paddingLeft="10dp" 6 android:paddingRight="10dp" 7 android:orientation="vertical" > 8 9 <ImageView 10 android:layout_width="50dip" 11 android:layout_height="50dip" 12 android:src="@drawable/ic_launcher" /> 13 14 <EditText 15 android:id="@+id/et_qq" 16 android:inputType="text" 17 android:layout_width="match_parent" 18 android:layout_height="wrap_content" 19 android:hint="请输入qq号码" /> 20 21 <EditText 22 android:id="@+id/et_pwd" 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content" 25 android:hint="请输入密码" 26 android:inputType="textPassword" /> 27 28 <CheckBox 29 android:id="@+id/cb_remember" 30 android:layout_width="match_parent" 31 android:layout_height="wrap_content" 32 android:text="记住密码" 33 /> 34 35 <Button 36 android:onClick="login" 37 android:layout_width="match_parent" 38 android:layout_height="wrap_content" 39 android:text="登陆" 40 41 /> 42 </LinearLayout>
布局效果如下:
(6)接下来我们来到MainActivity,如下:
1 package com.himi.httputils01; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.InputStreamReader; 8 import java.net.MalformedURLException; 9 import java.net.URL; 10 11 import com.lidroid.xutils.HttpUtils; 12 import com.lidroid.xutils.exception.HttpException; 13 import com.lidroid.xutils.http.ResponseInfo; 14 import com.lidroid.xutils.http.callback.RequestCallBack; 15 import com.lidroid.xutils.http.client.HttpRequest; 16 17 import android.app.Activity; 18 import android.os.Bundle; 19 import android.text.TextUtils; 20 import android.util.Log; 21 import android.view.View; 22 import android.widget.CheckBox; 23 import android.widget.EditText; 24 import android.widget.Toast; 25 26 public class MainActivity extends Activity { 27 private static final String Tag = "MainActivity"; 28 private EditText et_qq; 29 private EditText et_pwd; 30 private CheckBox cb_remember; 31 32 @Override 33 protected void onCreate(Bundle savedInstanceState) { 34 super.onCreate(savedInstanceState); 35 setContentView(R.layout.activity_main); 36 // 查询关心的控件 37 et_qq = (EditText) findViewById(R.id.et_qq); 38 et_pwd = (EditText) findViewById(R.id.et_pwd); 39 cb_remember = (CheckBox) findViewById(R.id.cb_remember); 40 Log.i(Tag, "oncreate 被调用"); 41 42 // 完成数据的回显。 43 readSavedData(); 44 } 45 46 // 读取保存的数据 47 private void readSavedData() { 48 // getFilesDir() == /data/data/包名/files/ 获取文件的路径 一般系统是不会清理的。 49 // 用户手工清理,系统会有提示。 50 // getCacheDir()== /data/data/包名/cache/ 缓存文件的路径 当系统内存严重不足的时候 系统会自动的清除缓存 51 // 用户手工清理系统没有提示 52 File file = new File(getFilesDir(), "info.txt"); 53 if (file.exists() && file.length() > 0) { 54 try { 55 // FileInputStream fis = new FileInputStream(file); 56 FileInputStream fis = this.openFileInput("info.txt"); 57 BufferedReader br = new BufferedReader(new InputStreamReader(fis)); 58 // 214342###abcdef 59 String info = br.readLine(); 60 String qq = info.split("###")[0]; 61 String pwd = info.split("###")[1]; 62 et_qq.setText(qq); 63 et_pwd.setText(pwd); 64 fis.close(); 65 } catch (Exception e) { 66 e.printStackTrace(); 67 } 68 } 69 } 70 71 /** 72 * 登陆按钮的点击事件,在点击事件里面获取数据 73 * 74 * @param view 75 */ 76 public void login(View view) { 77 final String qq = et_qq.getText().toString().trim(); 78 final String pwd = et_pwd.getText().toString().trim(); 79 if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(pwd)) { 80 Toast.makeText(this, "qq号码或者密码不能为空", 0).show(); 81 return; 82 } 83 // 判断用户是否勾选记住密码。 84 if (cb_remember.isChecked()) { 85 // 保存密码 86 Log.i(Tag, "保存密码"); 87 try { 88 // File file = new File(getFilesDir(),"info.txt"); 89 // FileOutputStream fos = new FileOutputStream(file); 90 FileOutputStream fos = this.openFileOutput("info.txt", 0); 91 // 214342###abcdef 92 fos.write((qq + "###" + pwd).getBytes()); 93 fos.close(); 94 Toast.makeText(this, "保存成功", 0).show(); 95 } catch (Exception e) { 96 e.printStackTrace(); 97 Toast.makeText(this, "保存失败", 0).show(); 98 } 99 } else { 100 // 无需保存密码 101 Log.i(Tag, "无需保存密码"); 102 } 103 104 105 /** 106 * 传统方法:使用子线程访问网络 107 */ 108 /*new Thread() { 109 public void run() { 110 // String path 111 // ="http://localhost:8080/web/LoginServlet";这里不能写成localhost 112 try { 113 String path = getString(R.string.serverip); 114 URL url = new URL(path + "?qq=" + qq + "&password=" + pwd); 115 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 116 117 conn.setRequestMethod("GET"); 118 int code = conn.getResponseCode(); 119 if (code == 200) { 120 InputStream is = conn.getInputStream(); 121 String result = StreamTools.readStream(is); 122 showToastInAnyThread(result); 123 } else { 124 showToastInAnyThread("请求失败"); 125 } 126 } catch (Exception e) { 127 e.printStackTrace(); 128 showToastInAnyThread("请求失败"); 129 } 130 }; 131 132 }.start();*/ 133 134 /** 135 * 使用HttpUtils Get方式访问网络 136 */ 137 138 HttpUtils http = new HttpUtils(); 139 String path = getString(R.string.serverip); 140 URL url = null; 141 try { 142 url = new URL(path+"?qq="+ qq + "&password="+pwd); 143 } catch (MalformedURLException e) { 144 // TODO Auto-generated catch block 145 e.printStackTrace(); 146 } 147 148 http.send(HttpRequest.HttpMethod.GET, url.toString(), 149 new RequestCallBack<String>() { 150 151 @Override 152 public void onFailure(HttpException arg0, String arg1) { 153 showToastInAnyThread("提交数据失败"); 154 155 } 156 157 @Override 158 public void onSuccess(ResponseInfo<String> arg0) { 159 showToastInAnyThread("提交数据成功"); 160 161 } 162 163 }); 164 165 } 166 167 /** 168 * 显示土司 在主线程更新UI 169 * 170 * @param text 171 */ 172 public void showToastInAnyThread(final String text) { 173 runOnUiThread(new Runnable() { 174 175 @Override 176 public void run() { 177 Toast.makeText(MainActivity.this, text, 0).show(); 178 179 } 180 }); 181 } 182 }
上面使用到res/values/string.xml,如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <string name="app_name">HttpUtils01</string> 5 <string name="hello_world">Hello world!</string> 6 <string name="action_settings">Settings</string> 7 <string name="serverip">http://49.123.72.28:8088/web/LoginServlet</string> 8 9 </resources>
(7)这里需要网络权限
(8)布署程序到模拟器上,如下:
输入账号和密码,如下:
保存账号到手机内存data/data/包名/files目录下,如下:
导出info.txt,查看里面内容如下:
我们查看服务器端,说明提交数据到服务器端成功。如下:
5. 使用HttpUtils下载文件
- 支持断点续传,随时停止下载任务,开始任务
(1)开启Apache服务器,如下:
(2)在Apache服务器安装(解压)目录下htdocs存放文件夹movies,文件夹内部存放一个MP4文件,如下:
(3)新建一个Android工程,如下:
(4)首先我们来到主布局文件,如下:
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=".MainActivity" > 7 8 <Button 9 android:text="下载" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:layout_marginTop="10dip" 13 android:onClick="download" /> 14 <Button 15 android:text="取消" 16 android:layout_width="match_parent" 17 android:layout_height="wrap_content" 18 android:layout_marginTop="10dip" 19 android:onClick="cancel_download" /> 20 21 <TextView 22 android:id="@+id/tv_info" 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content" 25 android:layout_marginTop="10dip" 26 android:text="提示信息" /> 27 28 </LinearLayout>
(5)这里需要使用 网络,则在AndroidManifest.xml中添加相应的权限,如下:
<uses-permission android:name="android.permission.INTERNET"/>
(6)接着,我们来到MainActivity,如下:
1 package com.himi.httputils02; 2 3 import java.io.File; 4 5 import com.lidroid.xutils.HttpUtils; 6 import com.lidroid.xutils.exception.HttpException; 7 import com.lidroid.xutils.http.HttpHandler; 8 import com.lidroid.xutils.http.ResponseInfo; 9 import com.lidroid.xutils.http.callback.RequestCallBack; 10 11 import android.app.Activity; 12 import android.os.Bundle; 13 import android.view.View; 14 import android.widget.TextView; 15 16 public class MainActivity extends Activity { 17 18 private TextView tv; 19 20 private HttpHandler handler; 21 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 setContentView(R.layout.activity_main); 26 27 tv = (TextView) findViewById(R.id.tv_info); 28 } 29 30 public void download(View v) { 31 String download_url = getString(R.string.source_url); 32 String target_url = getString(R.string.target_url); 33 HttpUtils http = new HttpUtils(); 34 /** 35 * 下载文件方法 36 * 37 * @param url 38 * 下载文件的url 39 * @param target 40 * 下载保存的目录 41 * @param autoResume 42 * 是否自动恢复下载 43 * @param autoRename 44 * 是否自动重命名 45 * @param callback 46 * 回调 47 * @return 48 */ 49 handler = http.download(download_url, target_url, true, // 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。 50 true, // 如果从请求返回信息中获取到文件名,下载完成后自动重命名。 51 new RequestCallBack<File>() { 52 53 @Override 54 public void onStart() { 55 tv.setText("conn..."); 56 } 57 58 @Override 59 public void onLoading(long total, long current, boolean isUploading) { 60 //当然这里也可以使用进度条 61 tv.setText(current + "/" + total); 62 63 } 64 65 @Override 66 public void onSuccess(ResponseInfo<File> responseInfo) { 67 tv.setText("downloaded:" + responseInfo.result.getPath()); 68 } 69 70 @Override 71 public void onFailure(HttpException error, String msg) { 72 tv.setText(msg); 73 } 74 }); 75 } 76 77 public void cancel_download(View v){ 78 //调用cancel()方法停止下载 79 handler.cancel(); 80 tv.setText("It's canceled"); 81 } 82 83 }
(7)布署程序到模拟器上,如下:
- 点击"下载",等待下载成功。
我们追踪data/data/com.himi.httputils02/files/video.mp4,如下:
- 点击"下载",没有下载完,就点击"取消".
观察比较下载中断之后的数据和原来服务器端的数据的大小,结果如下: