Android 网络请求详解

我们知道大多数的 Android 应用程序都是通过和服务器进行交互来获取数据的。如果使用 HTTP 协议来发送和接收网络数据,就免不了使用 HttpURLConnection 和 HttpClient,而 Android 中主要提供了上述两种方式来进行 HTTP 操作。并且这两种方式都支持 HTTPS 协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。

但是 Googl e发布 6.0 版本的时候声明原生剔除 HttpClient,但是笔者认为 HttpClient 会提供相应的 jar 包做支持,毕竟 Google 对向下兼容这方面一直都做的很好,相信在选择网络功能的时候我们会选自己喜欢的方法。

HttpURLConnection

接着我们来看一下如何使用 HttpURLConnection 来处理简单的网络请求。

// Get方式请求
public static void requestByGet() throws Exception {
    String path = "10.128.7.34:3000/name=helloworld&password=android";
    // 新建一个URL对象
    URL url = new URL(path);
    // 打开一个HttpURLConnection连接
    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
    // 设置连接超时时间
    urlConn.setConnectTimeout(6 * 1000);
    // 开始连接
    urlConn.connect();
    // 判断请求是否成功
    if (urlConn.getResponseCode() == HTTP_200) {
        // 获取返回的数据
        byte[] data = readStream(urlConn.getInputStream());
        Log.i(TAG_GET, new String(data, "UTF-8"));
    } else {
        Log.i(TAG_GET, "Get方式请求失败");
    }
    // 关闭连接
    urlConn.disconnect();
}  
// Post方式请求
public static void requestByPost() throws Throwable {
    String path = "http://10.128.7.34:3000/login";
    // 请求的参数转换为byte数组
    String params = "name+ URLEncoder.encode("helloworld", "UTF-8")
            + "&password=" + URLEncoder.encode("android", "UTF-8");
    byte[] postData = params.getBytes();
    // 新建一个URL对象
    URL url = new URL(path);
    // 打开一个HttpURLConnection连接
    HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
    // 设置连接超时时间
    urlConn.setConnectTimeout(5 * 1000);
    // Post请求必须设置允许输出
    urlConn.setDoOutput(true);
    // Post请求不能使用缓存
    urlConn.setUseCaches(false);
    // 设置为Post请求
    urlConn.setRequestMethod("POST");
    urlConn.setInstanceFollowRedirects(true);
    // 配置请求Content-Type
    urlConn.setRequestProperty("Content-Type",
            "application/x-www-form-urlencode");
    // 开始连接
    urlConn.connect();
    // 发送请求参数
    DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());
    dos.write(postData);
    dos.flush();
    dos.close();
    // 判断请求是否成功
    if (urlConn.getResponseCode() == HTTP_200) {
        // 获取返回的数据
        byte[] data = readStream(urlConn.getInputStream());
        Log.i(TAG_POST, new String(data, "UTF-8"));
    } else {
        Log.i(TAG_POST, "Post方式请求失败");
    }
}

关于HttpURLConnection的相关开源工程

由于 Google 已经表明了推荐广大开发者使用 HttpURLConnection,那么想必是有一定原因的。

xUtils3

这里就推荐大伙都很熟悉的开源项目 xUtils 的“弟弟“,xUtils3。xUtils 包含了 view 注入,图片处理,数据库操作以及网络请求封装,xUtils 使用的网络请求封装是基于 HttpClient 的。xUtils3 使用的网络请求是基于 HttpURLConnection,我们着重说明一下xUtils3。

