手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(二)
点击查看上一篇文章:手把手教你如何搭建一个自己的安卓快速开发框架之BaseActivity(一)
继上一篇我实现了基本的BaseActivity,包含
- ToolBar
- 透明状态栏
- 生命周期监控
那么,这一篇,我准备引入:
- OkHttp 3.3.1(引用鸿洋的一个OkhttpUtil)
- EventBus 3.0
- Json解析
- ButterKnife8.5.1
来完善我们的快速开发框架。
上次本来说这篇引入RXJava+retrofit,然后再引入MVP,但是突然发现过渡是不是有点太突然。
因此我准备循序渐进,慢慢深入,所以这次我们先用OKhttp+EventBus,去实现一次网络请求并完成界面异步更新。
1、首先第一:明确我们服务返回的JSON数据格式:
我们暂且称为BaseData。
{
"message": "ok",
"nu": "7700008953907",
"ischeck": "1",
"condition": "F00",
"com": "yunda",
"status": "200",
"state": "3",
"data": [
{
"time": "2017-02-14 19:14:27",
"ftime": "2017-02-14 19:14:27",
"context": "[陕西西安东郊区兴庆公园公司理工大分部]快件已被 已签收 签收",
"location": "陕西西安东郊区兴庆公园公司理工大分部"
},
{
"time": "2017-02-12 23:26:15",
"ftime": "2017-02-12 23:26:15",
"context": "[上海分拨中心]进行装车扫描,即将发往:陕西西安分拨中心",
"location": "上海分拨中心"
},
{
"time": "2017-02-12 23:21:52",
"ftime": "2017-02-12 23:21:52",
"context": "[上海分拨中心]在分拨中心进行称重扫描",
"location": "上海分拨中心"
},
]
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
2、第二:我们有一个get请求的URL:
http://www.kuaidi100.com/query
有2个参数 type=yunda&postid=7700008953907。
3、第三:
明确我们希望看到的请求方式:
Ok_Request.getAsyncData(this, map, UrlUtil.GetKuaiDi, new MyStringCallBack() {
@Override
public void onResponse(BaseData response, int id) {
List<dataModel> resultlist= null;
if (response != null) {
resultlist=response.getData();
}
//EventBus.getDefault().post(resultlist);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
发送一次get请求,Map里面是我们需要提交的参数。 最后在onResponse方法中得到我们想要的返回结果response,它是通过BaseData做了一层封装的。
4、第四:
请求结束,通过 EventBus.getDefault().post(resultlist);发送接收到的Json数据以供处理。并且通过dataEvent方法接收数据。ThreadMode.MAIN指定在主线程处理数据。
@Subscribe(threadMode = ThreadMode.MAIN)
public void dataEvent(List<dataModel> resultlist) {
tv.setText(resultlist.toString());
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
一次流程就这么走完了,但是从哪儿能看出我们这是一个框架呢?
1. BaseData
我们明确服务端的数据格式务必统一为BaseData,方便安卓端封装解析方法,直接返回需要的data字段。
2. getAsyncData
精简的请求方式,传入参数,URL,CallBack,在onresponse中处理结果即可。
3. BindView
所有界面省略繁琐的findviewById方法,采用ButterKnife注解生成,包括点击事件。
这里,第一和第三比较简单,第一点很必要,因为这直接决定了APP端的封装完整度和简洁度。第三点会用就行。所以,我们下来重点阐述第二点:
本来,OkhttpUtil的用法是这样的:
OkHttpUtils
.get()
.params(map)
.tag(mContext)
.url(url)
.build()
.execute(new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
}
@Override
public void onResponse(String response, int id) {
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
直接放到Activity中有以下几个缺点:
- 每个页面都得写这样一段。
- 如果一个页面3个请求就得写三个这样的代码段。
- 突然OKhttpUtil出Bug了需要修改为Volley,难道每个页面都要改吗?!
因此,我们需要做个封装:
/**
* Created by QHT on 2017-04-05.
*
* GET,PUT等网络操作类
*/
public class Ok_Request {
public static MediaType JSON = MediaType.parse("application/json;charset=utf-8");
/**
* GET方式
* 异步get请求
* @param url
*/
public static void getAsyncData(Context mContext, HashMap<String,String> map,final String url, Callback callback) {
OkHttpUtils
.get()
.params(map)
.tag(mContext)
.url(url)
.build()
.execute(callback);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
在Activity中调用Ok_Request.getAsyncData方法传入一个匿名CallBack即可。如下:
private static int Ok_count=2;
HashMap<String, String> map = new HashMap<>();
/**
* 参数
*/
map.put("type", "yunda");
map.put("postid", "7700008953907");
Ok_Request.getAsyncData(this, map, UrlUtil.GetKuaiDi, new MyStringCallBack() {
/**
* UI Thread
*/
@Override
public void onBefore(Request request, int id) {
DialogUtil.showProgressDialog(MainActivity.this, true);
}
@Override
public void onAfter(int id) {
--Ok_count;
if(Ok_count==0){
DialogUtil.hideProgressDialog();
}
}
@Override
public void onError(Call call, Exception e, int id) {
ToastUtil.showToastLong(e.getMessage());
}
@Override
public void onResponse(BaseData response, int id) {
List<dataModel> resultlist= null;
if (response != null) {
resultlist=response.getData();
}
EventBus.getDefault().post(resultlist);
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
共四个回调方法onBefore,onAfter,onResponse,onError。
- onBefore方法中我们显示一个dialog“加载中…”
- onAfter方法中我们dismiss这个dialog
- onResponse方法中处理服务端返回的数据
- onError方法中进行异常处理
如上,我们已经完成了我们的网络请求。但是,如果我们一个页面不止一次请求呢,有两次呢?我们怎么控制dialog何时隐藏?
这个时候,我们就需要一个计数器Ok_count,在onAfter方法中执行Ok_count减一,并且判断Ok_count是否为0,若为0才允许隐藏dialog。(类似于同步计数器CountDownLatch类)
说完了请求,下来我们来说说Json
默认情况下,Okhttp返回的数据为Response,那么我们就来一步一步写自己的解析方式:
请求结束之后,数据层首先执行parseNetworkResponse方法(此方法运行在子线程),返回一个Response,在这里,我们对需要的数据进行处理:
/**
* Created by QHT on 2017-04-05.
*/
public abstract class MyStringCallBack extends Callback<BaseData>{
/**
* Thread Pool Thread
* @param response
* @param id
*/
@Override
public BaseData parseNetworkResponse(Response response, int id) throws Exception {
String temp=response.body().string();
BaseData baseData = GsonUtils.jsonToModel(temp, BaseData.class);
return baseData;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
解析的代码如下:
public static <T> T jsonToModel(String json,Class<T> clazz) {
if (TextUtils.isEmpty(json) || null == clazz) {
return null;
}
try {
return gson.fromJson(json, clazz);
}catch (Exception e){
e.printStackTrace();
LogUtil.e("服务端接口json数据格式异常:"+e.getMessage());
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 通过response.body().string()可以拿到返回的String。
- 通过我们写好的Json解析类可以将String解析为我们最外层的BaseData。
- 固定服务端返回数据格式的重要作用就在这儿(统一处理)
接下来,回调onResponse方法,参数为我们上面返回的BaseData,onResponse方法最后就变成了这样:
@Override
public void onResponse(BaseData response, int id) {
List<dataModel> resultlist= null;
if (response != null) {
resultlist=response.getData();
}
EventBus.getDefault().post(resultlist);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
要什么,在BaseData 中取什么就行。
下一篇,我准备开始完善功能了,加入:
- BaseFrament
- 微信底部4按钮切换
- 登录功能
- 快递追踪功能
最后,我将代码上传到github上,持续更新,逐渐完善这个简易框架。
我的QQ: 1003077897
我的csdn:http://blog.csdn.net/u012534831
我的github:https://github.com/qht1003077897
我的个人博客:https://qht1003077897.github.io