Android基础学习【历史流程重走】 ---- 网络请求(四)

一、网络请求

移动软件及APP实现主要在于本地功能交互的实现与数据的展示,且数据常为移动软件的核心。数据常源自于

服务器,网络数据交互则扮演十分重要的角色。


二、网络情形考量

网络请求在数据交互中扮演重要角色。因其流程的特殊性,存有多种情形需要考虑。

1,返回值情形

接口崩溃,返回异常情形;以及接口正确抛出异常的返回

接口返回内容为空,或者状态正常,可用数据部分为空;

接口正常返回数据,解析数据出现错误;

2,网络请求执行过程

执行开始前:提示网络请求正在执行,给予用户良好的反馈,屏蔽用户的其他操作【管控恶意点击,重复提交】

执行过程中:网络请求在特定条件下(返回,Home,黑屏,强制关机,电话、短信的插入),需要对网络请求做暂停、取消、重新开始等处理;

执行完成后:解析数据,重新渲染界面;尤其是网络请求错误时,需要数据的回显与数据的重置,并给与用户友好的提示。


针对上面情形,需要考虑的是:

(1)限定网络请求头,可以避免重复提交,也能实现接口的版本控制;

(2)网络请求最好实现队列效果,能够在合适的时间处理其中的某一个网络请求;

(3)实现线程池管理,不能无限开启线程,管控当前应用对系统的消耗;

(4)实现网络请求的数据压缩与加密,增强网络请求的安全性,减少数据量,增强信息传送、携带能力。

网络请求主要交互数据类型:

一般是字符串与图片文件的交互。随应用的扩展,扩展到表单、Map数据,文件以及数据流。


三、开源框架

现已经公开使用且使用效果较为良好的网络请求方式主要有:HttpClient、HttpURLConnection、AsyncTask、xUtlis、Volley、OkHttp、Retrofit、Android_Async_Http。从最初始的网络情求到应用框架实现封装。挑选实现进行管控。

HttpURLConnection:

public class NetWorkHttpConnection {
    /**
     * 超时时间
     */
    private static final int TIMEOUT_IN_MILLIONS = 5000;

