Android中封装自己的SDK示例

转载于:http://blog.csdn.net/ryffic/article/details/44891899

这几天,忙的跟狗一样了。

新公司,新的责任。

最近,公司的一个新项目。我的工作,是负责安卓端网络通信层的编写。

其实,说实话,安卓项目经验也不是非常多。也是边学边成长吧。

最开始,我只是做一个简单的编写,利用Xutils框架,做了一个最简单的封装。

public void send(HttpMethod method, String url, RequestParams params) {

mHttpUtils.send(method, url, params, new RequestCallBack() {

@Override

public void onFailure(HttpException arg0, String arg1) {

}

@Override

public void onSuccess(ResponseInfo arg) {

}

});

}

说简单点,就是在框架上封装了一次,然后给业务层调用。

不过,项目经理看到这个以后,就屌我了:你这个不是网络通信层阿。只是一个方法而已。跟他进行沟通之后,了解到他的意思。他的想法是,业务层要进行网络通信时,只要调用某个业务,并传给参数给我,相应的url,请求方式t,都不是它关心的事。打个比方,现在有一个要登录的操作,业务层只要调用 login(参数)就可以了。

所以,我也在不停地尝试。

之后,回想到百度地图SDK中,有许多类似的例子。比如,现在我要做一个搜索Poi数据的操作,百度地图SDK也只有几步而已。

1:取得检索实例

2:设置监听

3:发起检索

简单的代码示例如下:

//取得Poi检索实例

mPoiSearch =PoiSearch.newInstance();

//设置监听

mPoiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {

@Override

public void onGetPoiResult(PoiResult result) {

}

@Override

public void onGetPoiDetailResult(PoiDetailResult result) {

});

//发起检索

mPoiSearch.searchInCity(new PoiCitySearchOption().city("北京").keyword("餐厅").pageNum(1).pageCapacity(10));

由百度地图的SDK,我突然想到,是不是,我也能参照这样的步骤,做一个类似的SDK,给业务层调用呢。

然后,我就开始写代码。这里,我用到的是百度地图LBS云检索的API来做示例。

首先,我得有一个监听函数。那么,我就先写一个简单的接口。

/**

*@类名称:OnResultListener

*@类描述:  结果回调

*@创建人:Yul_Wu

*@创建时间:2015年4月5日 下午10:08:15

*@修改人:Yul_Wu

*@修改时间:2015年4月5日 下午10:08:15

*@修改备注:

*@version

*

*/

public interface OnResultListener {

void reDraw(String result,int error);

}

然后,参照百度SDK的,我们还有一个检索的类GetBaiduSearch(以下称为检索类)

/**

*

*

*@项目名称:Result

*@类名称:GetBaiduSearch

*@类描述:  检索类

*@创建人:Yul_Wu

*@创建时间:2015年4月5日 下午10:11:02

*@修改人:Yul_Wu

*@修改时间:2015年4月5日 下午10:11:02

*@修改备注:

*@version

*

*/

public class GetBaiduSearch {

private static GetBaiduSearch baiduSearch;

private GetBaiduSearch() {

}

/**

* 取得实例

*

* @return

*/

public static GetBaiduSearch getInstance() {

if (baiduSearch == null) {

synchronized (GetBaiduSearch.class) {

baiduSearch = new GetBaiduSearch();

}

}

return baiduSearch;

}

可以看到,这是一个非常简单的单例模式,通过getInstance()的方法,我们可以取得该类的实例。那们,我们还要有一个设置监听的方法,就叫setOnResultListener好了,那么代码就成这样了

public class GetBaiduSearch {

OnResultListener listener = null;

private static GetBaiduSearch baiduSearch;

private GetBaiduSearch() {

}

/**

* 取得实例

*

* @return

*/

public static GetBaiduSearch getInstance() {

if (baiduSearch == null) {

synchronized (GetBaiduSearch.class) {

baiduSearch = new GetBaiduSearch();

}

}

return baiduSearch;

}

public void setOnResultListener(OnResultListener listener) {

        this.listener = listener;

        this.listener.reDraw(“要回调的具体内容”, 0);

    }

这样,我们一个简单的回调函数,以及简单方法就写好了。接下来,我们来测试一下,在MainActivity中,我们做一个非常简单的测试。

mSearch= GetBaiduSearch.getInstance();

button.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

mSearch.setOnResultListener(new OnResultListener() {

@Override

public void reDraw(String result, int error) {

// TODO Auto-generated method stub

Log.v("yul_wu", result);

}

});

}

});

