程序员今日看点

Android 网络请求框架OkHttp入门

2016-09-26  本文已影响1316人  david_zhw
最近身边越来越多的小伙伴提到okHttp,于是我也打算趁着新项目开始前着手学习一下okhttp,并且希望能在新项目中用起来。Google了一些材料,照着文档写了简单的demo,并且做了最简单的封装。每个项目中的网络请求接口一般都不会太少,所以不封装是不靠谱的,然而okHttp确实封装起来比较麻烦一些。

OkHttp官网地址: http://square.github.io/okhttp/

OkHttp GitHub地址:https://github.com/square/okhttp

  compile 'com.squareup.okhttp3:okhttp:3.3.1'

同步Http GET请求

OkHttpClient client = new OkHttpClient();
private void httpGet(String url) throws IOException {
        final Request request = new Request.Builder()
                .get()
                .tag(this)
                .url(url)
                .build();//Request是OkHttp中访问的请求,Builder是辅助类,Response即OkHttp中的响应
    final Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        return response.body().string();
    } else {
        throw new IOException("Unexpected code " + response);
    }
}
    /**
      * onResponse回调的参数是response,一般情况下,比如
      * 我们希望获得返回的字符串,可以通过response.body().string()获取;
      * 如果希望获得返回的二进制字节数组,则调用response.body().bytes();
      * 如果你想拿到返回的inputStream,则调用response.body().byteStream()
      */

同步Http POST请求

//POST提交键值对 
OkHttpClient client = new OkHttpClient();
private void httpPost(String url) throws IOException {
        RequestBody formBody = new FormBody.Builder()
                .add("u_Phone", "10086")//传入参数
                .add("code", "111111")//传入参数
                .add("encodestr", MD5Utils.ecodeTwice("10086" + "111111" +     
                      "action_login"))//传入参数
                .build();
        final Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .build();
       final Response response = client.newCall(request).execute();
         if (response.isSuccessful()) {
        return response.body().string();
    } else {
        throw new IOException("Unexpected code " + response);
    }
}

//POST提交Json数据 
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();
    f (response.isSuccessful()) {
        return response.body().string();
    } else {
        throw new IOException("Unexpected code " + response);
    }
}

异步 Http Get

private void asyGet(String url) throws IOException {
       final Request request = new Request.Builder()
               .get()
               .tag(this)
               .url(url)
               .build();//Request是OkHttp中访问的请求,Builder是辅助类,Response即OkHttp中的响应
       final Response response = client.newCall(request).execute();
       Call call = client.newCall(request);
       /**
        * 我们希望以异步的方式去执行请求,所以我们调用的是call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。
        */
       call.enqueue(new Callback() {
           @Override
           public void onFailure(Call call, IOException e) {
               try {
                   throw new IOException("UnException code" + response);
               } catch (IOException e1) {
                   e1.printStackTrace();
               }
           }
           @Override
           public void onResponse(Call call, Response response) throws IOException {
               Log.i("info", "打印GET响应的数据::" + response.body().string());
           }
       });
   }

异步HTTP Post

private void asyPost(String url) throws IOException {
    RequestBody formBody = new FormBody.Builder()
            .add("u_Phone", "10086")
            .add("code", "111111")
            .add("encodestr", MD5Utils.ecodeTwice("10086" + "111111" + "action_login"))
            .build();
    final Request request = new Request.Builder()
            .url(url)
            .post(formBody)
            .build();
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.e("info", String.valueOf(e));
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.i("info", "打印POST响应的数据:" + response.body().string());
        }
    });
}

看了基本用法后是不是感觉入门也是十分简单,跟volley十分相似,但是有一点却是十分懵逼的- -。因为volley的每一个请求都需要加入到请求队列中,并且可以使用tag来取消当前网络请求,如下:

requestQueue.add(req);

于是用惯了volley的我就不能忍了,于是乎查资料,发现在okhttp的用法跟volley不一样,所以这个一时我就找不到这个tag的作用,一脸懵逼状- -。只允许设置tag,却没法用tag给取消这个请求,kiding me? 想想这么流行的框架不可能会留下这种低级错误啊,于是乎查看源码(似懂非懂–),Google,终于找到对应的解决方式:

public void cancelCallsWithTag(Object tag){

    if (tag == null || mOkHttpClient == null) {
        return;
    }

    synchronized (mOkHttpClient.dispatcher().getClass()) {
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }

        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) call.cancel();
        }
    }
}

最基本的用法了解了,是时候该着手进行简单的封装
这里主要用到 OkHttpClientManager类,与回调接收接口ResultCallback
偷懒一下 ,直接贴源码了,相应解释直接在代码中注释:

package com.okhttpstudy.okhttp;

/**
 * Created by hwei on 2016/7/8.
 */
public interface ResultCallback {

    public abstract void onError(String msg);

    public abstract void onResponse(String result);
}
package com.okhttpstudy.okhttp;

import android.app.Activity;

import com.okhttpstudy.utils.LogUti;

import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by hwei on 2016/7/8.
 */
public class OkHttpClientManager {
    private static OkHttpClientManager instance;
    private OkHttpClient mOkHttpClient;
    private static final String TAG = "OkHttpClientManager";

