Android开发中常用网络框架例举综合
2016-10-19 17:09
573 查看
Android开发中常用网络框架例举综合
本篇简单总结各个框架的使用,以Get请求、JSON解析、图片加载为例。分别使用6个框架HttpURLConnection、HttpClient、AndroidAsyncHttp、Volley、OkHttp、Retrofit2(排序根据提出的时间和学习的顺序)
1.HttpURLConnection
HttpURLConnection是较为基础的网络框架,是Android6.0以后版本默认的底层网络。(同步的,需要自己封装线程)
static String host_address = "http://10.0.2.2:8080/listdata/"; /** * 根据指定的Url来获取byte数据 */ public static byte[] getData(String path) { path = host_address + path; byte[] data = null; URL url = null; try { // 1.创建url对象 url = new URL(path); // 2.开启链接引用 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // 3.设置链接事件 urlConnection.setReadTimeout(5000); urlConnection.setConnectTimeout(5000); urlConnection.setRequestMethod("GET"); // 4.连接成功获取数据 if (urlConnection.getResponseCode() == 200) { InputStream is = urlConnection.getInputStream(); data = BytesUtil.getBytes(is); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return data; } /** * 获取字符串 */ public static String getString(String path) { byte[] data = getData(path); try { return new String(data, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 获取bitmap */ public static Bitmap getBitmap(String path) { byte[] data = getData(path); Bitmap sBitmap = BitmapFactory.decodeByteArray(data, 0, data.length); return sBitmap; } /** * 设置对应imageview的bitmap,注意listview的复用问题 */ public static void setViewImage(final ImageView view, final String path) { // 打上标记防止复用view时造成图片加载混乱 view.setTag(path); new Thread() { public void run() { final Bitmap bitmap = getBitmap(path); view.post(new Runnable() { public void run() { //核对标记的一致 if (view.getTag().equals(path)) view.setImageBitmap(bitmap); } }); } }.start(); }
2.HttpClient
HttpClient是Apache提供的已经高度封装的网络请求端,在使用中他可以看作是一个网络客户端。(同步的,需要自己封装线程,支持回调处理)
添加jar包:
在sdk路径中 ~\platforms\android-23\optional\org.apache.http.legacy.jar
static String host_address = "http://10.0.2.2:8080/listdata/"; /** * 请求网络获取数据 */ public static byte[] getData(String path) { byte[] execute = null; // 1.一个默认的httpclient DefaultHttpClient client = new DefaultHttpClient(); // 2.创建一个get请求httpGet HttpGet httpGet = new HttpGet(host_address + path); try { // 3.httpclient执行这个请求 HttpResponse response = client.execute(httpGet); // 4.判断响应状态 int responseCode = response.getStatusLine().getStatusCode(); if (responseCode == HttpStatus.SC_OK) { // 5.HttpEntity响应内容 HttpEntity entity = response.getEntity(); // 6.响应体中获取流对象 execute = BytesUtil.getBytes(entity.getContent()); } } catch (IOException e) { e.printStackTrace(); } return execute; } //String解析,图片解析,方式与HttpUrlConnection相同
其在使用时的流程为下:
3.Android-Async-Http
AsyncHttp是一个支持异步的框架,其内部进行的封装使得用起来非常简单,但让代码结构看起来很差,会让网络设计的代码与UI部分混在一起。注意Asnyc-Http与AsyncTask<Params, Progress, Result>并非同一个事物,初学者在这里会混淆。添加Module:
compile ‘com.loopj.android:android-async-http:1.4.9’
// 在应用中应全局使用一个Client避免不必要的重复 AsyncHttpClient sClient = new AsyncHttpClient(); // 使用非常简单,仅仅调取sClient的get方法即可实现一个网络请求 // 通过添加处理回调的方式实现异步 sClient.get(host_address + url,new AsyncHttpResponseHandler() { // 连接成功时的回调,responseBody即为响应流中的数据 public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { mListData.addAll(JsonUtil.parse(ListData.class, new String(responseBody)).list); mInnerAdapter.notifyDataSetChanged(); } // 连接失败的回调 public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { error.printStackTrace(); } });
AsyncHttp已经提供了很多Hanlder供开发者使用,默认的有:
4.Volley
Volley是官方提供的网络解析框架,其底层使用了HttpURLConnection。其具备AsyncHttp和ImageLoader的特点,支持异步加载并采用回调,支持网络缓存,并提供支持缓存管理的ImageLoader,但是缓存需要我们自己完成,下面有使用样例。添加Module:
compile ‘eu.the4thfloor.volley:com.android.volley:2015.05.28’
在使用前需要初始化一个Volley的处理队列
//他必须在Application中声明 public class MyApplication extends Application { private static RequestQueue mRequestQueue; @Override public void onCreate() { super.onCreate(); // 为volley声明一个队列 mRequestQueue = Volley.newRequestQueue(this); } public static RequestQueue getRequestQueue() { return mRequestQueue; } }
1.像AsyncHttp那样拿到数据再解析再处理,Volley中请求需要被封装为一个Request对象,并在其中实现对Response的处理封装。
static String host_address = "http://10.0.2.2:8080/listdata/"; /** * 使用自定义request的方式去获取json数据,不会有乱码 */ public static void getData(String url, final List<ListData.Data> dataList, final BaseActivity.InnerAdapter adapter) { // 1.使用自定义实现Request,参数中null为ErrorListener可以不处理 Request<String> request = new Request<String>(Request.Method.GET, host_address + url, null) { // 2.网络数据解析过程,通过Response的Api可以获取一个默认的封装 protected Response<String> parseNetworkResponse(NetworkResponse response) { byte[] data = response.data; // 3.Entry是指定缓存类型中的条目,注意这里如果不想缓存可取消缓存 return Response.success(new String(data), HttpHeaderParser.parseCacheHeaders(response)); } // 3.解析结果的处理 protected void deliverResponse(String response) { ListData parse = JsonUtil.parse(ListData.class, response); dataList.addAll(parse.list); adapter.notifyDataSetChanged(); } }; // 取消缓存 // request.setShouldCache(false); sRequestQueue.add(request); }
2.使用默认的StringRequest处理json数据
public static void getString(String url, final List<ListData.Data> dataList, final BaseActivity.InnerAdapter innerAdapter) { // 使用默认的StringRequest需要添加响应成功的监听和失败的监听 sRequestQueue.add( new StringRequest(Request.Method.GET, host_address + url, new Response.Listener<String>() { // 重写该方法,实现对String结果的处理 public void onResponse(String response) { ListData parse = JsonUtil.parse(ListData.class, response); dataList.addAll(parse.list); innerAdapter.notifyDataSetChanged(); } }, new Response.ErrorListener() { // 重写该方法实现对异常情况的处理 public void onErrorResponse(VolleyError error) { error.printStackTrace(); Log.e("tag", "error"); } }) { //重写StringRequst中文字解析的过程,修复文字乱码的问题 protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { // 源码中的文字编码是获取自网络响应头中的,与U8不同时会造成乱码 // parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); parsed = new String(response.data, "UTF-8"); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } }); }
3.使用默认的ImageRequest加载图片
/** * 使用与StringRequest相同,但低效率,很慢,画质差 */ public static void getViewImage_request(final ImageView imageView, final String url) { // 设置标记进行校验,防止listview复用造成图片错位 imageView.setTag(url); sRequestQueue.add(new ImageRequest(host_address + url, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { // 校验标记 if (imageView.getTag().equals(url)) imageView.setImageBitmap(response); } }, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() { public void onErrorResponse(VolleyError error) { // empty } })); }
4.采用ImageLoader的方式来管理图片加载
ImageLoader(RequestQueue queue, ImageCache imageCache) // ImageLoader的构造方法
ImageLoader需要提供一个imagecache作为缓存处理的方式,但imagecache中是如何处理缓存的由我们来实现,这里采用lrucache集合的形式在内存中缓存,当然也可以使用其他想要的缓存方式。
private static ImageLoader.ImageCache sImageCache; private static LruCache<String, Bitmap> sLruCache; private static ImageLoader sImageLoader; public static void getViewImage_loader(String url, ImageView imageView) { // volley没有实现默认的缓存,需要我们自己实现 // 1.初始化一个默认大小的内存缓存 if (sLruCache == null) { sLruCache = getLruCache(); } // 2.将对应的bitmap缓存存取方式进行封装 if (sImageCache == null) sImageCache = new ImageLoader.ImageCache() { @Override public Bitmap getBitmap(String url) { return sLruCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { sLruCache.put(url, bitmap); } }; // 3.根据已经创建好的imageCache和requestQueue来初始化一个新的imageLoader if (sImageLoader == null) sImageLoader = new ImageLoader(MyApplication.getRequestQueue(), sImageCache); // 4.为对应的imageView生成一个默认的imageListener,设置初始图片和失败图片 ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher); // 5.使用ImageLoader的get请求这个加载,内部仍然是ImageRequest sImageLoader.get(host_address + url, listener); } /** * 获取一个LruCache,最近最少使用算法也是较为容易理解的一种算法 */ private static LruCache getLruCache() { long maxMemory = Runtime.getRuntime().maxMemory(); long cacheSize = maxMemory / 8; sLruCache = new LruCache<String, Bitmap>((int) (cacheSize / 1024)) { protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024; } }; return sLruCache; }
5.OkHttp
OkHttp是现在较为流行的网络框架之一,他与HttpClient的相似之处在于都可将网络看作一个Client,并通过Client执行一个封装的request再从执行的结果Response中获取数据。但不同的是,OkHttp中Client并非直接execute而是newCall返回一个Call对象,在Call对象中我们可以使用同步的方式处理或者异步的方式处理,并且可以控制这条请求的开关call.cancel()。
添加Module:
compile ‘com.squareup.okhttp:okhttp:2.0.0’
static String host_address = "http://10.0.2.2:8080/listdata/"; public static OkHttpClient mClient = new OkHttpClient(); /** * OKHttp用法与HttpClient类似 */ public static byte[] getData(String url) throws IOException { // 1.通过Builder建造 Request Request.Builder builder = new Request.Builder(); // 2.链式编程设置url和请求方式 builder.url(host_address + url). get(); // 3.建造出指定的request Request request = builder.build(); // 4.获取request已经实现了CallFactory工厂,使用其进行生产 Call call = mClient.newCall(request); // 5.执行对应的call获取响应对象(同步) Response response = call.execute(); // 6.判断响应状态 if (response.code() == 200) { // 7.获取响应体 ResponseBody body = response.body(); // 8.直接获取相应体中数据,也可以获取流对象,只有输入流 return body.bytes(); } return null; } //String解析,图片解析,方式与HttpUrlConnection相同
异步方式,通过给call添加回调来处理结果
call.enqueue(new Callback() { public void onFailure(Request request, IOException e) { // empty } public void onResponse(Response response) throws IOException { // TODO } });
OkHttp的执行流程:
6.Retrofit2
Retrofit经常与OkHttp搭配使用,其采用注解的方式简化网络请求代码的书写(此处有坑),并支持常规的callback方式,也支持observer的RxJava模式。(反正就是很牛,因为是初学所以本篇只是简单使用了一下,体现出怎么解析json数据、图片加载,并与前面几种方式形成对比)。添加Module:
compile 'com.squareup.retrofit2:retrofit:2.1.0'//Retrofit2所需要的包 compile 'com.squareup.retrofit2:converter-gson:2.1.0'//ConverterFactory的Gson依赖包 compile 'com.squareup.retrofit2:converter-scalars:2.1.0'//ConverterFactory的String依赖包 compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' //RxJavaCallAdapter依赖包 compile 'io.reactivex:rxandroid:1.2.1' // RxAndroid依赖包
1.配置一个全局的Retrofit,这一点与前面几个方法很相似
private static Retrofit sRetrofit; private static Retrofit getRetrofit() { // 1.初始化一个建造者 Retrofit.Builder builder = new Retrofit.Builder(); // 2.添加主机地址 builder.baseUrl(HttpUrl.parse("http://10.0.2.2:8080")) // .client(mOkHttpClient)可以使用指定的OkHttpClient // 3.添加数据转换工厂 .addConverterFactory(ScalarsConverterFactory.create())// 处理基本数据类型 .addConverterFactory(GsonConverterFactory.create())// 处理gson数据类型 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// 添加回调的适配器,RxJava的回调形式(即非callback的形式); // 4.生成配置好的retrofit return builder.build(); }
2.将对应的服务器api接口封装为本地接口,这里方法返回Call对象方便使用和理解,Observable对象是RxJava中使用到的,但也可以使用Call的形式进行处理
public interface ListDataService { @GET("/listdata/{datapath}") Call<ListData> getListData(@Path("datapath") String path); // (坑!)BUG:这里采用了切割,因为Retrofit将链接中的"/"转义为"%2F"造成请求失败 错误码400 @GET("/listdata/app/{package}/{icon}") Observable<ResponseBody> getBitmap(@Path("package") String packageName, @Path("icon") String icon); }
3.将本地接口生成对应的实例
private static ListDataService sService; /** * 根据已经构造的服务,获取api的接口服务实例 */ public static ListDataService getService() { // 1.获取retrofit if (sRetrofit == null) sRetrofit = getRetrofit(); // 2.使用retrofit创建对应api的接口 if(sService == null) sService = sRetrofit.create(ListDataService.class); return sService; }
4.使用接口中的方法
使用返回的Call对象,采用异步的方式执行,当然也可以使用同步的方式(与OkHttp中的execute)。
Call对象的用法OkHttp中的Call对象相同。
解析Json数据
public static void getListData(String path, Callback<ListData> callback) { // 1.检查是否有sService if (sService == null) sService = getService(); // 2.调用接口方法,获取Call Call<ListData> listdata = sService.getListData(path); // 3.执行Call并为其添加回调 listdata.enqueue(callback); // 同步 // listdata.execute().body(); }
解析图片数据,这里使用了RxJava的回调形式
public static void setViewImage(String path, final ImageView view) { // 1.检查是否有sService if (sService == null) sService = getService(); // 切割字符串避免"/"被转义 String[] split = path.split("/"); String packageName = split[1]; String icon = split[2]; // 2.实现retrofit的图片加载 Observable<ResponseBody> bitmap = sService.getBitmap(packageName, icon); bitmap.subscribeOn(Schedulers.io()) // 设置注册观察者的线程 .observeOn(AndroidSchedulers.mainThread())// 设置观察者响应的线程,要添加RxAndroid .subscribe(new Observer<ResponseBody>() { // 注册观察者 @Override public void onCompleted() { // 在所有的next事件都被执行了之后 Log.i("RxJava","onCompleted"); } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(ResponseBody responseBody) { view.setImageBitmap(BitmapFactory.decodeStream(responseBody.byteStream())); } }); }
更多Retrofit详情:
Retrofit 2.0 自定义Converter、
Retrofit用法详解
更多RxJava详情:
给 Android 开发者的 RxJava 详解、
深入浅出RxJava(一:基础篇)
演示
样例:相关文章推荐
- android游戏开发框架libgdx的使用(五)--舞台和常用UI类
- Android开发-常用工具方法(dp转成px、网络是否可用、是否3G网络、Gps是否打开、判断手机号码等)
- Android网络开发框架
- 上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一)
- 常用Android快速开发框架
- 使用 Android快速开发框架 Afinal 0.3 快速开发网络应用相关APK
- Android 网络开发框架的选择
- android 开发 常用到的一些网络通信包
- Android快速开发框架Android_BaseLib,集成了常用工具类,自定义View控件,Base基类封装,常用开源框架
- android 开发 常用到的一些网络通信包
- Android开发中4个常用的工具类【Toast、SharedPreferences、网络及屏幕操作】
- Android开发中的常用开源框架
- Android 网络开发框架的选择
- android 开发 常用到的一些网络通信包选择
- 常用IOS网络开发框架
- [Android开发常见问题-20] Android 网络通信框架Volley简介(Google IO 2013)
- Android 网络开发框架的选择
- Android比较全面的应用开发框架(涉及网络,数据库,缓存,下载管理等)
- android常用开发框架
- Android网络开发框架