    /**
     * HttpURLConnection GET请求
     * 访问路径中直接拼接完整参数
     *
     * @param urlStr 访问路径
     * @return 返回内容
     */
    public static String doGet(String urlStr) {
        URL url = null;
        HttpURLConnection conn = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(TIMEOUT_IN_MILLIONS);
            conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-type", "application/json");
            if (conn.getResponseCode() == 200) {
                is = conn.getInputStream();
                baos = new ByteArrayOutputStream();
                int len = -1;
                byte[] buf = new byte[128];

                while ((len = is.read(buf)) != -1) {
                    baos.write(buf, 0, len);
                }
                baos.flush();
                return baos.toString();
            } else {
                throw new RuntimeException(" responseCode is not 200 ... ");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (baos != null)
                    baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    /**
     * HttpURLConnection  POST请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String doPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            HttpURLConnection conn = (HttpURLConnection) realUrl
                    .openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type",
                    "application/json");
            conn.setRequestProperty("charset", "utf-8");
            conn.setUseCaches(false);
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setReadTimeout(TIMEOUT_IN_MILLIONS);
            conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);

            if (param != null && !param.trim().equals("")) {
                // 获取URLConnection对象对应的输出流
                out = new PrintWriter(conn.getOutputStream());
                // 发送请求参数
                out.print(param);
                // flush输出流的缓冲
                out.flush();
            }
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}
Volley:

**
 * 使用Volley封装网络请求
 * GET/POST都可以,在外部调用时传参一致
 *
 * @version V1.0
 * @author: Vision
 * @date: 2016-06-22 13:38
 */
public class NetWorkVolley {
    public static RequestQueue mQueue = Volley.newRequestQueue(DemoApplicatipn.getApplication());

    /**
     * POST方法访问网络
     *
     * @param method        访问路径
     * @param params        传递参数
     * @param listener      正确返回值监听器
     * @param errorListener 错误时监听器
     */
    public static void netWorkByPost(String method, JSONObject params, Response.Listener<JSONObject> listener,
                                     Response.ErrorListener errorListener) {
        JsonObjectRequest request = null;
        request = new JsonObjectRequest(Request.Method.POST, method, params,
                listener, errorListener) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                headers.put("User-Agent", "有代表意义的String串");
                headers.put("content-type", "x-www-form-urlencoded");
                headers.put("Accept-Encoding", "gzip");
                headers.put("api-version", 1 + "");
                return headers;
            }
        };
        request.setRetryPolicy(new DefaultRetryPolicy(15000,//设置默认超时时间,15秒
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默认最大尝试次数 1
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

        mQueue.add(request);
    }

    /**
     * GET方法实现网络请求
     *
     * @param url           访问路径
     * @param parames       传递参数
     * @param listener      正确返回值监听器
     * @param errorListener 错误时监听器
     */
    public static void netWorkByGet(String url, Map<String, Object> parames,
                                    Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        /**
         * 拼接参数
         */
        String paramStr = "";
        if (parames != null) {
            for (String key : parames.keySet()) {
                paramStr = paramStr + key + "=" + parames.get(key).toString() + "&";
            }
            url = url + "?" + paramStr;
        }
        /**
         * 执行网络请求
         */
        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, listener, errorListener) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                headers.put("User-Agent", "有代表意义的String串");
                headers.put("content-type", "x-www-form-urlencoded");
                headers.put("Accept-Encoding", "gzip");
                headers.put("api-version", 1 + "");
                return headers;
            }
        };
        request.setRetryPolicy(new DefaultRetryPolicy(15000,//设置默认超时时间,15秒
                0,//默认最大尝试次数
                1.0f));
        mQueue.add(request);
    }
}
xUtlis:

/**
 * @version V1.0
 * @author: Vision
 * @date: 2016-06-22 14:33
 */
public class NetWorkXUtils {
    /**
     * xutil请求网络数据POST
     *
     * @param url
     * @param map
     * @param requestCallBack
     */
    public static void getJsonPostForXutil(String url, Map<String, Object> map, RequestCallBack<String> requestCallBack) {
        HttpUtils httpUtils = new HttpUtils();
        httpUtils.configTimeout(10000);
        httpUtils.configSoTimeout(10000);
        httpUtils.configCurrentHttpCacheExpiry(1000);
        RequestParams params = new RequestParams();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            params.addBodyParameter(entry.getKey(), entry.getValue().toString());
        }
        httpUtils.send(HttpRequest.HttpMethod.POST, url, params, requestCallBack);
    }

    /**
     * xutils请求网络数据GET
     *
     * @param url
     * @param map
     * @param requestCallBack
     */
    public static void getJsonGetForXutil(String url, Map<String, Object> map, RequestCallBack<String> requestCallBack) {
        HttpUtils httpUtils = new HttpUtils();
        String getUrl = "";
        if (map != null) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                getUrl = getUrl + entry.getKey() + "=" + entry.getValue() + "&";
            }
            if (getUrl.length() > 1) {
                getUrl.substring(0, getUrl.length() - 1);
            }
        }
        httpUtils.configCurrentHttpCacheExpiry(1000);//防止连续点击的网络请求
        httpUtils.send(HttpRequest.HttpMethod.GET, url + getUrl, requestCallBack);
    }
}
Gzip实现类,调用GzipNetWork实现网络请求【数据压缩】
public class GZipRequest extends StringRequest {
    /**
     * 使用当前构造方法,没有参数体,不能使用POST请求
     * 要使用post,需要重写获取参数方法  getParams()
     *
     * @param method
     * @param url
     * @param listener
     * @param errorListener
     */
    public GZipRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        super(method, url, listener, errorListener);
    }

    /**
     * 默认Get请求
     *
     * @param url
     * @param listener
     * @param errorListener
     */
    public GZipRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        super(url, listener, errorListener);
    }


    // parse the gzip response using a GZIPInputStream
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        /**
         * 先判断数据是否为Gzip
         * 【使用gzip模式访问数据,不压缩的数据格式不接受】
         *
         * Content-Encoding  数据返回格式是否压缩的关键判断字段
         */
        Map<String, String> headers = response.headers;
        if (headers != null && headers.containsKey("Content-Encoding") && headers.get("Content-Encoding").contains("gzip")) {
            String output = ""; // note: better to use StringBuilder
            try {
                final GZIPInputStream gStream = new GZIPInputStream(new ByteArrayInputStream(response.data));
                final InputStreamReader reader = new InputStreamReader(gStream);
                final BufferedReader in = new BufferedReader(reader);
                String read;
                while ((read = in.readLine()) != null) {
                    output += read;
                }
                reader.close();
                in.close();
                gStream.close();
            } catch (IOException e) {
                return Response.error(new ParseError());
            }
            return Response.success(output, HttpHeaderParser.parseCacheHeaders(response));
        } else {
            String output = null;
            try {
                output = new String(response.data, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return Response.success(output, HttpHeaderParser.parseCacheHeaders(response));
        }
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        HashMap<String, String> headers = new HashMap<String, String>();
        headers.put("User-Agent", "有意义的String");
        headers.put("content-type", "application/x-www-form-urlencoded");
        headers.put("Accept-Encoding", "gzip");
        return headers;
    }
}
public class GzipNetWork {

