zoukankan      html  css  js  c++  java
  • Android使用http协议与服务器通信

    网上介绍Android上http通信的文章很多,不过大部分只给出了实现代码的片段,一些注意事项和如何设计一个合理的类用来处理所有的http请求以及返回结果,一般都不会提及。因此,自己对此做了些总结,给出了我的一个解决方案。

    首先,需要明确一下http通信流程,Android目前提供两种http通信方式,HttpURLConnection和HttpClient,HttpURLConnection多用于发送或接收流式数据,因此比较适合上传/下载文件,HttpClient相对来讲更大更全能,但是速度相对也要慢一点。在此只介绍HttpClient的通信流程:

    1.创建HttpClient对象,改对象可以用来多次发送不同的http请求

    2.创建HttpPost或HttpGet对象,设置参数,每发送一次http请求,都需要这样一个对象

    3.利用HttpClient的execute方法发送请求并等待结果,该方法会一直阻塞当前线程,直到返回结果或抛出异常。

    4.针对结果和异常做相应处理

    根据上述流程,发现在设计类的时候,有几点需要考虑到:

    1.HttpClient对象可以重复使用,因此可以作为类的静态变量

    2.HttpPost/HttpGet对象一般无法重复使用(如果你每次请求的参数都差不多,也可以重复使用),因此可以创建一个方法用来初始化,同时设置一些需要上传到服务器的资源

    3.目前Android不再支持在UI线程中发起Http请求,实际上也不该这么做,因为这样会阻塞UI线程。因此还需要一个子线程,用来发起Http请求,即执行execute方法

    4.不同的请求对应不同的返回结果,对于如何处理返回结果(一般来说都是解析json&更新UI),需要有一定的自由度。

    5.最简单的方法是,每次需要发送http请求时,开一个子线程用于发送请求,子线程中接收到结果或抛出异常时,根据情况给UI线程发送message,最后在UI线程的handler的handleMessage方法中做结果解析和UI更新。这么写虽然简单,但是UI线程和Http请求的耦合度很高,而且代码比较散乱、丑陋。

    基于上述几点原因,我设计了一个PostRequest类,用于满足我的http通信需求。我只用到了Post请求,如果你需要Get请求,也可以改写成GetRequest

    package com.handspeaker.network;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.params.HttpConnectionParams;
    import org.apache.http.params.HttpParams;
    import org.apache.http.protocol.HTTP;
    import org.apache.http.util.EntityUtils;
    import org.json.JSONObject;
    
    import android.app.Activity;
    import android.content.Context;
    import android.net.ConnectivityManager;
    import android.os.Handler;
    import android.util.Log;
    
    /**
     * 
     * 用于封装&简化http通信
     * 
     */
    public class PostRequest implements Runnable {
        
        private static final int NO_SERVER_ERROR=1000;
        //服务器地址
        public static final String URL = "fill your own url";
        //一些请求类型
        public final static String ADD = "/add";
        public final static String UPDATE = "/update";
        public final static String PING = "/ping";
        //一些参数
        private static int connectionTimeout = 60000;
        private static int socketTimeout = 60000;
        //类静态变量
        private static HttpClient httpClient=new DefaultHttpClient();
        private static ExecutorService executorService=Executors.newCachedThreadPool();
        private static Handler handler = new Handler();
        //变量
        private String strResult;
        private HttpPost httpPost;
        private HttpResponse httpResponse;
        private OnReceiveDataListener onReceiveDataListener;
        private int statusCode;
    
        /**
         * 构造函数,初始化一些可以重复使用的变量
         */
        public PostRequest() {
            strResult = null;
            httpResponse = null;
            httpPost = new HttpPost();
        }
        
        /**
         * 注册接收数据监听器
         * @param listener
         */
        public void setOnReceiveDataListener(OnReceiveDataListener listener) {
            onReceiveDataListener = listener;
        }
    
        /**
         * 根据不同的请求类型来初始化httppost
         * 
         * @param requestType
         *            请求类型
         * @param nameValuePairs
         *            需要传递的参数
         */
        public void iniRequest(String requestType, JSONObject jsonObject) {
            httpPost.addHeader("Content-Type", "text/json");
            httpPost.addHeader("charset", "UTF-8");
    
            httpPost.addHeader("Cache-Control", "no-cache");
            HttpParams httpParameters = httpPost.getParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters,
                    connectionTimeout);
            HttpConnectionParams.setSoTimeout(httpParameters, socketTimeout);
            httpPost.setParams(httpParameters);
            try {
                httpPost.setURI(new URI(URL + requestType));
                httpPost.setEntity(new StringEntity(jsonObject.toString(),
                        HTTP.UTF_8));
            } catch (URISyntaxException e1) {
                e1.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 新开一个线程发送http请求
         */
        public void execute() {
            executorService.execute(this);
        }
    
        /**
         * 检测网络状况
         * 
         * @return true is available else false
         */
        public static boolean checkNetState(Activity activity) {
            ConnectivityManager connManager = (ConnectivityManager) activity
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            if (connManager.getActiveNetworkInfo() != null) {
                return connManager.getActiveNetworkInfo().isAvailable();
            }
            return false;
        }
    
        /**
         * 发送http请求的具体执行代码
         */
        @Override
        public void run() {
            httpResponse = null;
            try {
                httpResponse = httpClient.execute(httpPost);
                strResult = EntityUtils.toString(httpResponse.getEntity());
            } catch (ClientProtocolException e1) {
                strResult = null;
                e1.printStackTrace();
            } catch (IOException e1) {
                strResult = null;
                e1.printStackTrace();
            } finally {
                if (httpResponse != null) {
                    statusCode = httpResponse.getStatusLine().getStatusCode();
                }
                else
                {
                    statusCode=NO_SERVER_ERROR;
                }
                if(onReceiveDataListener!=null)
                {
                    //将注册的监听器的onReceiveData方法加入到消息队列中去执行
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            onReceiveDataListener.onReceiveData(strResult, statusCode);
                        }
                    });
                }
            }
        }
    
        /**
         * 用于接收并处理http请求结果的监听器
         *
         */
        public interface OnReceiveDataListener {
            /**
             * the callback function for receiving the result data
             * from post request, and further processing will be done here
             * @param strResult the result in string style.
             * @param StatusCode the status of the post
             */
            public abstract void onReceiveData(String strResult,int StatusCode);
        }
    
    }

    代码使用了观察者模式,任何需要接收http请求结果的类,都要实现OnReceiveDataListener接口的抽象方法,同时PostRequest实例调用setOnReceiveDataListener方法,注册该监听器。完整调用步骤如下:

    1.创建PostRequest对象,实现onReceiveData接口,编写自己的onReceiveData方法

    2.注册监听器

    3.调用PostRequest的iniRequest方法,初始化本次request

    4.调用PostRequest的execute方法

    可能的改进:

    1.如果需要多个观察者,可以把只能注册单个监听器改为可以注册多个监听器,维护一个监听器List。

    2.如果需求比较简单,并希望调用流程更简洁,iniRequest和execute可以合并

    如果有更好的方法或者问题,欢迎随时交流

  • 相关阅读:
    JS 中 console 的用法
    C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
    C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo
    MEF框架使用总结
    webfunny前端监控开源项目
    我从Vue源码中学到的一些JS编程技巧
    nodejs 发送邮件demo
    从零开始手写Promise
    概率论要点
    行列式技巧
  • 原文地址:https://www.cnblogs.com/hrlnw/p/4118480.html
Copyright © 2011-2022 走看看