美文网首页安卓网络
iOS转android之网络封装

iOS转android之网络封装

作者: 移动端_小刚哥 | 来源:发表于2019-01-07 16:39 被阅读6次

    在移动端开发中和基础架构同样重要的是网络封装,包括对JSON数据的处理。Android中有很多好用的网络请求工具,这里我选择的是OkHttp

    一、网络配置文件

    新建单例类NetWorkManager,这个类的功能是创建一个全局唯一的OkHttpClient,每次网络请求都使用这个OkHttpClient类来创建一个Call类,每个Call对象只能进行一次网络请求。如果每次网络请求都创建OkHttpClient会造成资源的极大浪费。在这个单例类中可以对OkHttpClient单例对象配置超时时间、请求头、编码格式等基础配置,还可以实现动态修改超时时间,取消某个网络请求等功能。

    /**
     * 一、网络请求相关的配置,包括超时时间、请求头等
     * 二、生成OkHttpClient单例对象,并且以次单例对象生成Call对象进行网络请求
     */
    public class NetWorkManager {
    
        private static int mConnectTimeout = 10000; //默认连接超时时间10秒=10000毫秒
        private static int mReadTimeout = 10000; //默认读取超时时间10秒=10000毫秒
        private static int mWriteTimeout = 10000; //默认写入超时时间10秒=10000毫秒
    
        /**
         * 存放当前正在网络请求的call们,以备后续进行取消等操作
         */
        private static ArrayList<Call> callList = new ArrayList<Call>();
    
    
        /**
         * 声明OkHttp的客户端类
         */
        private static volatile OkHttpClient mOkHttpClient = null;
    
    
        /**
         * 私有化构造方法防止外部创建
         */
        private NetWorkManager(){}
    
    
        /**
         * 定义类型变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时mNetWorkManager变量的可见性,
         * 避免了mNetWorkManager初始化时其他变量属性还没有赋值完时被另外线程调用)
         */
        private static volatile NetWorkManager mNetWorkManager = null;
    
    
    
    
        /**
         * 通过OkHttpClient的单例对象创造一个call对象进行本次网络请求
         * @param url 地址
         * @param map 参数map
         * @param method GET/POST
         * @return
         */
        public static Call getInstance( String url, HashMap<String,Object> map, String method){
    
            /**
             * 对象实例化时调用,不使用同步代码块,mNetWorkManager!=null时直接返回对象,提高运行效率
             */
            if (mNetWorkManager == null){
                synchronized (NetWorkManager.class){
                    //未初始化时,初始化mNetWorkManager对象
                    if (mNetWorkManager == null){
                        mNetWorkManager = new NetWorkManager();
                        mOkHttpClient = new OkHttpClient
                                .Builder()
                                .connectTimeout(mConnectTimeout,TimeUnit.MILLISECONDS)
                                .readTimeout(mReadTimeout,TimeUnit.MILLISECONDS)
                                .writeTimeout(mWriteTimeout,TimeUnit.MILLISECONDS)
                                .build();
                    }
                }
            }
    
    
            /**
             * 如果通过setConnectTimeout方法修改了连接超时时间,
             * 那么再次进行网络请求时要修改为默认的连接超时时间
             */
            if (mOkHttpClient.connectTimeoutMillis() != mConnectTimeout){
                try {
                    Field connectTimeoutField = mOkHttpClient.getClass().getDeclaredField("connectTimeout");
                    connectTimeoutField.setAccessible(true);
                    connectTimeoutField.setInt(mOkHttpClient,mConnectTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
    
    
            /**
             * 如果通过setReadTimeout方法修改了连接超时时间,
             * 那么再次进行网络请求时要修改为默认的读取超时时间
             */
            if (mOkHttpClient.readTimeoutMillis() != mReadTimeout){
                try {
                    Field readTimeoutField = mOkHttpClient.getClass().getDeclaredField("readTimeout");
                    readTimeoutField.setAccessible(true);
                    readTimeoutField.setInt(mOkHttpClient,mReadTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
    
    
            /**
             * 如果通过setWriteTimeout方法修改了连接超时时间,
             * 那么再次进行网络请求时要修改为默认的写入超时时间
             */
            if (mOkHttpClient.writeTimeoutMillis() != mWriteTimeout){ //通过其他方法修改过写入超时时间
                try {
                    Field writeTimeoutField = mOkHttpClient.getClass().getDeclaredField("writeTimeout");
                    writeTimeoutField.setAccessible(true);
                    writeTimeoutField.setInt(mOkHttpClient,mWriteTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
    
    
            //将参数字段转化为json字符串
            Gson gson = new Gson();
            String json = gson.toJson(map);
    
            //设置请求参数的格式为utf-8
            MediaType JSON = MediaType.parse("application/json;charset=UTF-8");
            RequestBody body = RequestBody.create(JSON,json);
            Request request;
            //请求头
            Headers headers = new Headers.Builder()
                        .add("os","ios")
                        .add("appname","crm")
                        .add("version","2.9.1")
                        .add("Content-Type","application/json;charset=UTF-8")
                        .build();
    
    
            if (method.equals(PCH.mHttpRequestPost)){ //post请求
                request = new Request.Builder()
                        .url(url)
                        .post(body)
                        .headers(headers)
                        .build();
            }else {//get请求
                request = new Request.Builder()
                        .url(url)
                        .get()
                        .headers(headers)
                        .build();
            }
    
    
            Call call = mOkHttpClient.newCall(request);
            callList.add(call);
            return call;
        }
    
    
        /**
         * 如果当前网络请求已经成功或者失败,那么要将当前call从callList中删除
         * @param call
         */
        public static void removeCall(Call call){
            callList.remove(call);
        }
    
    
    
        /**
         * 单独修改本次网络请求的连接超时时间
         * @param connectTimeout
         */
        public static void setConnectTimeout(int connectTimeout){
            if (mOkHttpClient != null && mOkHttpClient.connectTimeoutMillis() != connectTimeout){
                try {
                    Field connectTimeoutField = mOkHttpClient.getClass().getDeclaredField("connectTimeout");
                    connectTimeoutField.setAccessible(true);
                    connectTimeoutField.setInt(mOkHttpClient,connectTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        /**
         * 单独修改本次网络请求的读取超时时间
         * @param readTimeout
         */
        public static void setReadTimeout(int readTimeout){
            if (mOkHttpClient != null && mOkHttpClient.readTimeoutMillis() != readTimeout){
                try {
                    Field readTimeoutField = mOkHttpClient.getClass().getDeclaredField("readTimeout");
                    readTimeoutField.setAccessible(true);
                    readTimeoutField.setInt(mOkHttpClient,readTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        /**
         * 单独修改本次网络请求的读取超时时间
         * @param writeTimeout
         */
        public static void setWriteTimeout( int writeTimeout ) {
            if (mOkHttpClient != null && mOkHttpClient.readTimeoutMillis() != writeTimeout){
                try {
                    Field writeTimeoutField = mOkHttpClient.getClass().getDeclaredField("writeTimeout");
                    writeTimeoutField.setAccessible(true);
                    writeTimeoutField.setInt(mOkHttpClient,writeTimeout);
                }catch (NoSuchFieldException e){
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    二、新建网络请求工具类NetWorkTool

    /**
     * 网络请求方法
     */
    public class NetWorkTool {
    
    
        /**
         * 网络请求
         * @param url 地址
         * @param paraDic 地址
         * @param method GET/POST
         * @param myCallBack 回调
         */
        public static <T extends BaseDao> void request( final String url, final HashMap<String,Object> paraDic, String method, final MyCallBack<T> myCallBack){
    
    
            /**
             * 通过NetWorkManager.getInstance(url,paraDic,method)获取一个call对象进行异步网络请求
             */
            Call call = NetWorkManager.getInstance(url,paraDic,method);
    //        if (url == ""){ //可以根据具体url设置不同超时时间😂
    //            NetWorkManager.setConnectTimeout(15000); //可以设置本次网络请求的超时时间
    //        }
            call.enqueue(new Callback() {
    
                /**
                 * 网络请求失败 没有访问到服务器
                 * @param call
                 * @param e
                 */
                @Override
                public void onFailure( Call call, IOException e ) {
    
                    /**
                     * 打印出本次网络请求的错误信息,开发调试使用,生产环境可以注释掉
                     */
                    Log.d(" "," ");Log.d(" "," ");Log.d(" "," ");
                    Log.d("网络请求失败url=",url);
                    Log.d("requestHeader=", String.valueOf(call.request().headers()));
                    Log.d("requestPara=", String.valueOf(paraDic));
                    JUtil.i("response==", String.valueOf(e));
                    Log.d("","--------------------------------------------------------------------------------------------------------");
                    Log.d(" "," ");Log.d(" "," ");Log.d(" "," ");
                    /**
                     * 在NetWorkManager的单例对象中保留当前网络请求的所有call对象,
                     * 当本次网络请求结束(成功、失败)以后删除此call对象
                     */
                    NetWorkManager.removeCall(call);
                    myCallBack.onError(PCH.mHttpConnectError,e);
                }
    
    
                /**
                 * 网络请求访问到服务器了,分析服务器数据得到想要的结果
                 * 如果数据很简单不需要解析为model可以直接传入BaseDao,然后获取
                 * myCallBack.onSuccess(t,jsonStr,response)中的jsonStr自己做解析
                 *
                 * @param call
                 * @param response
                 * @throws IOException
                 */
                @Override
                public void onResponse( Call call, Response response ) throws IOException {
    
                        /**
                         * 在NetWorkManager的单例对象中保留当前网络请求的所有call对象,
                         * 当本次网络请求结束(成功、失败)以后删除此call对象
                         */
                        NetWorkManager.removeCall(call);
                    //response.body().string()只能执行一次
                    // 否则会报AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher错误
                    String jsonStr = response.body().string();
    
                    /**
                     * 打印出本次网络请求的信息
                     */
    
                    //格式化输出获取的数据,开发调试使用,生产环境可以注释掉
                    Gson gson = new GsonBuilder().setPrettyPrinting().create();
                    HashMap<String,Object> jsonModel = gson.fromJson(jsonStr,new TypeToken<HashMap<String,Object>>(){}.getType());
                    String outputJsonStr = gson.toJson(jsonModel,new TypeToken<HashMap<String,Object>>(){}.getType());
                    Log.d(" "," ");Log.e(" "," ");Log.i(" "," ");
                    Log.d("网络请求成功url=",url);
                    Log.d("requestHeader=", String.valueOf(call.request().headers()));
                    Log.d("requestPara=", String.valueOf(paraDic));
                    JUtil.i("response==",outputJsonStr);
                    Log.d("","--------------------------------------------------------------------------------------------------------");
                    Log.d(" "," ");Log.e(" "," ");Log.i(" "," ");
    
    
    
                    //设计思想: 由上而下,层层细化: ,传入要解析对象,返回解析实体对象。
                    T t = null;
                    // 解析对象过程
                    //获得泛型集合
                    //实体类型
                    Class<? extends MyCallBack> callBackClass = myCallBack.getClass();
                    String name = callBackClass.getSimpleName();
                    Type[] interfaces = callBackClass.getGenericInterfaces(); //获取接口类型
                    if (!(interfaces[0] instanceof ParameterizedType)){ //MyCall中的范型T不能为空,如果不需要解析为model可以传BaseDao
                        myCallBack.onError(PCH.mHttpParseError,null);
                        return;
                    }
                    ParameterizedType parameterizedType = (ParameterizedType) (interfaces[0]);
                    Type type = parameterizedType.getActualTypeArguments()[0];
                    Class<T> entityClass = (Class<T>) (type);
    
                    t = NetUtil.parse(jsonStr,entityClass);
    
                    if (t != null){
                       
                        if (t.getStatusCode() == 200){ //请求成功了 状态码200表示成功
                            myCallBack.onSuccess(t,jsonStr,response);
                        }else if (t.getStatusCode() == 401){ //用户未登录 602表示用户不是销售
    
                        }else if (t.getStatusCode() == 600){ //升级
    
                        }else { //请求失败
                            myCallBack.onError(PCH.mHttpConnectError,null);
                        }
                    }else {
                        myCallBack.onError(PCH.mHttpConnectError,null);
                    }
                }
            });
        }
    
    }
    

    三、新建Dao的基类BaseDao

    第二章节中的网络请求需要传入一个dao对象,然后返回一个数据解析成功之后的dao文件,这个dao不能为空,这个BaseDao包含了所有接口都会返回的最基本的信息

    public class BaseDao {
    
        private String status;
        private int statusCode;
        private String message;
    
    
        public String getStatus() {
            return status;
        }
    
        public void setStatus( String status ) {
            this.status = status;
        }
    
        public int getStatusCode() {
            return statusCode;
        }
    
        public void setStatusCode( int statusCode ) {
            this.statusCode = statusCode;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage( String message ) {
            this.message = message;
        }
    }
    

    四、使用方法

            /**
             *这个类可以做首页初始化完成之后需要处理的事情,
             * 首页显示的东西在TabbarActivity已经初始化完成,这里可以什么都不做 😂
             */
            HashMap<String,Object> para = new HashMap<>();
            para.put("username","username");
            para.put("password","password");
            NetWorkTool.request(PCH.requestLoginAction, para, PCH.mHttpRequestPost, new MyCallBack<BaseDao>() {
    
                @Override
                public void onSuccess( BaseDao baseDao, String responseString, Response response ) {
    
    
    //                Gson gson = new Gson();
    //                HashMap<String,String> obj = gson.fromJson(responseString,(new HashMap<String,Object>()).getClass());
    //                String string = obj.get("data").toString();
    
                    Log.d("网络请求成功",responseString);
    //                SharedPreferences sharedPreferences = getSharedPreferences(PCH.userLoginCookieKey,Context.MODE_PRIVATE);
    //                SharedPreferences.Editor editor = sharedPreferences.edit();
    //                editor.putString(PCH.userLoginCookieKey, "f26bf1fc7f9640fe8c8fa7926aebb414");
    //                editor.apply();
                }
    
                @Override
                public void onError( String errString, IOException e ) {
                    Log.d("网络请求失败",errString);
                }
    
            });
    

    五、项目实战

    相比较iOS我比较喜欢Android的一个用法就是内部类的使用,尤其在Dao中,不需要新建很多的Dao类,在一个类中根据json数据的结构新建内部类就可以了,见以下代码

    public class MessageListDao extends BaseDao {
    
    
        private DataBean data = new DataBean();
        public DataBean getData() {
            return data;
        }
    
        /**
         * data中的数据
         */
        public static class DataBean{
            private int pageSize = 0;
            private int pageNo = 0;
            private int count = 0; //共多少条数据
            private int pageCount = 0; //共多少页数据
            private ArrayList<ListData> list = new ArrayList<>();
    
            public int getPageSize() {
                return pageSize;
            }
    
            public void setPageSize( int pageSize ) {
                this.pageSize = pageSize;
            }
    
            public int getPageNo() {
                return pageNo;
            }
    
            public void setPageNo( int pageNo ) {
                this.pageNo = pageNo;
            }
    
            public int getCount() {
                return count;
            }
    
            public void setCount( int count ) {
                this.count = count;
            }
    
            public int getPageCount() {
                return pageCount;
            }
    
            public void setPageCount( int pageCount ) {
                this.pageCount = pageCount;
            }
    
            public ArrayList<ListData> getList() {
                return list;
            }
    
            /**
             * 上拉加载更多数据插入
             * @param list
             */
            public void loadMoreInsertList( ArrayList<ListData> list ) {
                this.list.addAll(list);
            }
    
            /**
             * list中的数据
             */
            public static class ListData{
              
                private String notifyId  =  ""; /** 消息体id 用于获取消息详情*/
                private String title  =  ""; /** 标题*/
                private String content  =  ""; /** 内容*/
                private String readFlag  =  ""; /** 用户阅读状态 0未读 1已读*/
                private String sendTime  =  ""; /** 消息发送时间*/
                private String showTime  =  ""; /** 消息发送时间 */
                public String getTitle() {
                    return title;
                }
    
                public String getContent() {
                    return content;
                }
    
                public String getReadFlag() {
                    return readFlag;
                }
    
                public String getSendTime() {
                    return sendTime;
                }
    
                public String getShowTime() {
                    return showTime;
                }
    
                public String getNotifyId() {
                    return notifyId;
                }
            }
        }
    
    }
    

    我对网络请求的理解就是会用,对底层理解不深入,所以就不讲解了😄

    demo地址
    https://github.com/jzglovewjr/crmandroidj

    相关文章

      网友评论

        本文标题:iOS转android之网络封装

        本文链接:https://www.haomeiwen.com/subject/mxgurqtx.html