RequestParams params = new RequestParams("http://10.128.7.34:3000/upload");
        // 加到url里的参数, http://xxxx/s?wd=xUtils
        params.addQueryStringParameter("wd", "xUtils");
        // 添加到请求 body 体的参数, 只有 POST, PUT, PATCH, DELETE 请求支持.
        // params.addBodyParameter("wd", "xUtils");

        // 使用 multipart 表单上传文件
        params.setMultipart(true);
        params.addBodyParameter(
                "file",
                new File("/sdcard/test.jpg"),
                null); // 如果文件没有扩展名, 最好设置contentType 参数.
        params.addBodyParameter(
                "file2",
                new FileInputStream(new File("/sdcard/test2.jpg")),
                "image/jpeg",
                // 测试中文文件名
                "你+& \" 好.jpg"); // InputStream 参数获取不到文件名, 最好设置, 除非服务端不关心这个参数.
        x.http().post(params, new Callback.CommonCallback<String>() {
            @Override
            public void onSuccess(String result) {
                Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onCancelled(CancelledException cex) {
                Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFinished() {

            }
        });

具有 cache 功能

RequestParams params = new RequestParams("http://10.128.7.34:3000/upload");
        params.wd = "xUtils";
        // 默认缓存存活时间, 单位:毫秒.(如果服务没有返回有效的max-age 或 Expires)
        params.setCacheMaxAge(1000 * 60);
        Callback.Cancelable cancelable
                // 使用 CacheCallback, xUtils 将为该请求缓存数据.
                = x.http().get(params, new Callback.CacheCallback<String>() {

            private boolean hasError = false;
            private String result = null;

            @Override
            public boolean onCache(String result) {
                // 得到缓存数据, 缓存过期后不会进入这个方法.
                // 如果服务端没有返回过期时间, 参考params.setCacheMaxAge(maxAge)方法.
                //
                // * 客户端会根据服务端返回的 header 中 max-age 或 expires 来确定本地缓存是否给 onCache 方法.
                //   如果服务端没有返回 max-age 或 expires, 那么缓存将一直保存, 除非这里自己定义了返回false的
                //   逻辑, 那么xUtils将请求新数据, 来覆盖它.
                //
                // * 如果信任该缓存返回 true, 将不再请求网络;
                //   返回 false 继续请求网络, 但会在请求头中加上ETag, Last-Modified等信息,
                //   如果服务端返回 304, 则表示数据没有更新, 不继续加载数据.
                //
                this.result = result;
                return false; // true: 信任缓存数据, 不在发起网络请求; false 不信任缓存数据.
            }

            @Override
            public void onSuccess(String result) {
                // 注意: 如果服务返回 304 或 onCache 选择了信任缓存, 这里将不会被调用,
                // 但是 onFinished 总会被调用.
                this.result = result;
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                hasError = true;
                Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
                if (ex instanceof HttpException) { // 网络错误
                    HttpException httpEx = (HttpException) ex;
                    int responseCode = httpEx.getCode();
                    String responseMsg = httpEx.getMessage();
                    String errorResult = httpEx.getResult();
                    // ...
                } else { // 其他错误
                    // ...
                }
            }

            @Override
            public void onCancelled(CancelledException cex) {
                Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFinished() {
                if (!hasError && result != null) {
                    // 成功获取数据
                    Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
                }
            }
        });

post请求直接更改 post 方式,以及需要提交的参数即可,篇幅问题这里就不在一一列举了。通过以上代码可以看到,我们在使用 xUtils 来请求网络的时候会非常的方便,只用在回调函数里面做对应的代码逻辑处理即可,不用关心线程问题,极大的解放了我们的生产力。

Android Stuido Gradle使用方法如下:

compile ‘org.xutils:xutils:3.1.+‘

Volley

在 Android 2.3 及以上版本,使用的是 HttpURLConnection,而在Android 2.2 及以下版本,使用的是 HttpClient。鉴于现在的手机行业发展速度,我们已经不考虑 Android2.2 了。

简单提供一些 Volley 的实例:

//简单的 GET 请求
mQueue = Volley.newRequestQueue(getApplicationContext());
mQueue.add(new JsonObjectRequest(Method.GET, url, null,
            new Listener() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.d(TAG, "response : " + response.toString());
                }
            }, null));
mQueue.start();  
//对 ImageView 的操作
ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_launcher, android.R.drawable.ic_launcher);
mImageLoader.get(url, listener);  

//对 ImageView 网络加载的处理
mImageView.setImageUrl(url, imageLoader);

当然我们也可以定制自己的 request

mRequestQueue.add( new GsonRequest(url, ListResponse.class, null,
    new Listener() {
        public void onResponse(ListResponse response) {
            appendItemsToList(response.item);
            notifyDataSetChanged();
        }
    }
}

HttpClient

同样,我们来看一下 HttpClient 的简单请求。

// HttpGet 方式请求
public static void requestByHttpGet() throws Exception {
    String path = "http://10.128.7.34:3000/name=helloworld&password=android";
    // 新建 HttpGet 对象
    HttpGet httpGet = new HttpGet(path);
    // 获取 HttpClient 对象
    HttpClient httpClient = new DefaultHttpClient();
    // 获取 HttpResponse 实例
    HttpResponse httpResp = httpClient.execute(httpGet);
    // 判断是够请求成功
    if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
        // 获取返回的数据
        String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
        Log.i(TAG_HTTPGET, "HttpGet 方式请求成功,返回数据如下:");
        Log.i(TAG_HTTPGET, result);
    } else {
        Log.i(TAG_HTTPGET, "HttpGet 方式请求失败");
    }
}  

