用多了OkHttp你会发现,它的返回结果都是在子线程中的,我们对返回结果进行解析后,必须通过handler去更新UI,这么一来,便会多出很多重复的机械代码。我们需要进行一层封装,在onResponse回调方法中对返回结果进行解析,然后将解析结果发出去到UI线程进行更新UI。
因此,我们需要一个解析的方法,我们定义一个接口。
public interface Parser<T> {T parse(Response response);}
该接口传入okhttp给我们返回的Response ,我们将其进行解析,,具体怎么解析由我们自己实现,比如直接返回字符串形式,或者将json转化为实体类返回等等。
然后我们默认提供几种实现,首先是直接返回字符串。
<String> {@Overridepublic String parse(Response response) {String result=null;try {result=response.body().string();} catch (IOException e) {e.printStackTrace();}return result;}}
再实现一个将json转化为实体类的。这个相对复杂一点,需要将实体类的Class对象传入,因为我们使用的是gson,进行转换的时候需要该参数。当然这个应该是对所有实体类通用的,很显然的用到了泛型。
<Class<T> mClass=null;public GsonParser(Class<T> clazz){if (clazz==null){throw new IllegalArgumentException(“Class can’t be null”);}this.mClass=clazz;}@Overridepublic T parse(Response response) {try {Gson gson=new Gson();String str=response.body().string();T t=gson.fromJson(str,mClass);return t;} catch (IOException e) {e.printStackTrace();}return null;}}
要在UI层进行更新UI,其实很简单,解析完成后发生一个消息就好了,那么要怎么做呢。
首先实现Callback接口
<Parser<T> mParser;public Callback(Parser<T> mParser) {if (mParser == null) {throw new IllegalArgumentException(“Parser can’t be null”);}this.mParser = mParser;}@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(Response response) throws IOException {}}
通过构造函数将我们的Parser传递了进去。
现在假设,我们已经定义好了Handler对象,则在请求失败的时候我们需要发送一个失败的消息
应该有两个区别消息的常量
CALLBACK_SUCCESSFUL=0x01;CALLBACK_FAILED=0x02;
请求失败后发送失败的消息
public void onFailure(Request request, IOException e) {Message message=Message.obtain();message.what=CALLBACK_FAILED;message.obj=e;mHandler.sendMessage(message);}
请求成功的回调的处理看个人情况了,这里认为响应码是2开头的就是请求成功,否则也认为是失败,比如400,500。如果请求成功了就调用Parser的parse方法解析
public void onResponse(Response response) throws IOException {if (response.isSuccessful()) {T parseResult = mParser.parse(response);Message message=Message.obtain();message.what=CALLBACK_SUCCESSFUL;message.obj=parseResult;mHandler.sendMessage(message);} else {Message message=Message.obtain();message.what=CALLBACK_FAILED;mHandler.sendMessage(message);}}
剩下的就是我们的Handler了,我们把它定义成静态的,防止内存泄露,由于需要调用外部类的方法,所有还需要持有外部类的引用,同样的防止内存泄露,使用弱引用。同时记得使用主线程的Looper。
<WeakReference mWeakReference;public UIHandler(cn.edu.zafu.coreokhttp.callback.Callback<T> callback){super(Looper.getMainLooper());mWeakReference=new WeakReference(callback);}@Overridepublic void handleMessage(Message msg) {}}private Handler mHandler=new UIHandler(this);
接下来就是handleMessage方法的处理了。
public void handleMessage(Message msg) {switch (msg.what){case CALLBACK_SUCCESSFUL: {T t = (T) msg.obj;cncallback = (cn) mWeakReference.get();if (callback != null) {callback.onResponse(t);}break;}case CALLBACK_FAILED: {IOException e = (IOException) msg.obj;cncallback = (cn) mWeakReference.get();if (callback != null) {callback.onFailure(e);}break;}default:super}}
从代码中看到,我们回调了两个函数,没错,这两个是空函数,由用户去覆盖重写实现
(T t){}(IOException e){}
这样有什么好处呢?
Parser可以重复使用,避免多次解析使用同样的代码避免编写多次Handler去处理UI层更新
现在我们看看如何使用。
我们简单的使用StringParser进行解析返回结果
OkHttpClient okHttpClient=new OkHttpClient();StringParser parser=new StringParser();Request request = new Request.Builder().url(“https://www.baidu.com”).build();okHttpClient<String>(parser) {@Overridepublic void onResponse(String s) {Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();}});
从代码中看到,我们重写了我们定义的空函数,直接用Toast显示出了解析结果。
在一定程度上简化了原来的代码。但是还不够精简,请期待后续的封装。
源码下载 –
钱财何足贵,仁义值千金。