Android 基于OkHttp的UI层回调封装
2015-10-08 16:09
393 查看
用多了OkHttp你会发现,它的返回结果都是在子线程中的,我们对返回结果进行解析后,必须通过handler去更新UI,这么一来,便会多出很多重复的机械代码。我们需要进行一层封装,在onResponse回调方法中对返回结果进行解析,然后将解析结果发出去到UI线程进行更新UI。
因此,我们需要一个解析的方法,我们定义一个接口。
该接口传入okhttp给我们返回的Response ,我们将其进行解析,具体怎么解析由我们自己实现,比如直接返回字符串形式,或者将json转化为实体类返回等等。
然后我们默认提供几种实现,首先是直接返回字符串。
再实现一个将json转化为实体类的。这个相对复杂一点,需要将实体类的Class对象传入,因为我们使用的是gson,进行转换的时候需要该参数。当然这个应该是对所有实体类通用的,很显然的用到了泛型。
要在UI层进行更新UI,其实很简单,解析完成后发生一个消息就好了,那么要怎么做呢。
首先实现Callback接口
通过构造函数将我们的Parser传递了进去。
现在假设,我们已经定义好了Handler对象,则在请求失败的时候我们需要发送一个失败的消息
应该有两个区别消息的常量
请求失败后发送失败的消息
请求成功的回调的处理看个人情况了,这里认为响应码是2开头的就是请求成功,否则也认为是失败,比如400,500。如果请求成功了就调用Parser的parse方法解析
剩下的就是我们的Handler了,我们把它定义成静态的,防止内存泄露,由于需要调用外部类的方法,所有还需要持有外部类的引用,同样的防止内存泄露,使用弱引用。同时记得使用主线程的Looper。
接下来就是handleMessage方法的处理了。
从代码中看到,我们回调了两个函数,没错,这两个是空函数,由用户去覆盖重写实现
这样有什么好处呢?
Parser可以重复使用,避免多次解析使用同样的代码
避免编写多次Handler去处理UI层更新
现在我们看看如何使用。
我们简单的使用StringParser进行解析返回结果
从代码中看到,我们重写了我们定义的空函数,直接用Toast显示出了解析结果。
在一定程度上简化了原来的代码。但是还不够精简,请期待后续的封装。
源码下载
- http://download.csdn.net/detail/sbsujjbcy/9163435
因此,我们需要一个解析的方法,我们定义一个接口。
{ T parse(Response response); } " data-snippet-id="ext.cec61e79aa461b746feef11602eb4015" data-snippet-saved="false" data-csrftoken="FFB8F3V0-cMZ5HYXGR2ciooUmZ0MydkD49ok" data-codota-status="done">[code]public interface Parser<T> { T parse(Response response); }
该接口传入okhttp给我们返回的Response ,我们将其进行解析,具体怎么解析由我们自己实现,比如直接返回字符串形式,或者将json转化为实体类返回等等。
然后我们默认提供几种实现,首先是直接返回字符串。
{ @Override public String parse(Response response) { String result=null; try { result=response.body().string(); } catch (IOException e) { e.printStackTrace(); } return result; } }" data-snippet-id="ext.516a89f6a521c25637bfc09af9f05630" data-snippet-saved="false" data-csrftoken="y3cxcXmx-n-JLN_KclziMMzSOdhEgpZDwWcc" data-codota-status="done">[code]public class StringParser implements Parser<String> { @Override public String parse(Response response) { String result=null; try { result=response.body().string(); } catch (IOException e) { e.printStackTrace(); } return result; } }
再实现一个将json转化为实体类的。这个相对复杂一点,需要将实体类的Class对象传入,因为我们使用的是gson,进行转换的时候需要该参数。当然这个应该是对所有实体类通用的,很显然的用到了泛型。
implements Parser { private Class mClass=null; public GsonParser(Class clazz){ if (clazz==null){ throw new IllegalArgumentException("Class can't be null"); } this.mClass=clazz; } @Override public 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; } } " data-snippet-id="ext.eb19a9e01dbbd2b4c51c65e05d4020f0" data-snippet-saved="false" data-csrftoken="IZar1yFn-UJkcVXawAxgbtZEYAKOCG964lOA" data-codota-status="done">[code]public class GsonParser<T> implements Parser<T> { private Class<T> mClass=null; public GsonParser(Class<T> clazz){ if (clazz==null){ throw new IllegalArgumentException("Class can't be null"); } this.mClass=clazz; } @Override public 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接口
implements com.squareup.okhttp.Callback { private Parser mParser; public Callback(Parser mParser) { if (mParser == null) { throw new IllegalArgumentException("Parser can't be null"); } this.mParser = mParser; } @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { } } " data-snippet-id="ext.7e4050d9ffcd016000b2d5fce948b0e4" data-snippet-saved="false" data-csrftoken="3LIOZuhp-3Fb7sxOuPVtPQBo_1fubSAlgGkE" data-codota-status="done">[code]public class Callback<T> implements com.squareup.okhttp.Callback { private Parser<T> mParser; public Callback(Parser<T> mParser) { if (mParser == null) { throw new IllegalArgumentException("Parser can't be null"); } this.mParser = mParser; } @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { } }
通过构造函数将我们的Parser传递了进去。
现在假设,我们已经定义好了Handler对象,则在请求失败的时候我们需要发送一个失败的消息
应该有两个区别消息的常量
private static final int CALLBACK_SUCCESSFUL=0x01; private static final int 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。
extends Handler{ private WeakReference mWeakReference; public UIHandler(cn.edu.zafu.coreokhttp.callback.Callback callback){ super(Looper.getMainLooper()); mWeakReference=new WeakReference(callback); } @Override public void handleMessage(Message msg) { } } private Handler mHandler=new UIHandler(this);" data-snippet-id="ext.f51a388bd196ac6782b89d87fe2e01fd" data-snippet-saved="false" data-csrftoken="WyHTOoMS-rPdG952wjFxjTAikJsxdDhHQ54A" data-codota-status="done">[code]static class UIHandler<T> extends Handler{ private WeakReference mWeakReference; public UIHandler(cn.edu.zafu.coreokhttp.callback.Callback<T> callback){ super(Looper.getMainLooper()); mWeakReference=new WeakReference(callback); } @Override public 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; cn.edu.zafu.coreokhttp.callback.Callback callback = (cn.edu.zafu.coreokhttp.callback.Callback) mWeakReference.get(); if (callback != null) { callback.onResponse(t); } break; } case CALLBACK_FAILED: { IOException e = (IOException) msg.obj; cn.edu.zafu.coreokhttp.callback.Callback callback = (cn.edu.zafu.coreokhttp.callback.Callback) mWeakReference.get(); if (callback != null) { callback.onFailure(e); } break; } default: super.handleMessage(msg); break; } }
从代码中看到,我们回调了两个函数,没错,这两个是空函数,由用户去覆盖重写实现
public void onResponse(T t){ } public void onFailure(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.newCall(request).enqueue(new cn.edu.zafu.coreokhttp.callback.Callback<String>(parser) { @Override public void onResponse(String s) { Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show(); } });
从代码中看到,我们重写了我们定义的空函数,直接用Toast显示出了解析结果。
在一定程度上简化了原来的代码。但是还不够精简,请期待后续的封装。
源码下载
- http://download.csdn.net/detail/sbsujjbcy/9163435
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories