Android网络编程之一:原生网络访问简单封装

转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/54143487
本文出自:【Kevin.zhou的博客】

前言:转眼间2017了,去年给自己定的一周一篇博客被拖成了一月一篇,后来忙着找工作也荒废了。竟然还被CSDN博客之星提名,又点燃了撸博客的激情。
作为一个android codder,网略访问基本上在项目中都会用到,常用的获取JSON数据、下载文件(图片等)、上传数据、上传问文件等等。Android原生的访问网络有HttpClientHttpURLConnection。在Android 6.0时删除了HttpClientOkHttp的呼声也随之高涨。

下面会对这几种网络访问模式写下简单的示例,网上大多示例都是访问别人的服务器或者本地的服务器,不便于大家测试,我用阿里云搭建了个简单的服务端。

吐下槽,之前使用的MyEclipse开发Java Web,换电脑之后在网上搜怎么配MacJava Web开发环境,有很多人提到使用IntelliJ IDEA,搞环境又搞了一两天,本人后端小菜~

NetworkTask编写

这里我们使用AsyncTask的方式进行子线程访问网络并回调到主线程,在创建NetworkTask的时候要传入是GET还是POST请求,然后传入参数开始访问网略获取数据。

1. 这里我们约定`GET`请求时参数即为拼接的请求地址,如:
    new xxxNetworkTask(NetworkTask.GET).execute("http://123.57.31.11/androidnet/getJoke?id=5");
2. 约定`POST`请求时参数第一个为地址,其他为请求参数对,如:
    new xxxNetworkTask(NetworkTask.POST).execute("http://123.57.31.11/androidnet/getJoke", "id=5");
/**
 * 访问网络AsyncTask基类,访问网络在子线程进行并返回主线程通知访问的结果
 */
public abstract class NetworkTask extends AsyncTask<String, Integer, String> {

    public static final String TAG = "NetworkTask";

    public static String GET = "GET";
    public static String POST = "POST";
    private String mRequestMethod;

    public NetworkTask(String method) {
        this.mRequestMethod = method;
    }

    @Override
    protected String doInBackground(String... params) {
        String data;
        if(GET.equals(mRequestMethod)) {
            data = doGet(params[0]);
        } else if(POST.equals(mRequestMethod)) {
            data = doPost(params);
        } else {
            throw new RuntimeException("Request mode can only be GET or POST!");
        }
        return data;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
    }

    /**
     * 以GET的方式访问网络
     * 
     * @param url
     * @return 返回的字符串数据
     */
    public abstract String doGet(String url);

    /**
     * 以POST的方式访问网络
     * 
     * @param params
     * @return 返回的字符串数据
     */
    public abstract String doPost(String[] params);

}

然后我们加上返回数据的监听回调

/**
 * 访问网络AsyncTask基类,访问网络在子线程进行并返回主线程通知访问的结果
 */
public abstract class NetworkTask extends AsyncTask<String, Integer, String> {

    public static final String TAG = "NetworkTask";

    public static String GET = "GET";
    public static String POST = "POST";
    // 访问方式,只能是GET或POST
    private String mRequestMethod;
    // 是否访问网络成功
    protected boolean isSuccess = true;
    // 监听回调
    private ResponceLintener mResponceLintener;

    public NetworkTask(String method) {
        this.mRequestMethod = method;
    }

    @Override
    protected String doInBackground(String... params) {
        String data;
        String url = params[0];
        if(GET.equals(mRequestMethod)) {
            data = doGet(url);
        } else if(POST.equals(mRequestMethod)) {
            Map<String, String> paramMap = new HashMap<String, String>();
            // 第一个参数为访问的接口,不为body参数
            for (int i = 1; i < params.length; i++) {
                String[] value = new String[2];
                if (params[i].split("=").length == 1) {
                    value[0] = params[i].split("=")[0];
                    value[1] = "";
                } else {
                    value = params[i].split("=");
                }
                paramMap.put(value[0], value[1]);
            }
            data = doPost(url, paramMap);
        } else {
            throw new RuntimeException("Request mode can only be GET or POST!");
        }
        return data;
    }

    @Override
    protected void onPostExecute(String result) {
        if(null != mResponceLintener) {
            if(isSuccess) {
                mResponceLintener.onSuccess(result);
            } else {
                mResponceLintener.onError(result);
            }
        }
    }

    /**
     * 以GET的方式访问网络
     * 
     * @param url
     * @return 返回的字符串数据
     */
    public abstract String doGet(String url);