// HttpPost 方式请求
public static void requestByHttpPost() throws Exception {
    String path = "https://reg.163.com/login";
    // 新建 HttpPost 对象
    HttpPost httpPost = new HttpPost(path);
    // Post 参数
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("name", "helloworld"));
    params.add(new BasicNameValuePair("password", "android"));
    // 设置字符集
    HttpEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
    // 设置参数实体
    httpPost.setEntity(entity);
    // 获取 HttpClient 对象
    HttpClient httpClient = new DefaultHttpClient();
    // 获取 HttpResponse 实例
    HttpResponse httpResp = httpClient.execute(httpPost);
    // 判断是够请求成功
    if (httpResp.getStatusLine().getStatusCode() == HTTP_200) {
        // 获取返回的数据
        String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
        Log.i(TAG_HTTPGET, "HttpPost 方式请求成功,返回数据如下:");
        Log.i(TAG_HTTPGET, result);
    } else {
        Log.i(TAG_HTTPGET, "HttpPost 方式请求失败");
    }
}  

关于 HttpClinet 的相关开源工程

HttpClient 也拥有这大量优秀的开源工程,afinal、xUtils 以及AsyncHttpClient,也可以为广大开发者提供已经造好的轮子。由于xUtils 是基于 afinal 重写的,现在 xUtils3 也有替代 xUtils 的趋势,所以我们在这就简单介绍一下 AsyncHttpClient。

AsyncHttpClient

见名知意,AsyncHttpClient 对处理异步 Http 请求相当擅长,并通过匿名内部类处理回调结果,Http 异步请求均位于非 UI 线程,不会阻塞 UI 操作,通过线程池处理并发请求处理文件上传、下载、响应结果自动打包 JSON 格式。使用起来会很方便。

//GET请求
AsyncHttpClient client = new AsyncHttpClient();
//当然这里也可以换成 new JsonHttpResponseHandler(),我们就能直接获得 JSON 数据了。
client.get("http://www.google.com", new AsyncHttpResponseHandler() {

    @Override
    public void onStart() {
        // called before request is started
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response) {
        // called when response HTTP status is "200 OK"
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
        // called when response HTTP status is "4XX" (eg. 401, 403, 404)
    }

    @Override
    public void onRetry(int retryNo) {
        // called when request is retried
    }
});
//POST 请求
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("key", "value");
params.put("more", "data");
//同上,这里一样可以改成处理 JSON 数据的方法
client.get("http://www.google.com", params, new
    TextHttpResponseHandler() {
        @Override
        public void onSuccess(int statusCode, Header[] headers, String response) {
            System.out.println(response);
        }

        @Override
        public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
            Log.d("ERROR", error);
        }
    }
);

经过上面的代码发现,AsyncHttpClient 使用起来也是异常简洁,主要靠回调方法来处理成功或失败之后的逻辑。仔细想想,xUtils 的处理方式和这个处理方式很类似,看来好用设计还是很受人青睐的。

OkHttp

如果两种网络请求都想使用怎么办?那么 OkHttp 是一个最佳解决方案了。

OkHttp 在网络请求方面的口碑很好,就连 Google 自己也有使用OkHttp。虽然 Google6.0 中剔除了 HttpClient 的 Api,但是由于OkHttp 的影响力以及其强大的功能,使用 OkHttp 无需重写您程序中的网络代码。同时最重要的一点 OkHttp 实现了几乎和java.net.HttpURLConnection 一样的 API。如果您用了 Apache HttpClient,则 OkHttp 也提供了一个对应的 okhttp-apache 模块。足以说明 OkHttp 的强大,下面是一些例子。

  • 一般的 get 请求
  • 一般的 post 请求
  • 基于 Http 的文件上传
  • 文件下载
  • 加载图片
  • 支持请求回调,直接返回对象、对象集合
  • 支持 session 的保持

简单代码实例

//GET 请求
OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  Response response = client.newCall(request).execute();
  return response.body().string();
}
//POST 请求
public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}

Android Studio Gradle 使用方式:

compile ‘com.squareup.okhttp:okhttp:2.7.0‘

总结

Android 开发应用少不了使用网络,移动互联时代,抢占终端入口变得异常重要,那么我们在开发过程中,不管使用哪一种网络请求,HttpURLConnection 或者是 HttpClient,都可以满足我们和服务器的沟通。

