Android开发中常用网络框架例举综合

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(一:基础篇)

演示


样例:

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1) JSON,图像等的异步下载; (2) 网络请求的排序(scheduling) (3) 网络请求的优先级处理 (4) 缓存 (5) 多级别取消请求 (6) 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求) 2、android-async-http 项目地址:https://github.com/loopj/android-async-http 文档介绍:http://loopj.com/android-async-http/ (1) 在匿名回调处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences 3、Afinal框架 项目地址:https://github.com/yangfuhai/afinal 主要有四大模块: (1) 数据库模块:android的orm框架使用了线程池对sqlite进行操作。 (2) 注解模块:android的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。 (3) 网络模块:通过httpclient进行封装http数据请求,支持ajax方式加载,支持下载、上传文件功能。 (4) 图片缓存模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程出现的oom和android容器快速滑动时候出现的图片错位等现象。 FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法, 没有使用弱引用(android2.3以后google已经不建议使用弱引用,android2.3后强行回收软引用和弱引用,详情查看android官方文档), 更好的管理bitmap内存。FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器, 在imageview显示图片的时候播放动画等(默认是渐变动画显示)。 4、xUtils框架 项目地址:https://github.com/wyouflf/xUtils 主要有四大模块: (1) 数据库模块:android的orm框架,一行代码就可以进行增删改查; 支持事务,默认关闭; 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名); 支持绑定外键,保存实体时外键关联实体自动保存或更新; 自动加载外键关联实体,支持延时加载; 支持链式表达查询,更直观的查询语义,参考下面的介绍或sample的例子。 (2) 注解模块:android的ioc框架,完全注解方式就可以进行UI,资源和事件绑定; 新的事件绑定方式,使用混淆工具混淆后仍可正常工作; 目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。 (3) 网络模块:支持同步,异步方式的请求; 支持大文件上传,上传大文件不会oom; 支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求; 下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件; 返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。 (4) 图片缓存模块:加载bitmap的时候无需考虑bitmap加载过程出现的oom和android容器快速滑动时候出现的图片错位等现象; 支持加载网络图片和本地图片; 内存管理使用lru算法,更好的管理bitmap内存; 可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等... 5、ThinkAndroid 项目地址:https://github.com/white-cat/ThinkAndroid 主要有以下模块: (1) MVC模块:实现视图与模型的分离。 (2) ioc模块:android的ioc模块,完全注解方式就可以进行UI绑定、res的资源的读取、以及对象的初始化。 (3) 数据库模块:android的orm框架使用了线程池对sqlite进行操作。 (4) http模块:通过httpclient进行封装http数据请求,支持异步及同步方式加载。 (5) 缓存模块:通过简单的配置及设计可以很好的实现缓存,对缓存可以随意的配置 (6) 图片缓存模块:imageview加载图片的时候无需考虑图片加载过程出现的oom和android容器快速滑动时候出现的图片错位等现象。 (7) 配置器模块:可以对简易的实现配对配置的操作,目前配置文件可以支持Preference、Properties对配置进行存取。 (8) 日志打印模块:可以较快的轻易的是实现日志打印,支持日志打印的扩展,目前支持对sdcard写入本地打印、以及控制台打印 (9) 下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。 (10) 网络状态检测模块:当网络状态改变时,对其进行检 6、LoonAndroid 项目地址:https://github.com/gdpancheng/LoonAndroid 主要有以下模块: (1) 自动注入框架(只需要继承框架内的application既可) (2) 图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性) (3) 网络请求模块(继承了基本上现在所有的http请求) (4) eventbus(集成一个开源的框架) (5) 验证框架(集成开源框架) (6) json解析(支持解析成集合或者对象) (7) 数据库(不知道是哪位写的 忘记了) (8) 多线程断点下载(自动判断是否支持多线程,判断是否是重定向) (9) 自动更新模块 (10) 一系列工具类

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值