    /**
     * 以POST的方式访问网络
     * 
     * @param url
     * @param paramMap
     * @return 返回的字符串数据
     */
    public abstract String doPost(String url, Map<String, String> paramMap);

    public void setResponceLintener(ResponceLintener l) {
        this.mResponceLintener = l;
    }

    public interface ResponceLintener {
        /**
         * 成功的监听回调
         * @param result
         */
        void onSuccess(String result);
        /**
         * 失败的监听回调
         * @param error
         */
        void onError(String error);
    }

}

OK,经过简单的封装之后,我们在使用不同的形式访问网络时只需要对应的去实现doGetdoPost就可以了。

HttpClient

尽管HttpClient删除了,我们还是简单回顾下它的使用。

HttpClientNetworkTask

创建HttpClientNetworkTask继承NetworkTask并实现抽象方法。

/**
 * 以HttpClient访问网络AsyncTask,访问网络在子线程进行并返回主线程通知访问的结果
 */
public class HttpClientNetworkTask extends NetworkTask {

    public HttpClientNetworkTask(String method) {
        super(method);
    }

    @Override
    public String doGet(String url) {
        return null;
    }

    @Override
    public String doPost(String url, Map<String, String> paramMap) {
        return null;
    }

}

下面我们只需要使用HttpClient去完成响应的网络请求就可以啦~ 是不是很清爽~~

HttpClient使用步骤:

  1. 创建HttpClient对象;
  2. 创建请求的对象,如果为GET请求,则创建HttpGet对象,如果为POST请求,则创建HttpPost对象;
  3. 调用HttpClient对象的execute发送请求,执行该方法后,将获得服务器返回的HttpResponse对象;
  4. 检查相应状态是否正常;
  5. 获得相应对象当中的数据。

GET

@Override
public String doGet(String url) {
    String result = null;
    HttpClient httpCient = new DefaultHttpClient();
    HttpGet httpGet = new HttpGet(url);
    try {
        HttpResponse httpResponse = httpCient.execute(httpGet);
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
             HttpEntity entity = httpResponse.getEntity();
             result = EntityUtils.toString(entity,"utf-8");
        } else {
            isSuccess = false;
            result = "网络响应状态码不为200!";
        }
    } catch (IOException e) {
        isSuccess = false;
        result = "网络访问错误:" + e.getMessage();
    }

    return result;
}

使用如下:

NetworkTask networkTask = new HttpClientNetworkTask(NetworkTask.GET);
networkTask.execute("http://123.57.31.11/androidnet/getJoke?id=5");
networkTask.setResponceLintener(new NetworkTask.ResponceLintener() {

    @Override
    public void onSuccess(String result) {
        tv.setText(result);
    }

    @Override
    public void onError(String error) {
        Toast.makeText(getApplicationContext(), error, Toast.LENGTH_SHORT).show();
    }
});

据说没图不便于理解,上图:

网络访问

POST

@Override
public String doPost(String url, Map<String, String> paramMap) {
    String result;
    HttpClient httpCient = new DefaultHttpClient();
    HttpPost httpRequest = new HttpPost(url);
    // 使用NameValuePair来保存要传递的Post参数
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    for (Map.Entry<String, String> entry : paramMap.entrySet()) {
        params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
    }
    try {
        httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
        HttpResponse response = httpCient.execute(httpRequest);
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            result = EntityUtils.toString(response.getEntity());
        } else {
            isSuccess = false;
            result = "网络响应状态码不为200!";
        }
    } catch (IOException e) {
        isSuccess = false;
        result = "网络访问错误:" + e.getMessage();
    }

    return result;
}

使用如下:

NetworkTask networkTask = new HttpClientNetworkTask(NetworkTask.POST);
networkTask.execute("http://123.57.31.11/androidnet/getJoke", "id=5");
networkTask.setResponceLintener(new NetworkTask.ResponceLintener() {

    @Override
    public void onSuccess(String result) {
        tv.setText(result);
    }

    @Override
    public void onError(String error) {
        Toast.makeText(getApplicationContext(), error, Toast.LENGTH_SHORT).show();
    }
});

HttpURLConnection

HttpURLConnectionNetworkTask

创建HttpURLConnectionNetworkTask继承NetworkTask并实现抽象方法。

/**
 * 以HttpURLConnection访问网络AsyncTask,访问网络在子线程进行并返回主线程通知访问的结果
 */
public class HttpURLConnectionNetworkTask extends NetworkTask {

    public HttpURLConnectionNetworkTask(String method) {
        super(method);
    }

