美文网首页开源库
接口回调,OkHttp基本使用与封装

接口回调,OkHttp基本使用与封装

作者: 云承寒 | 来源:发表于2017-07-26 20:17 被阅读0次
    接口回调

    在对象中,有些事件不确定什么时候能完成,此时可以通过预留监督机制,关注事件的变化,这个机制即回调。

    举个例子
    模拟下载,实施监督下载的进度,当100%时,提醒下载完成
    
    1.  建立一个下载进度的类
        需要监督加载的进度,因此方法内需要一个监督进度的形参接口
    class Progress {
    
        public void loadProgress(IProgressListener progressListener) {
            //模拟进度
            for (int i = 1; i <= 100; i++) {
                //进度每改变一次,即调用更新一次监督的数据
                progressListener.curProgress(i);
            }
        }
    }
    
    
    2.  建立监听的回调接口,用来监听进度
    interface IProgressListener {
        void curProgress(int curProgress);
    }
    
    
    3.运行调用
      实际还是对多态的运用
      当Progress类调用loadProgress(IProgressListener progressListener)时
      传入的实参是一个匿名内部类,也是IProgressListener的子类
      相当于 IProgressListener progressListener = new 子类();
      此时调用的是子类的实现。
    
    public class Main {
    
        public static void main(String[] args) {
            Progress progress = new Progress();
    
            progress.loadProgress(new IProgressListener() {
                @Override
                public void curProgress(int curProgress) {
                    System.out.printf("curProgress:" + curProgress + "\r\n");
                    if (curProgress == 100)
                        System.out.printf("下载完成");
                }
            });
        }
    }
    

    OkHttp
    Android网络请求的变迁
    OkHttp的基本用法
    前置工作
    1.  添加依赖
    OkHttp依赖:implementation 'com.squareup.okhttp3:okhttp:3.11.0'
    Gson依赖:implementation 'com.google.code.gson:gson:2.8.5'
    
    2.  Android在做网络请求时要添加权限
    <uses-permission android:name="android.permission.INTERNET" />
    
    注意
    Android P 限制了明文流量的网络请求,非加密的流量请求都会被系统禁止。
    如果 WebView 的 url 用 http 协议,同样会出现加载失败,https 不受影响。
    
    如果当前应用的请求是 htttp 而非 https,系统会禁止当前应用进行该请求。
    在 Android P 版本如果使用了明文流量,OkHttp3会抛出
    CLEARTEXT communication to " + host + " not permitted by network security policy异常
    
    解决方案
    服务器和客户端的请求最好都用https
    
    OkHttp提供的API
    
    Get请求
    1.  首先创建OkHttpClient
    OkHttpClient okHttpClient = new OkHttpClient();
    
    
    2.  发送请求需要构建Request对象
    Request request = new Request.Builder()
                    .url(requestUrl())
                    .build();
    
    
    3.  okHttpClient 调用newCall()创建一个Call对象,并调用enqueue()
    发送请求并获取服务器返回的数据。
    okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
    
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
    
                if (response.isSuccessful()) {
                    String resJson = response.body().string();
                    Gson gson = new Gson();
                    User user = gson.fromJson(resJson, User.class);
                }
            }
    });
    
    
    Post请求
    1. 需要构建一个RequestBody对象来存放提交的参数
    RequestBody body = new FormBody.Builder()
                    .add("userName", getUserName())
                    .add("userCode", getUserCode())
                    .build();
    
    
    2.  将body 添加到Request.Builder中
    Request request = new Request.Builder()
                    .url(requestUrl())
                    .post(body)
                    .build();
    
    举个例子
    客户端向服务器发送用户输入的用户名,用户编号
    服务端返回用户的信息
    
    
    1.  服务端
    Module类
    public class User {
        String name;
        int code;
        String info;
    }
    
    
    @WebServlet(value = "/user")
    public class UserServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
    
            req.setCharacterEncoding("UTF-8");
            resp.setContentType("text/html;charset=UTF-8");
    
            Gson gson = new Gson();
            String userName = req.getParameter("userName");
            String userCode = req.getParameter("userCode");
    
            if (userName.equals("admin") && userCode.equals("123")) {
                User user = new User("admin", 1, "演示信息");
                resp.getWriter().println(gson.toJson(user));
            }
        }
    }
    
    2.  客户端
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        private EditText mEtUserName;
        private EditText mEtUserCode;
        private Button mBtnQuery;
        private TextView mTvShowUserInfo;
    
        @SuppressLint("HandlerLeak")
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        User user = (User) msg.obj;
                        showUserInfo(user);
                        break;
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
            initEvent();
        }
    
        private void initEvent() {
            mBtnQuery.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    getUserInfo();
                }
            });
        }
    
        //网络请求
        private void getUserInfo() {
            OkHttpClient okHttpClient = new OkHttpClient();
            RequestBody body = new FormBody.Builder()
                    .add("userName", getUserName())
                    .add("userCode", getUserCode())
                    .build();
    
            final Request request = new Request.Builder()
                    .url(requestUrl())
                    .post(body)
                    .build();
    
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                    if (response.isSuccessful()) {
                        String resJson = response.body().string();
                        Gson gson = new Gson();
                        User user = gson.fromJson(resJson, User.class);
                        Message message = Message.obtain();
                        message.what = 1;
                        message.obj = user;
                        mHandler.sendMessage(message);
                    }
                }
            });
        }
    
        private void initView() {
            mEtUserName = findViewById(R.id.et_user_name);
            mEtUserCode = findViewById(R.id.et_user_code);
            mBtnQuery = findViewById(R.id.btn_query_data);
            mTvShowUserInfo = findViewById(R.id.tv_user_info_show);
        }
    
        private String getUserName() {
            return mEtUserName.getText().toString();
        }
    
        private String getUserCode() {
            return mEtUserCode.getText().toString();
        }
    
        private void showUserInfo(User user) {
            StringBuilder builder = new StringBuilder();
            builder.append("UserName:" + user.getName())
                    .append("\r\n")
                    .append("UserCode:" + user.getCode())
                    .append("\r\n")
                    .append("UserInfo:" + user.getInfo());
            mTvShowUserInfo.setText(builder.toString());
        }
    
        private String requestUrl() {
            return "http://192.168.1.104:8080/user";
        }
    }
    
    OkHttp封装
    思路
    通过观察OkHttp,不难发现所有的请求都是通过Request这个类构建
    为了保证不浪费资源,将OkHttp设置为单例模式。
    
    1.  用枚举区分Get,Post,设置对外调用方法,获取网络请求
        传递参数
          1.请求的路径
          2.post请求时传递的参数
          3.一个用于监测请求完成的回调类
    
    2.  定义OkHttp的请求doRequest()方法,用于监听请求成功失败,请求前的状态
        传递参数
          1.构建的Request类
          2.监听回调类
    
    3.  所有请求都用异步在子线程操作,修改UI需要Handler发送到主线程
    这就需要根据成功失败的回调,创建发送的Handler方法
    
    4.  定义回调类
        1.请求成功
        2.请求失败
    
    5.  设置回调的包装类,帮助简化构建不必要的方法
    
    1.  设置回调类
    
    public abstract class IBaseCallBack<T> {
    
        public Type mType;
    
        public IBaseCallBack() {
            mType = getSuperclassTypeParameter(getClass());
        }
    
        /**
         * 将Type类型转换成Gson,解析
         */
        static Type getSuperclassTypeParameter(Class<?> subclass) {
            Type superclass = subclass.getGenericSuperclass();
            if (superclass instanceof Class) {
                throw new RuntimeException("Missing type parameter.");
            }
            ParameterizedType parameterized = (ParameterizedType) superclass;
            return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
        }
    
        //请求成功前回调
        public abstract void onRequestBefore();
    
        //网络请求成功后根据返回码调用
        public abstract void onSuccess(Response response, T t);
    
        //请求失败时
        public abstract void onFailure(Call call, Exception e);
    }
    
    2.  将OkHttp封装
    
    public class OkHttpHelper {
    
        private static OkHttpHelper mOkHttpHelper;
        private static OkHttpClient mOkHttpClient;
    
        private static Gson mGson;
        private Handler mHandler;
    
        private OkHttpHelper() {
            mOkHttpClient = new OkHttpClient();
            mGson = new Gson();
    
            //每发现一条消息就推送到Handler
            mHandler = new Handler(Looper.getMainLooper());
        }
    
        public static OkHttpHelper getOkHttpHelperInstance() {
            if (mOkHttpHelper == null) {
                synchronized (OkHttpHelper.class) {
                    if (mOkHttpHelper == null) {
                        mOkHttpHelper = new OkHttpHelper();
                    }
                }
            }
            return mOkHttpHelper;
        }
    
        //来区别请求的类型
        enum HttpMethodType {
            GET, POST
        }
    
        /**
         * 对外调用的Get,Post请求
         */
        public void get(String url, IBaseCallBack callBack) {
            Request request = buildRequest(
                    url,
                    null,
                    HttpMethodType.GET);
    
            doRequest(request, callBack);
        }
    
        public void post(String url, Map<String, String> parameter,
                         IBaseCallBack callBack) {
    
            Request request = buildRequest(
                    url,
                    parameter,
                    HttpMethodType.POST);
    
            doRequest(request, callBack);
        }
    
        /**
         * 构建Get或Post请求的Request
         *
         * @param url        Url地址
         * @param parameter  Post请求所需要的参数
         * @param methodType 通过枚举来判断是Get还是Post
         * @return Request
         */
        private Request buildRequest(String url,
                                     Map<String, String> parameter,
                                     HttpMethodType methodType) {
    
            Request.Builder builder = new Request.Builder();
            builder.url(url);
            if (methodType == HttpMethodType.GET) {
                builder.get();
            } else {
                //构建参数获取
                RequestBody body = buildFormData(parameter);
                builder.post(body);
            }
            return builder.build();
        }
    
        /**
         * 构建Post请求的body
         */
        private RequestBody buildFormData(Map<String, String> parameter) {
            FormBody.Builder body = new FormBody.Builder();
    
            if (null != parameter) {
    
                for (Map.Entry<String, String> entry : parameter.entrySet()) {
    
                    body.add(entry.getKey(), entry.getValue());
                }
            }
            return body.build();
        }
    
    
        /**
         * 通过构建好的Get或Post请求的Request,做网络访问
         */
        private void doRequest(final Request request, final IBaseCallBack callBack) {
    
            callBack.onRequestBefore();
    
            mOkHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    requestFailure(callBack, call, e);
                }
    
                @Override
                public void onResponse(Call call, Response response)
                        throws IOException {
    
                    if (response.isSuccessful()) {
                        String resultStr = response.body().string();
    
                        if (callBack.mType == String.class) {
    
                            requestSuccess(callBack, response, request);
    
                        } else {
    
                            try {
                                //防止Json解析错误
                                Object obj = mGson.fromJson(resultStr, callBack.mType);
    
                                requestSuccess(callBack, response, obj);
    
                            } catch (JsonParseException e) {
                                requestFailure(callBack, call, e);
                            }
                        }
                    } else {
                        requestFailure(callBack, call, null);
                    }
                }
            });
        }
    
        private void requestFailure(final IBaseCallBack callBack,
                                    final Call call,
                                    final Exception e) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onFailure(call, e);
                }
            });
        }
    
        private void requestSuccess(final IBaseCallBack callBack,
                                    final Response response,
                                    final Object o) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onSuccess(response, o);
                }
            });
        }
    }
    
    3.  设置接口的包装类,帮助简化不必要的实现接口或者添加其他方法
    注意:两者同样是抽象类,SpotsCallBack重写的抽象方法,在其子类是不会主动提示覆盖的
    
    public abstract class SpotsCallBack<T> extends IBaseCallBack<T> {
    
        ProgressDialog mDialog;
    
        public SpotsCallBack(Context context) {
            mDialog = new ProgressDialog(context);
            mDialog.setCancelable(false);
            mDialog.setCanceledOnTouchOutside(false);
        }
    
        public void showDialog() {
            mDialog.show();
        }
    
        public void dismissDialog() {
            mDialog.dismiss();
        }
    
        @Override
        public void onRequestBefore() {
            showDialog();
        }
    }
    
    具体调用
    
    private void getUserInfo() {
    
            HashMap<String, String> paramester = new HashMap<>();
            paramester.put("userName", getUserName());
            paramester.put("userCode", getUserCode());
    
            OkHttpHelper.getOkHttpHelperInstance()
                    .post(requestUrl(), paramester, new SpotsCallBack<User>(this) {
                        @Override
                        public void onSuccess(Response response, User user) {
                            dismissDialog();
                            showUserInfo(user);
                        }
    
                        @Override
                        public void onFailure(Call call, Exception e) {
                            dismissDialog();
                        }
              });
    }
    

    相关文章

      网友评论

        本文标题:接口回调,OkHttp基本使用与封装

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