我们运行程序,点击Button,可以看到logcat上的输出:

这说明我们的数据成功返回了。

那么,接下来呢,我们再给检索类加上一个方法,也就是我们检索的主入口。

public void searchGeoTable() {

//这里用的是百度地图LBS云检索的例子,把通过API获得的数据返回给我们的监听函数

HttpUtils utils = new HttpUtils();

RequestParams params = new RequestParams();

String url = "http://api.map.baidu.com/geodata/v3/geotable/list";

params.addQueryStringParameter("ak", "百度地图的ak");

utils.send(HttpMethod.GET, url, params, new RequestCallBack() {

@Override

public void onFailure(HttpException arg0, String result) {

}

@Override

public void onSuccess(ResponseInfo result) {

if (result.statusCode == 0 || result.statusCode == 200) {

}

}

});

}

那么,我们修改一下MainActivity中的代码:

mSearch= GetBaiduSearch.getInstance();

mSearch.setOnResultListener(new OnResultListener() {

@Override

public void reDraw(String result, int error) {

Log.v("yul_wu", result);

}

});

button.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

mSearch.searchGeoTable();

}

});

可以看到,我们做完这些修改以后,是不是就跟百度SDK中的代码操作是不是一样了。

那么,接下来,我们怎么把通过http请求的数据回传给我们的调用处呢。最初的想法,我是在检索类中,我们定义一个变量result,然后再上面的OnSuccess中,去设置result的值,改完之后的代码如下:

private void setResult(String str){

this.result = str;

}

public void setOnResultListener(OnResultListener listener) {

this.listener = listener;

this.listener.reDraw(this.result, 0);

}

public void SearchGeoTable() {

HttpUtils utils = new HttpUtils();

RequestParams params = new RequestParams();

String url = "http://api.map.baidu.com/geodata/v3/geotable/list";

params.addQueryStringParameter("ak", "你的百度AK");

utils.send(HttpMethod.GET, url, params, new RequestCallBack() {

@Override

public void onFailure(HttpException arg0, String result) {

}

@Override

public void onSuccess(ResponseInfo result) {

if (result.statusCode == 0 || result.statusCode == 200) {

setResult(result.result);

}

}

});

}

也就是我们在网络请求中,设置了result的值,然后再回传。接下来我们运行,发现,报空指针了.....

看这个错误日志,是说Log里的result是空的,而且,在我还没有点击按钮的时候,就已经报错了。这是为什么呢。其实,是我自己发蒙了。因为设置监听函数的时候,已经执行了redeaw这个方法了。所以,这个方法不能放在这里。那应该放在哪呢。(当然放在onSuccess方法中阿,这个简单你都不知道,博主是不是傻了。)

其实,我真是傻了。因为,代码写太多,脑子都乱掉了。我们再做一下修改,把redraw方法放在网络请求成功后的方法里,把没用的删掉,就成这样了。

public class GetBaiduSearch {

OnResultListener listener = null;

private static GetBaiduSearch baiduSearch;

private GetBaiduSearch() {

}

/**

* 取得实例

*

* @return

*/

public static GetBaiduSearch getInstance() {

if (baiduSearch == null) {

synchronized (GetBaiduSearch.class) {

baiduSearch = new GetBaiduSearch();

}

}

return baiduSearch;

}

/**

* 设置监听

* @param listener

*/

public void setOnResultListener(OnResultListener listener) {

this.listener = listener;

}

public void searchGeoTable() {

HttpUtils utils = new HttpUtils();

RequestParams params = new RequestParams();

String url = "http://api.map.baidu.com/geodata/v3/geotable/list";

params.addQueryStringParameter("ak", "你的百度AK");

utils.send(HttpMethod.GET, url, params, new RequestCallBack() {

@Override

public void onFailure(HttpException arg0, String result) {

}

@Override

public void onSuccess(ResponseInfo result) {

if (result.statusCode == 0 || result.statusCode == 200) {

listener.reDraw(result.result, 0);

}

}

});

}

}

然后,我们运行程序,程序没有报错吧。接下来,我们点击Buttou,是不是结果成功返回了!

