这是一个基于HttpUrlConnection的Android异步网络框架。
##特点:
- 高度的可配置化.全局配置与单次事件配置都是可控的.
- 支持请求的重试,重定义,代理,认证,取消等.
- 支持自动化的Cookie管理
- 支持http缓存.
- 实现请求参数的封装与响应的回调.
- 支持Http的所有谓词,支持异步与同步两种调用方式.
- 支持其它异步任务的回调.
- 连缀式调用方式,希望你喜欢.
- 其实它还有更多,等待你去发现.
##使用
####1.添加引用
- Eclipse
下载jar文件Download,添加至项目的libs目录下. - Gradle
在build.gradle文件中如下配置
dependencies {
compile 'com.bsince.event:library:1.0.3'
}
####2.配置
你需要在你项的Application的子类中(如果没有继承自该类,需要建类继承,并在Manifest文件中注册)的oncreate方法中进行相关参数的配置.
public class AppContext extends Application {
@Override
public void onCreate() {
super.onCreate();
HttpGlobalConfiguration globalConfiguration
= new HttpGlobalConfiguration.Builder()
.connectTimeOut(5000)
.readTimeOut(5000)
.bufferSize(2048)
.debug(true)
.endPoint("http://192.168.1.109:8080")
.userAgent("Bsince/test/engine")
.useCookie(true)
.engineType(EngineType.Engine_Bsince)
.threadSize(3)
.defaultAllowRedirect(false)
.keepAlive(true)
// .proxy(...)
// .urlRewriter(...)
// .defaultSSLSocketFactory(...)
// .defaultHostnameVerifier(...)
// .defaultContentHandlerFactory(...)
// .authenticator(...)
// .cookieHandler(...)
// .netCacheDir(...)
//more you want ...
.retryCount(2)
.addDefaultRequestProperty("customHeader", "customerHeaderValue")
.build(this);
EventPublisher.init(globalConfiguration);
}
}
上面的每一项配置都不是必须的,因为程序会默认一个值,如果你不想改变它,可以直接像下面这样
```Java HttpGlobalConfiguration globalConfiguration= new HttpGlobalConfiguration.Builder().build(this); EventPublisher.init(globalConfiguration); ```
####3.调用 完成如上配置后,你就可以愉快地开发了。比如 #####Get请求
EventPublisher.connect(String.class, "http://www.baidu.com")
.tag("baidu")
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
}
@Override
public void onErrorResponse(Exception e) {
editext.setText(e.toString());
}
});
#####Post请求
FormEncodeDataSet ds = new FormEncodeDataSet();
ds.put("name", "张三");
ds.put("pwd", "123456");
EventPublisher.connect(String.class, "/HttpService/login")
.data(ds)
.method(Method.POST)
.tag("login")
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
}
@Override
public void onErrorResponse(Exception e) {
editext.setText(e.toString());
}
});
注意:在使用EventPublisher.Connect("")时,未指定method将会被默认成GET请求,上面示例中FormEncodeDataset是用于封装请求参数的实体类,Get请求也可以使用.data()方法来指定请求参数,请求参数将默认以表单提交的方式追加到Url后面
如果你的返回类型不是String类型,你还必须为其指定一个parser作为解析器,我们为你提供以下几种默认的解析器,以便你针对不同情况时使用:
- BitmapParserImp //默认解析后返回Bitmap对象
- FileDownloadParser // 默认解析后返回文件对象
- JSONArrayParserImp //抽象类,返回jsonArray由你去实现将其转换为javaBean对象
- JSONObjectParserImp // 抽象类,返回JsonObject由你去实现将其转换为javaBean对象
- SimpleParserImp //抽象类,返回String由你去实现将其转换为javaBean对象
- TextParserImp //默认返回String字符串
- XmlParserImp //抽象类,返回Xmlpullparser由你去实现将其转换为javaBean对象
如下是使用JSONObjectParserImp的示例
EventPublisher.connect(User.class,"/login?....")
.parser(new JSONObjectParserImp<User>() {
@Override
public User parsed(JSONObject object, Headers mHeaders) throws ParseException {
User u = new User();
u.name = object.optString("name");
u.value =object.optString("value");
return u;
}
})
.submit(new ResponseListener<User>() {
@Override
public void onSuccessResponse(User response) {
editext.setText(response.name);
}
@Override
public void onErrorResponse(Exception error) {
editext.setText(e.toString());
}
});
#####3. File Upload
BsinceEvent支持File与InputStream两种形式的文件上传
MulitDataSet ds = new MulitDataSet();
ds.put("title", "xxxxx");
ds.put("videofile", file,filename);
ds.put("stream", is, streamName);
EventPublisher.connect(String.class, "/HttpService/upload")
.method(Method.POST)
.data(ds)
.tag("upload")
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
dialog.dismiss();
}
@Override
public void onErrorResponse(Exception e) {
dialog.dismiss();
editext.setText(e.toString());
}
});
相信你也发现了,这里我们用的是MulitDataset来封装参数.是的我们为你提拱了以下几种Dataset的实现
- JsonDataSet
用来传输Json格式的字符参数 - JsonStreamDataSet
将文件流转化为Json形式上传,支持Gzip压缩 - FormEncodeDataset
普通的表单提交,支持集合类型 - NameValueDataSet
键值对型,与FormEncodeDataSet功能近似,支持集合类型,但集合若有序键会追加下标(eg:key[index]) - SoapDataSet
构建webService服务的请求参数,下面会提到
到这里,也许关于文件上传就差不多了,文件、流、都能上传,甚至可以Gzip压缩成Json字符串上传,如此说来确实很方便。但是? 是的这里存在一些问题:
- 太大的文件最好不要通过Http协议上传(一般是2M),会崩的.怎么办呢?
当然你可以改成ChunkingMode,BsinceEvent也支持这种方式,重写DataSet下面这个方法,并重写setpropertybeforeConnect,设置块大小.
@Override
public boolean isChunkedStreamingMode() {
return true;
}
@Override
public void setPropertyBeforeConnect(HttpURLConnection conn) {
conn.setChunkedStreamingMode(5);
}
当然我们更乐意你用另一种方式,我们额外提供了一个SocketClient;
SocketClient.doUpload("http://192.168.1.109:8080/HttpService/upload",map, new MulitDataSet.FileWrapper[]{new MulitDataSet.FileWrapper(f,null,"xiong.jpg")},new LoadingListener() {
@Override
public void onLoadingStarted() {
Log.e("load","onLoadingStarted");
}
@Override
public void onLoadProgressChanged(int i, int i2) {
Log.e("load","onLoadProgressChanged"+i+"/"+i2);
}
@Override
public void onLoadingError(Exception e) {
Log.e("load","onLoadingError");
dialog.dismiss();
}
@Override
public void onLoadingEnd(boolean b, Object... objects) {
Log.e("load","onLoadingEnd");
dialog.dismiss();
}
});
- 如何监听上传进度?
是的,相信你也发现了,用Socket上传还能监听到上传进度。是的,因为这里我们只实现了socket文件的上传,而文件的总长度是可知的,所以监听到其上传进度并不意外。实现上,如果你使用Mulitdataset,也只向里面添加了文件,而没有流的话,也是可以实现监听的。
MulitDataSet ds = new MulitDataSet();
ds.put("title", "xxx文件");
ds.put("timelength", "15");
try {
ds.put("videofile", new File(Environment.getExternalStorageDirectory(), "xiong.jpg"));
} catch (FileNotFoundException e) {
e.printStackTrace();
editext.setText(e.toString());
return;
}
ds.setProgressChangeListener(new ProgressChangeListener() {
@Override
public void onLoadProgressChanged(int currentSize, int totalSize) {
Log.d("Sample",currentSize+"/"+totalSize);
}
});
EventPublisher.connect(String.class, "/HttpService/upload")
.method(Method.POST)
.data(ds)
.tag("upload")
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
dialog.dismiss();
}
@Override
public void onErrorResponse(Exception e) {
dialog.dismiss();
editext.setText(e.toString());
}
});
好了,文件上传部份暂时就到这里 #####4.WebService请求 有时其实会遇到这样的情况,需要向一些公众支持接口调取服务,比如天气,归属地等,它们一般都是以webservice服务,这时你大可不必担忧,因为这里提供了一种Dataset的实现
- doNet平台
SoapDataSet ds = new SoapDataSet(SoapDataSet.SOAP_VER_12);
ds.setMethodName("getSupportCity");
ds.setNameSpace("http://WebXml.com.cn/");
ds.setSoapAction("http://WebXml.com.cn/getSupportCity");
ds.put("byProvinceName", "北京");
ds.dotNet = true;
EventPublisher.connect(String.class, "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx")
.data(ds)
.method(Method.POST)
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
dialog.dismiss();
}
@Override
public void onErrorResponse(Exception e) {
dialog.dismiss();
editext.setText(e.toString());
}
});
- 非doNet平台
SoapDataSet ds2 = new SoapDataSet(SoapDataSet.SOAP_VER_11);
ds2.setMethodName("getTempVerifiCode");
ds2.setNameSpace("http://jdk.study.hermit.org/client");
ds2.setSoapAction("");
ds2.put("userCode", "42a3c56c9e45c968");
ds2.put("password", "");
ds2.put("userType", "02");
ds2.dotNet = false;
EventPublisher.connect(String.class, "http://wwww...........")
.data(ds2)
.method(Method.POST)
.submit(new ResponseListener<String>() {
@Override
public void onSuccessResponse(String s) {
editext.setText(s);
dialog.dismiss();
}
@Override
public void onErrorResponse(Exception e) {
dialog.dismiss();
editext.setText(e.toString());
}
});
#####5.Cookie 在配置Globalconfiguration时,useCookie设为true,将会自动处理Cookie; #####6.同步与异步 BsinceEvent在submit时,设置了对应回调ResponseListener时,为异步调用,不传入参数时,是为同步调用。
String s =EventPublisher.connect(String.class, "/HttpService/habit")
.data(ds)
.method(Method.POST)
.tag("habit")
.submit();
同时BsinceEvent还支持异步任务的调用
public static void submit(Event<?> task) {
}
EventPublisher.task().submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "hello";
}
}, new ResponseListener<String>() {
@Override
public void onSuccessResponse(String response) {
}
@Override
public void onErrorResponse(Exception error) {
}
});
#####7.图片的加载
EventPublisher.connect(Bitmap.class,"http://img0.bdstatic.com/img/image/f3165146edddf5807b7cb40a426ffaaf1426747348.jpg").bitmapExtras(0,0, Bitmap.Config.RGB_565)
.cacheMode(CacheModel.CACHE_NEVER)
.parser(BitmapParserImp.INSTANCE)
.submit(new ResponseListener<Bitmap>() {
@Override
public void onSuccessResponse(Bitmap response) {
image.setImageBitmap(response);
}
@Override
public void onErrorResponse(Exception error) {
Toast.makeText(ListActivity.this,error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
在列表中显示图片,使用NetworkImageview
NetworkImageView view = (NetworkImageView) convertView.findViewById(R.id.head);
TextView tex= (TextView) convertView.findViewById(R.id.url);
tex.setText(getItem(position));
view.setDefaultImageResId(R.mipmap.ic_launcher);
view.setImageUrl(getItem(position), imageLoader);
#####8.文件下载
FileDownloadParser parser = new FileDownloadParser(Environment.getExternalStorageDirectory().getAbsolutePath(),"inst.exe");
EventPublisher.connect(File.class, "http://down.360safe.com/360/inst.exe")
.parser(parser)
.cacheMode(CacheModel.CACHE_NEVER)//禁用缓存
.submit(new ResponseListener<File>() {
@Override
public void onSuccessResponse(File response) {
Toast.makeText(DownFileActivity.this,"下载成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onErrorResponse(Exception error) {
Toast.makeText(DownFileActivity.this,"下载失败",Toast.LENGTH_SHORT).show();
}
});
下载文件时,设置缓存模式为CacheModel.CACHE_NEVER
如果要监听下载进度,在parser中进行设置
parser.setLoadingListener(new LoadingListener() {
@Override
public void onLoadingStarted() {
Log.i("down","onLoadingStarted");
}
@Override
public void onLoadProgressChanged(int currentSize, int totalSize) {
Log.i("down","onLoadProgressChanged:"+currentSize+"/"+totalSize);
}
@Override
public void onLoadingError(Exception e) {
Log.i("down","onLoadingError:"+e.toString());
}
@Override
public void onLoadingEnd(boolean complete, Object... args) {
Log.i("down","onLoadingEnd");
}
});
#####9.Extras
- 清除http磁盘缓存
EventPublisher.clearHttpCache(new Runnable() {
@Override
public void run() {
Toast.makeText(ListActivity.this,"缓存清除成功",Toast.LENGTH_SHORT).show();
}
});
- 取消请求
EventPublisher.cancel("tag");//通过标记请求
EventPublisher.cancelAll();//取消全部
EventPublisher.cancel(3);//通过序号取消
EventPublisher.cancel(new EventFilter() {//自定义筛选条件取消
@Override
public boolean apply(Event<?> task) {
return false;
}
});
目前项目中的注释大量‘清白’,主要是想全部改成英文注释,删完原先注释之后,才发现工作量不小,只能以后尽快补上了,若造成了你的不便,请谅解
如果你在使用过程中发现Bug或遇到什么问题,请与我联系 oeager@foxmail.com