    public OkHttpClientManager() {
        //mOkHttpClient = new OkHttpClient();
        mOkHttpClient = new OkHttpClient.Builder()
                .connectTimeout(1000l, TimeUnit.MILLISECONDS)
                .readTimeout(10000L, TimeUnit.MILLISECONDS)
                //.cache(cache)
                .build();

        //cookie enabled
        //cookie相关的东西还有很多需要研究,以后慢慢补充
//        mOkHttpClient.cookieJar(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
    }

    public static OkHttpClientManager getInstance() {
        if (instance == null) {
            synchronized (OkHttpClientManager.class) {
                if (instance == null) {
                    instance = new OkHttpClientManager();
                }
            }
        }
        return instance;
    }


    public void cancelCallsWithTag(Object tag) {
        if (tag == null || mOkHttpClient == null) {
            return;
        }
        synchronized (mOkHttpClient.dispatcher().getClass()) {
            for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
                if (tag.equals(call.request().tag())) {
                    call.cancel();
                }
            }
            for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
                if (tag.equals(call.request().tag())) call.cancel();
            }
        }
    }
    public void getAsyn(final Activity activity, String url, Map<String, String> requestmap, final                  ResultCallback callback) {

        final Request request = new Request.Builder()
                .get()
                .tag(activity.getClass().getSimpleName())
                .url(onBuildGetParams(url, requestmap))//get请求,参数拼接
                .build();//Request是OkHttp中访问的请求,Builder是辅助类,Response即OkHttp中的响应
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onError(String.valueOf(e));
            }

            /**
             *
             * @param call
             * @param response
             * @throws IOException
             * onResponse回调的参数是response,一般情况下,比如
             * 我们希望获得返回的字符串,可以通过response.body().string()获取;
             * 如果希望获得返回的二进制字节数组,则调用response.body().bytes();
             * 如果你想拿到返回的inputStream,则调用response.body().byteStream()
             */
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (response.isSuccessful()) {
                    activity.runOnUiThread(new Runnable() {//用惯了volley的人初次搞这个可能都会习惯直接调用ui线程去更新ui,然后okhttp在这一点上一点却让人“不太省心”,我们必须自己进行线程切换
                        @Override
                        public void run() {
                            try {
                                callback.onResponse(response.body().string());
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                        }
                    });
                }
            }
        });
    }

    public void postAsyn(final Activity activity, String url, Map<String, String> requestmap, final         ResultCallback callback) {

        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        JSONObject jsonObject = new JSONObject(requestmap);
        RequestBody requestBody = RequestBody.create(JSON, String.valueOf(jsonObject));
        LogUti.i("info", "requestmapJson" + String.valueOf(jsonObject));
        Request request = new Request.Builder()
                .url(url)
                .tag(activity.getClass().getSimpleName())
                .post(requestBody)
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onError(String.valueOf(e));
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (response.isSuccessful()) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                callback.onResponse(response.body().string());
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        });
    }

/**
* get请求参数的封装,构造成与POST同样的调用方式
*/
    private String onBuildGetParams(String url, Map<String, String> map) {
        StringBuilder sb = new StringBuilder(url);
        boolean isFirst = true;
        if (map == null) {//没有参数时 直接返回url
            return sb.toString();
        }
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (isFirst) {
                isFirst = false;
                sb.append("?" + entry.getKey() + "=" + entry.getValue());
            } else {
                sb.append("&" + entry.getKey() + "=" + entry.getValue());
            }
        }
        LogUti.i("info", "url" + sb.toString());
        return sb.toString();
    }
}

如何使用:
//调用post请求
Map<String,String> map = new HashMap<>();
map.put("u_Phone","10086");
map.put("url","http://simple.cn/Service.php?a=checkMobile");
map.put("code","111111");
map.put("encodestr",MD5Utils.ecodeTwice("10086" + "111111" + "action_login"));
OkHttpClientManager.getInstance().postAsyn(this,"http://simple.cn/Service.php?a=checkMobile", map, new ResultCallback() {
    @Override
    public void onError(String msg) {
        LogUti.i("info","post onError" + msg);
    }
    
    @Override
    public void onResponse(final String result) {
        Toast.makeText(MainActivity.this,"result"+result ,Toast.LENGTH_LONG).show();
        LogUti.i("info","post onResponse result:" + result.toString());
    }
});


//调用get请求
Map<String,String> map = new HashMap<>();
       map.put("u_Phone","10086");
       map.put("url","http://simple.cn/Service.php?a=checkMobile");
       map.put("code","111111");
       map.put("encodestr",MD5Utils.ecodeTwice("simple" + "111111" + "action_login"));
       OkHttpClientManager.getInstance().postAsyn(this,"http://simple.cn/Service.php?a=checkMobile", map, new ResultCallback() {
           @Override
           public void onError(String msg) {
               LogUti.i("info","post onError" + msg);

           }

           @Override
           public void onResponse(final String result) {
               Toast.makeText(MainActivity.this,"result"+result ,Toast.LENGTH_LONG).show();
               LogUti.i("info","post onResponse result:" + result.toString());
           }
       });


//我们可以在每个页面销毁前取消对应tag的网络请求
@Override
  protected void onDestroy() {
      super.onDestroy();
      OkHttpClientManager.getInstance().cancelCallsWithTag(tag);
  }

只是简单的进行了封装,直接将网络响应结果回调给每个Activity,而没有进行统一的解析,这里有待改进。。。

上一篇 下一篇

猜你喜欢

热点阅读