    @Override
    public String doGet(String url) {
        return null;
    }

    @Override
    public String doPost(String url, Map<String, String> paramMap) {
        return null;
    }

}

下面我们用HttpURLConnection去完成响应的网络。

HttpURLConnection使用步骤:

  1. 实例化URL对象;
  2. 实例化HttpUrlConnection对象;
  3. 设置请求连接属性,传递参数等;
  4. 获取返回码判断是否链接成功;
  5. 读取输入流;
  6. 关闭链接。

GET

@Override
public String doGet(String httpUrl) {
    String result;
    try {
        URL url = new URL(httpUrl);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        urlConnection.setReadTimeout(5000);
        urlConnection.setConnectTimeout(5000);
        urlConnection.setRequestProperty("Charset", "UTF-8");
        if (urlConnection.getResponseCode() == 200) {
            InputStream is = urlConnection.getInputStream();
            result = readFromStream(is);
        } else {
            isSuccess = false;
            result = "网络响应状态码不为200!";
        }
    } catch(IOException e) {
        isSuccess = false;
        result = "网络访问错误:" + e.getMessage();
    }

    return result;
}

这里编写了一个从流获取字符串的工具

/**
 * 输入流获取字符串
 * 
 * @param is 输入流
 * @return String 返回的字符串
 * @throws IOException
 */
public String readFromStream(InputStream is) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = is.read(buffer)) != -1) {
        baos.write(buffer, 0, len);
    }
    is.close();
    String result = baos.toString();
    baos.close();
    return result;
}

使用方法和HttpClientNetworkTask一样,只不过是把实现类由HttpClientNetworkTask换为HttpURLConnection:

NetworkTask networkTask = new HttpURLConnectionNetworkTask(NetworkTask.GET);
networkTask.execute("http://123.57.31.11/androidnet/getJoke?id=6");
networkTask.setResponceLintener(new NetworkTask.ResponceLintener() {

    @Override
    public void onSuccess(String result) {
        tv.setText(result);
    }

    @Override
    public void onError(String error) {
        Toast.makeText(getApplicationContext(), error, Toast.LENGTH_SHORT).show();
    }
});

POST

@Override
public String doPost(String httpUrl, Map<String, String> paramMap) {
    String result;
    try {
        URL url = new URL(httpUrl);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setReadTimeout(5000);
        urlConnection.setConnectTimeout(5000);
        // 配置连接的Content-type
        urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        urlConnection.setDoOutput(true);    // 发送POST请求必须设置允许输出 
        urlConnection.setDoInput(true);     // 发送POST请求必须设置允许输入 

        String data = "";
        boolean firstParam = true;
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            if(firstParam) {
                data += entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
                firstParam = false;
            } else {
                data += "&" + entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
            }
        }
        OutputStream os = urlConnection.getOutputStream();
        os.write(data.getBytes());
        os.flush();

        if (urlConnection.getResponseCode() == 200) {
            InputStream is = urlConnection.getInputStream();
            result = readFromStream(is);
        } else {
            isSuccess = false;
            result = "网络响应状态码不为200!";
        }
    } catch (IOException e) {
        isSuccess = false;
        result = "网络访问错误:" + e.getMessage();
    }

    return result;
}

使用方法和HttpClientNetworkTask一样,只不过是把实现类由HttpClientNetworkTask换为HttpURLConnection:

NetworkTask networkTask = new HttpURLConnectionNetworkTask(NetworkTask.POST);
networkTask.execute("http://123.57.31.11/androidnet/getJoke", "id=6");
networkTask.setResponceLintener(new NetworkTask.ResponceLintener() {

    @Override
    public void onSuccess(String result) {
        tv.setText(result);
    }

    @Override
    public void onError(String error) {
        Toast.makeText(getApplicationContext(), error, Toast.LENGTH_SHORT).show();
    }
});

总结

其实开发的时候我们不是很关心具体是怎么联网的,封装好之后使用起来越简单越好。我给你地址和参数你去访问网略然后返回我关心的数据就可以了。

以上是使用HttpClientHttpURLConnection进行了GETPOST的返回数据为字符串类型简单封装,有兴趣的朋友也可以进行OkHttp或其他方式的封装。

当然在使用的时候可能会有更加复杂的场景,比如:上传一个图片、下载一个文件等。

我们最常使用的还是获取JSON类型的数据,然后封装到实体。那么这一块如何封装呢?接下来的一篇博客将抛开NetworkTask进行获取JSON数据并封装到实体的简单编写。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值