Android中封装自己的SDK示例和自己的总结

本文分享了在新项目中负责安卓端网络通信层开发的经验,通过参考百度地图SDK的设计思路,逐步实现了从简单封装到高级封装的过程。文章详细介绍了如何使用回调函数、单例模式及反射等技术手段构建易用的网络通信层。

下面是转载于:http://blog.youkuaiyun.com/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布局(如上面大神说的)

List of Sample Apps The list below provides a summary of the sample applications that are available with the Android SDK. Using the links on this page, you can view the source files of the sample applications in your browser. You can also download the source of these samples into your SDK, then modify and reuse it as you need. For more information, see Getting the Samples. API Demos A variety of small applications that demonstrate an extensive collection of framework topics. Backup and Restore A simple example that illustrates a few different ways for an application to implement support for the Android data backup and restore mechanism. Bluetooth Chat An application for two-way text messaging over Bluetooth. BusinessCard An application that demonstrates how to launch the built-in contact picker from within an activity. This sample also uses reflection to ensure that the correct version of the contacts API is used, depending on which API level the application is running under. Contact Manager An application that demonstrates how to query the system contacts provider using the ContactsContract API, as well as insert contacts into a specific account. Home A home screen replacement application. JetBoy A game that demonstrates the SONiVOX JET interactive music technology, with JetPlayer. Live Wallpaper An application that demonstrates how to create a live wallpaper and bundle it in an application that users can install on their devices. Lunar Lander A classic Lunar Lander game. Multiple Resolutions A sample application that shows how to use resource directory qualifiers to provide different resources for different screen configurations. Note Pad An application for saving notes. Similar (but not identical) to the Notepad tutorial. SampleSyncAdapter Demonstrates how an application can communicate with a cloud-based service and synchronize its data with data stored locally in a content provider. The sample uses two related parts of the Android framework — the account manager and the synchronization manager (through a sync adapter). Searchable Dictionary A sample application that demonstrates Android's search framework, including how to provide search suggestions for Quick Search Box. Snake An implementation of the classic game "Snake." Soft Keyboard An example of writing an input method for a software keyboard. Spinner A simple application that serves as an application-under-test for the SpinnerTest sample application. SpinnerTest An example test application that contains test cases run against the Spinner sample application. To learn more about the application and how to run it, please read the Activity Testing tutorial. TicTacToeLib An example of an Android library project that provides a game-play Activity to any dependent application project. For an example of how an application can use the code and resources in an Android library project, see the TicTacToeMain sample application. TicTacToeMain An example of an Android application that makes use of code and resources provided in an Android library project. Specifically, this application uses code and resources provided in the TicTacToeLib library project. Wiktionary An example of creating interactive widgets for display on the Android home screen. Wiktionary (Simplified) A simple Android home screen widgets example.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值