1、3主要接口
Android平台有三种网络接口可以使用,他们分别是:java.net.*(标准Java接口)、Org.apache接口和Android.net.*(Android网络接口)。下面分别介绍这些接口的功能和作用。
1.1 标准Java接口
java.net.*提供与联网有关的类,包括流、数据包套接字(socket)、Internet协议、常见Http处理等。比如:创建URL,以及URLConnection/HttpURLConnection对象、设置链接参数、链接到服务器、向服务器写数据、从服务器读取数据等通信。这些在Java网络编程中均有涉及,我们看一个简单的socket编程,实现服务器回发客户端信息。
1.2 Apache接口
对于大部分应用程序而言JDK本身提供的网络功能已远远不够,这时就需要Android提供的Apache HttpClient了。它是一个开源项目,功能更加完善,为客户端的Http编程提供高效、最新、功能丰富的工具包支持。
1.3 android.net编程:
常常使用此包下的类进行Android特有的网络编程,如:访问WiFi,访问Android联网信息,邮件等功能。
2、Http两访问方式:HttpURLConnection(java.net.)、HttpClient(org.apache.http.client.)
2.1 HttpURLConnection
HttpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它。
不过在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能:
private void disableConnectionReuseIfNecessary() { // 这是一个2.2版本之前的bug if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { System.setProperty("http.keepAlive", "false"); } }
2.2 HttpClient
DefaultHttpClient和它的兄弟AndroidHttpClient都是HttpClient具体的实现类,它们都拥有众多的API,而且实现比较稳定,bug数量也很少。但同时也由于HttpClient的API数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。
2.3 小结:
This API(HttpURLConnection) is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption.
Android6.0已经将HttpClient移除,官方给出的解释如上,在我看来不外乎效率和扩展两方面考虑,但HttpClient毕竟是Apache提供的一个不错的API,所以有必要将HttpURLConnection,HttpClient进行比较,让我们在对比中感受他们各自的特点。
A 对比观点一 http://blog.csdn.net/wszxl492719760/article/details/8522714
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能:HttpURLConnection。
HttpURLConnection是java的标准类,HttpURLConnection继承自URLConnection,可用于向指定网站发送GET请求、POST请求。它在URLConnection的基础上提供了如下便捷的方法:
int getResponseCode():获取服务器的响应代码。
String getResponseMessage():获取服务器的响应消息。
String getResponseMethod():获取发送请求的方法。
void setRequestMethod(String method):设置发送请求的方法。
在一般情况下,如果只是需要Web站点的某个简单页面提交请求并获取服务器响应,HttpURLConnection完全可以胜任。但在绝大部分情况下,Web站点的网页可能没这么简单,这些页面并不是通过一个简单的URL就可访问的,可能需要用户登录而且具有相应的权限才可访问该页面。在这种情况下,就需要涉及Session、Cookie的处理了,如果打算使用HttpURLConnection来处理这些细节,当然也是可能实现的,只是处理起来难度就大了。
为了更好地处理向Web站点请求,包括处理Session、Cookie等细节问题,Apache开源组织提供了一个HttpClient项目,看它的名称就知道,它是一个简单的HTTP客户端(并不是浏览器),可以用于发送HTTP请求,接收HTTP响应。但不会缓存服务器的响应,不能执行HTML页面中嵌入的Javascript代码;也不会对页面内容进行任何解析、处理。
简单来说,HttpClient就是一个增强版的HttpURLConnection,HttpURLConnection可以做的事情HttpClient全部可以做;HttpURLConnection没有提供的有些功能,HttpClient也提供了,但它只是关注于如何发送请求、接收响应,以及管理HTTP连接。
使用HttpClient发送请求、接收响应很简单,只要如下几步即可。
- 创建HttpClient对象。
- 如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
- 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
- 调用HttpClient对象的execute(HttpUriRequest request)发送请求,执行该方法返回一个HttpResponse。
- 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
比如一个Android应用需要向指定页面发送请求,但该页面并不是一个简单的页面,只有当用户已经登录,而且登录用户的用户名有效时才可访问该页面。如果使用HttpURLConnection来访问这个被保护的页面,那么需要处理的细节就太复杂了。
其实访问Web应用中被保护的页面,使用浏览器则十分简单,用户通过系统提供的登录页面登录系统,浏览器会负责维护与服务器之间的Sesion,如果用户登录的用户名、密码符合要求,就可以访问被保护资源了。
在Android应用程序中,则可使用HttpClient来登录系统,只要应用程序使用同一个HttpClient发送请求,HttpClient会自动维护与服务器之间的Session状态,也就是说程序第一次使用HttpClient登录系统后,接下来使用HttpClient即可访问被保护页而了。
B 对比观点二 http://blog.csdn.net/huzgd/article/details/8712187
1.HttpClient是apache的开源实现,而HttpUrlConnection是安卓标准实现;
2.HttpUrlConnection直接支持GZIP压缩;HttpClient也支持,但要自己写代码处理;我们之前测试HttpUrlConnection的GZIP压缩在传大文件分包trunk时有问题,只适合小文件,不过这个BUG后来官方说已经修复了;
3.HttpUrlConnection直接支持系统级连接池,即打开的连接不会直接关闭,在一段时间内所有程序可共用;HttpClient当然也能做到,但毕竟不如官方直接系统底层支持好;
4.HttpUrlConnection直接在系统层面做了缓存策略处理,加快重复请求的速度。
在安卓开发上,虽然HttpClient更好地支持很多细节的控制(如代理、COOKIE、鉴权、压缩、连接池),但相应地对开发人员要求更高,代码写起来更复杂,普通开发人员很难做到对它很好地驾驭,官方的支持也越来越少;而HttpUrlConnection对大部分工作进行了包装,屏蔽了不需要的细节,更适合开发人员直接调用,而且官方对它的支持和优化也会越来越好。我们既然是做安卓应用的开发,自然要遵循安卓官方的指引,选用HttpUrlConnection。
2.4 HTTP通信 GET/POST DEMO
1 HttpUrlConnection通信GET方式
public static String loginByURLGet(String path, String username, String password) { String str = null; try { // 拼接路径 path += "?username=" + URLEncoder.encode(username, "UTF-8") + "&password=" + URLEncoder.encode(password); URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); // 请求成功 if (200 == conn.getResponseCode()) { InputStream is = conn.getInputStream(); str = StreamTools.readInputStream(is); } } catch (Exception e) { e.printStackTrace(); } return str; }
2 HttpUrlConnection通信POST方式
public static String loginByURLPost(String path, String username, String password) { String str = null; try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("POST"); // 传参 String data = "username" + URLEncoder.encode(username) + "&password" + URLEncoder.encode(password); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setRequestProperty("Content-Length", data.length() + ""); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.write(data.getBytes()); // 请求成功 if (200 == conn.getResponseCode()) { InputStream is = conn.getInputStream(); str = StreamTools.readInputStream(is); } } catch (Exception e) { e.printStackTrace(); } return str; }
3 HttpClient通信GET方式
public static String loginByApacheGet(String path, String username, String password) { String str = null; try { HttpClient client = new DefaultHttpClient(); path += "?username=" + URLEncoder.encode(username, "UTF-8") + "&password=" + URLEncoder.encode(password); HttpGet httpGet = new HttpGet(path); HttpResponse response = client.execute(httpGet); // 请求成功 if (200 == response.getStatusLine().getStatusCode()) { InputStream is = response.getEntity().getContent(); str = StreamTools.readInputStream(is); } } catch (Exception e) { e.printStackTrace(); } return str; }
4 HttpClient通信POST方式
public static String loginByApachePost(String path, String username, String password) { String str = null; try { HttpClient client = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(path); // 传参 List<NameValuePair> parameters = new ArrayList<NameValuePair>(); parameters.add(new BasicNameValuePair("username", username)); parameters.add(new BasicNameValuePair("password", password)); httpPost.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8")); HttpResponse response = client.execute(httpPost); // 请求成功 if (200 == response.getStatusLine().getStatusCode()) { InputStream is = response.getEntity().getContent(); str = StreamTools.readInputStream(is); } } catch (Exception e) { e.printStackTrace(); } return str; }
StreamTools.readInputStream();
public static String readInputStream(InputStream is) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } is.close(); baos.close(); byte[] result = baos.toByteArray(); // 试着解析result里的字符串 String temp = new String(result, "gbk"); return temp; } catch (Exception e) { e.printStackTrace(); return "获取失败"; } }
3、其他通信方式
HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生:
比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。
再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
总的来说,数据量不大,但网络通信频繁的应用,非常适合使用Volley。
3.1 AsyncHttpClient
核心类,使用HttpClient执行网络请求,提供了get,put,post,delete,head等请求方法,使用起来很简单,只需以url及RequestParams调用相应的方法即可,还可以选择性地传入Context,用于取消Content相关的请求,同时必须提供ResponseHandlerInterface(AsyncHttpResponseHandler继承自ResponseHandlerInterface)的实现类,一般为AsyncHttpResponseHandler的子类,AsyncHttpClient内部有一个线程池,当使用AsyncHttpClient执行网络请求时,最终都会调用sendRequest方法,在这个方法内部将请求参数封装成AsyncHttpRequest(继承自Runnable)交由内部的线程池执行。
步骤
- 创建一个AsyncHttpClient;
- (可选的)通过RequestParams对象设置请求参数;
- 调用AsyncHttpClient的某个get方法,传递你需要的(成功和失败时)callback接口实现,一般都是匿名内部类,实现了AsyncHttpResponseHandler,类库自己也提供了好些现成的response handler,你一般不需要自己创建一个。
特点
- 发送异步http请求,在匿名callback对象中处理response;
- http请求发生在UI线程之外;
- 内部采用线程池来处理并发请求;
- GET/POST 参数构造,通过RequestParams类。
- 内置多部分文件上传,不需要第三方库支持;
- 流式Json上传,不需要额外的库;
- 能处理环行和相对重定向;
- 和你的app大小相比来说,库的size很小,所有的一切只有90kb;
- 自动智能的请求重试机制在各种各样的移动连接环境中;
- 自动的gzip响应解码;
- 内置多种形式的响应解析,有原生的字节流,string,json对象,甚至可以将response写到文件中;
- 永久的cookie保存,内部实现用的是Android的SharedPreferences;
- 通过BaseJsonHttpResponseHandler和各种json库集成;
- 支持SAX解析器;
- 支持各种语言和content编码,不仅仅是UTF-8。
DEMO
AsyncHttpClient通信Get方式
AsyncHttpClient client = new AsyncHttpClient(); client.get("http://www.google.com", new AsyncHttpResponseHandler() { @Override public void onStart() { // called before request is started } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { // called when response HTTP status is "200 OK" } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { // called when response HTTP status is "4XX" (eg. 401, 403, 404) } @Override public void onRetry(int retryNo) { // called when request is retried } });
AsyncHttpClient通信Post方式
AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("key", "value"); params.put("more", "data"); client.post("http://www.google.com", params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { System.out.println(response); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Log.d("ERROR", error); } } );
3.2 Universal-Image-Loader
特点:
- 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
- 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
- 支持图片的内存缓存,文件系统缓存或者SD卡缓存
- 支持图片下载过程的监听
- 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
- 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
- 提供在较慢的网络下对图片进行加载
DEMO1
final ImageView mImageView = (ImageView) findViewById(R.id.image); String imageUrl = "http://upload.ct.youth.cn/2016/0416/1460802358119.jpg"; ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() { @Override public void onLoadingStarted(String imageUri, View view) { } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { } @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { mImageView.setImageBitmap(loadedImage); } @Override public void onLoadingCancelled(String imageUri, View view) { } });
DEMO2
File cacheDir = StorageUtils.getCacheDirectory(context); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .memoryCacheExtraOptions(480, 800) // default = device screen dimensions .diskCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null) .taskExecutor(...) .taskExecutorForCachedImages(...) .threadPoolSize(3) // default .threadPriority(Thread.NORM_PRIORITY - 1) // default .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) .memoryCacheSize(2 * 1024 * 1024) .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiscCache(cacheDir)) // default .diskCacheSize(50 * 1024 * 1024) .diskCacheFileCount(100) .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default .imageDownloader(new BaseImageDownloader(context)) // default .imageDecoder(new BaseImageDecoder()) // default .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default .writeDebugLogs() .build();
3.3 volley http://www.tuicool.com/articles/eeyQ3eE
特点
- 自动调度网络请求
- 多个并发的网络连接
- 通过使用标准的HTTP缓存机制保持磁盘和内存响应的一致
- 支持请求优先级
- 支持取消请求的强大API,可以取消单个请求或多个
- 易于定制
- 健壮性:便于正确的更新UI和获取数据
- 包含调试和追踪工具
优点:
- 默认Android2.3及以上基于HttpURLConnection,2.3以下使用基于HttpClient;
- 符合Http 缓存语义 的缓存机制(提供了默认的磁盘和内存等缓存);
- 请求队列的优先级排序;
- 提供多样的取消机制;
- 提供简便的图片加载工具(其实图片的加载才是我们最为看重的功能);
- 一个优秀的框架 。
缺点:它只适合数据量小,通信频繁的网络操作,如果是数据量大的,像音频,视频等的传输,还是不要使用Volley的为好。
3.4 Retrofit,OkHttp,NoHttp
- Retrofit: A type-safe REST client for Android and Java Retrofit简化了从Web API下载数据,解析成普通的Java对象(POJO)。
- OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求。Retrofit使用GSON解析JSON数据。OKHttp与HttpUrlConnection一样,都是面向java的,而且是做socket层的事情的,使用时要在子线程调用,通过handler发送结果到主线程。
- 而NoHttp和Volley不是做socket层的东西。直接在主线程就可以调用,拿到结果后直接更新UI,不需要用handler去发送, 很简单。
NoHttp:封装了文件下载、断点续传、304缓存、302/303传参数、传文件、请求头、多文件上传、大文件上传、Cookie自动管理等多种功能,这些是Volley而没有,使用Volley时这些功能要我们去写蛮多代码来再次封装。而且Volley用的HttpClient来解析的,Android6.0删除了HttpClient后,我们在6.0下也不能使用Volley的源码了,所以还是用NoHttp吧,NoHttp兼容2.0-6.0以上。而使用OkHttp还需要我们自己去封装, 而且Android4.4之后NoHttp也是使用OkHttp做底层的。
Retrofit:和OkHttp都是square团队开发的。Retrofit是一套RESTful架构的Android(Java)客户端实现,基于注解,提供JSON to POJO(Plain Ordinary Java Object,简单Java对象),POJO to JSON,网络请求(POST,GET,PUT,DELETE等)封装。
Retrofit 和Java领域的ORM概念类似, ORM把结构化数据转换为Java对象,而Retrofit 把REST API返回的数据转化为Java对象方便操作。同时还封装了网络代码的调用。
Retrofit功能组件
- POJO或模型实体类 : 从服务器获取的JSON数据将被填充到这种类的实例中。
- 接口 : 我们需要创建一个接口来管理像GET,POST...等请求的URL,这是一个服务类。
- RestAdapter类 : 这是一个REST客户端(RestClient)类,retrofit中默认用的是Gson来解析JSON数据,也可以设置自己的JSON解析器,比如jackson
Retrofit使用步骤:
- 定义接口,参数声明,Url都通过Annotation指定
- 通过
RestAdapter
生成一个接口的实现类(动态代理) - 调用接口请求数据
涉及重要知识点
- 动态代理
- 注解
- Handler + MessageQueue + Thread + Looper机制
- OKHttp请求网络
- GSON用来转换Java POJO和解析JSON
使用技术
- Retrofit非常巧妙的用注解来描述一个HTTP请求,将一个HTTP请求抽象成一个Java接口,然后用了Java动态代理的方式,动态的将这个接口的注解“翻译”成一个HTTP请求,最后再执行这个HTTP请求
- Retrofit的功能非常多的依赖Java反射,代码中其实还有很多细节,比如异常的捕获、抛出和处理,大量的Factory设计模式(为什么要这么多使用Factory模式?)
- Retrofit中接口设计的恰到好处,在你创建
Retrofit
对象时,让你有更多更灵活的方式去处理你的需求,比如使用不同的Converter
、使用不同的CallAdapter
,这也就提供了你使用RxJava来调用Retrofit的可能
http://www.jb51.net/article/74747.htm
http://www.kwstu.com/ArticleView/kwstu_20144118313429
http://www.cnblogs.com/angeldevil/p/3729808.html
http://www.2cto.com/kf/201408/326552.html
http://www.cnblogs.com/lichenwei/p/4651576.html
http://www.bkjia.com/Androidjc/995850.html
http://www.tuicool.com/articles/26jUZjv