可是发布的 App 到用户手中后,有用 WIFI 的,有用流量的,网络环境多样,我们怎么能知道用户在什么样的情况下访问服务器的流畅度呢?

答案很简单,只要集成了OneAPM
Mobile Insight
,即可轻松知晓网络交互情况,轻松了解用户在使用App的过程中哪里容易出问题,并对症下药。

OneAPM Mobile Insight,监控网络请求及网络错误,提升用户留存。访问 OneAPM
官方网站
感受更多应用性能优化体验,想阅读更多技术文章,请访问 OneAPM 官方技术博客

本文转自 OneAPM 官方博客

时间: 2024-10-09 07:49:50

Android 网络请求详解的相关文章

Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)

最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所帮助. 首先按照惯例先来简单了解一些AsyncHttpClient网络框架的一些知识. 1.简介 Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求,而使用android-a

Android 四大组件 详解

[置顶] Android四大组件详解 分类: Android四大组件2013-02-09 16:23 19411人阅读 评论(13) 收藏 举报 Android开发 注:本文主要来自网易的一个博主的文章,经过阅读,总结,故留下文章在此 Android四大基本组件介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器. 一:了解四大基本组件 Activity : 应用程序中,一个

Android平台调用WebService详解

上篇文章已经对Web Service及其相关知识进行了介绍(Android开发之WebService介绍 ),相信有的朋友已经忍耐不住想试试在Android应用中调用Web Service.本文将通过一个简单的示例讲解和演示Android平台的Web Service开发. Ksoap2-android简介       在Android平台调用Web Service需要依赖于第三方类库ksoap2,它是一个SOAP Web service客户端开发包,主要用于资源受限制的Java环境如Applet

Android WebView 开发详解

Android WebView 开发详解 1.概览: Android WebView 做为承载网页的载体控件,他在网页显示的过程中会产生一些事件,并回调给我们的应用程序,以便我们在网页加载过程中做应用程序想处理的事情.比如说客户端需要显示网页加载的进度.网页加载发生错误等等事件. WebView提供两个事件回调类给应用层,分别为WebViewClient,WebChromeClient开发者可以继承这两个类,接手相应事件处理.WebViewClient 主要提供网页加载各个阶段的通知,比如网页开

【转】【Android应用开发详解】第01期:第三方授权认证(一)实现第三方授权登录、分享以及获取用户资料

转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9057257 由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折,查阅了一番资料,做了一个Demo.实现起来的效果还是不错的,不敢独享,决定写一个总结的教程,供大家互相交流.学习和参考,博主只求能和大家共同进步.希望能多多支持! 这篇文章中,我们使用到了Share SDK,它是为iOS.Android.WP8的APP提供社会化功能的一

android屏幕适配详解

android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要使用绝对布局 2.尽量使用match_parent 而不是fill_parent . 3.能够使用权重的地方尽量使用权重(android:layout_weight) 4.如果是纯色背景,尽量使用android的shape 自定义. 5.如果需要在特定分辨率下适配,可以在res目录上新建layout

用netstat查看网络状态详解

--用netstat查看网络状态详解 -----------------------------2014/06/11 一.Linux服务器上11种网络连接状态:                                          图:TCP的状态机 通常情况下:一个正常的TCP连接,都会有三个阶段:1.TCP三次握手;2.数据传送;3.TCP四次挥手 注:以下说明最好能结合"图:TCP的状态机"来理解. SYN: (同步序列编号,Synchronize Sequence

Android中Context详解 ---- 你所不知道的Context

转载至 :http://blog.csdn.net/qinjuning 前言:本文是我读<Android内核剖析>第7章 后形成的读书笔记 ,在此向欲了解Android框架的书籍推荐此书. 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中 时刻的在与它打交道,例如:Service.BroadcastReceiver.Activity等都会利用到Context的相关方法 : 说它陌生,完全是 因为我们真正的不懂Context

Android相机开发详解(一)

Android相机开发详解(一) 请支持原创,尊重原创,转载请注明出处:http://blog.csdn.net/kangweijian(来自kangweijian的csdn博客) Android相机开发能够实现打开相机,前后摄像头切换,摄像预览,保存图片,浏览已拍照图片等相机功能. Android相机开发详解(一)主要实现打开相机,摄像预览,前后置摄像头切换,保存图片等四个功能. Android相机开发详解(二)主要实现翻页浏览相片,触控缩放浏览图片,删除图片,发送图片等四个功能. Andro