如果做过百度LBS云开发的朋友,看到这个字符串肯定不陌生哈。说明我们的数据已经成功能过我们的回调函数返回了。这样,我们就完成了一个简单的模型。

接下来,我们再做一步封装,把参数封装成百度SDK的样子,

public class BaiduSearchOptions {

private String ak;

public BaiduSearchOptions() {

}

public BaiduSearchOptions ak(String ak) {

this.ak = ak;

return this;

}

}

这样,我们再把检索类中的方法修改一下,

public void SearchGeoTable(BaiduSearchOptions option) {

HttpUtils utils = new HttpUtils();

//通过反射,取得参数里的值和字段名

RequestParams params = option.reflect(option);

String url = "http://api.map.baidu.com/geodata/v3/geotable/list";

utils.send(HttpMethod.GET, url, params, new RequestCallBack() {

@Override

public void onFailure(HttpException arg0, String result) {

}

@Override

public void onSuccess(ResponseInfo result) {

if (result.statusCode == 0 || result.statusCode == 200) {

listener.reDraw(result.result, 0);

}

}

});

}

}

看一下我们的reflect方法:

public RequestParams reflect(Object obj) {

RequestParams params = new RequestParams();

String key =null;

String value =null;

if (obj == null)

params= null;

Field[] fields = obj.getClass().getDeclaredFields();

for (int j = 0; j < fields.length; j++) {

fields[j].setAccessible(true);

// 字段名

key = fields[j].getName();

System.out.print(fields[j].getName() + ":");

// 字段值

if (fields[j].getType().getName()

.equalsIgnoreCase("java.lang.String")) {

try {

value= fields[j].get(obj).toString();

System.out.print(fields[j].get(obj) + "    ");

} catch (Exception e) {

e.printStackTrace();

}

}

}

params.addQueryStringParameter(key,value);

return params;

}

那么,我们检索的时候,是不是就变成这样了:

BaiduSearchOptions options = new BaiduSearchOptions().ak("你的百度AK");

mSearch.SearchGeoTable(options);

现在看一下,是不是就跟百度SDK检索的操基本一样了。这样,以后业务层调用的时候,只要给出参数,我们就可以把结果回传给调用者。调用于就不用去考虑Http请求那些东西了。当然,你还可以根据不同的业务,再次把返回的result进行封装,这里我就不多做介绍了。

好了,那么关于回调函数的内容就到这里了!

---------------------分割线----------------------------

另外附上关于SDK开发一位大神的总结:

作者:neevek

链接:https://www.zhihu.com/question/36520512/answer/68177050

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

SDK 一般以一个或多个 jar 文件加上资源文件的形式对外开放,当然也可以把资源文件打包到 jar 中,这样别人接入你的 SDK 所需要的配置就非常简单了,只需要引入一个 jar 文件就可以了。 (我自己用的是第二种方式,资源文件包括图片、XML文件、动态链接库等)。

多数 SDK 都是需要 UI 的,有两种方式在一个 jar 里面实现 UI。第一种是用 Java 实现所有界面布局,很多 SDK 这样做,但这并不是最好的方法,这样实现起来麻烦,一个简单的界面要写很多的代码,维护肯定也不简单。第二种方法是像平常写 app 一样用 XML 写布局,然后用 aapt 编译这些 XML(不同于代码编译,实际上是把 XML 转换成另外一种 Android 的布局系统更容易解析的一种格式 :They call it compiled XML),在代码中通过反射使用 XmlPullParser,inflate 出 XML 中的布局,这样比 Java 实现要简单得多,代码也更容易维护。

目前应该也可以把 SDK 打包成 aar,那样应该就可以完全跟开发 app 一样了,不需要像上面那么复杂,但我没试过,不太清楚。目前市场上的 SDK 大多都还是 jar 的形式。

剩下的是一些个人实践中的一些总结,不一定对,仅供参考:

1. 暴露的接口尽可能少,最大程度减少 SDK 接入方需要了解的细节。

2. 统一所有接口调用方式,我实现过的一个 SDK 其中的一个接口签名:SDK.exec(Context, Action, Callback),Action 可以有每个不同业务的不同参数。

---------------------关于SDK开发我自己的总结---------------------------

我觉的SDK开发经常用到的东西有如下:

1. java中的泛型

2.反射

3.接口回调

3.设计模式(常用的单例,工厂,观察者,代理,适配器,装饰器)

4.就是写UI布局(如上面大神说的)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容