    public static RequestQueue mQueue = Volley.newRequestQueue(DemoApplicatipn.getApplication());

    /**
     * 使用Gzip的GET网络请求
     *
     * @param url           网络请求不带参数的链接地址
     * @param params        网络请求参数
     * @param listener      网络请求正确返回值监听器
     * @param errorListener 网络请求错误返回值监听器
     */
    public static void netGzipWorkByGet(String url, Map<String, String> params, Response.Listener<String> listener,
                                        Response.ErrorListener errorListener) {
        String paramStr = "";
        if (params != null) {
            for (String key : params.keySet()) {
                paramStr = paramStr + key + "=" + params.get(key) + "&";
            }
            url = url + "?" + paramStr;
        }

        GZipRequest gZipRequest = new GZipRequest(url, listener, errorListener);
        mQueue.add(gZipRequest);
    }


    /**
     * 使用Gzip的POST网络请求
     *
     * @param url           网络请求不带参数的链接地址
     * @param params        网络请求参数
     * @param listener      网络请求正确返回值监听器
     * @param errorListener 网络请求错误返回值监听器
     */
    public static void netGzipWorkByPost(String url, final Map<String, String> params, Response.Listener<String> listener,
                                         Response.ErrorListener errorListener) {

        GZipRequest gZipRequest = new GZipRequest(Request.Method.POST, url, listener, errorListener) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params;
            }
        };
        mQueue.add(gZipRequest);
    }
}
在实际使用均调用NetWork类中的方法就可以,GET/POST方法都已实现,调用参数形式一致。主要是GET实现在链接后直接拼接参数,能够从外部看到,不安全且传输数据量有限;POST请求有自己的请求体,不在链接中展示,安全性较高,且数据内容长度没有限制。


四、相互关系

HttpURLConnection的实现中,传参较为麻烦,只是基本功能的实现,也没有效率方面的考虑;

xUtlis特长在于四大模块:Dbutlis/ViewUtlis/HttpUtlis/BitmapUtlis。

Volley实现队列访问,是一个相对比较成熟的框架。

Volley+Gzip则实现了网络数据的压缩。

点击这里有惊喜$_$

曾记许,旧时处,佩玉鸣箫罢歌舞;剑如初,心如故,三千弱水繁华路   \(^o^)/~


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

壹叁零壹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值