一步一步搭建自己的iOS网络请求库(一)

大家好,我是LastDay,很久没有写博客了,这周会分享一个的HTTP请求库的编写经验。

简单的介绍

介绍一下,NSURLSession是iOS7中新的网络接口,它与NSURLConnection是并列的。在程序在前台时,NSURLSession与NSURLConnection可以互为替代工作。两者在前台的时候其实没有什么区别,最主要的是程序在进入后台的时候,Background Session会更加灵活

测试NSURLSession

首先我们来新建一个工程,起名为LyHttp,在页面上放置一个按钮 ,起名为”测试”。

将按钮关联到我们的ViewController.m,起名为test。

添加以下代码

- (IBAction)test:(id)sender {
NSURL *url = [NSURL URLWithString:@"http://cityuit.sinaapp.com/1.php"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume];
}

http://cityuit.sinaapp.com/1.php是我自己写的一个接口用来测试的,会返回succeed。

我们来看一下触发效果:

测试完成

接下来我们来看看我们的NSURLSession是否为异步?OK,我们来简单的修改一下我们的程序吧。讲两个阻塞,来看看我们的主线程变化。

- (IBAction)test:(id)sender {
NSURL *url = [NSURL URLWithString:@"http://cityuit.sinaapp.com/1.php"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){
//阻塞3秒
[NSThread sleepForTimeInterval:3];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume];
}

可以看见效果就是连续点击3次,每隔三秒进行一次输出,直到三次执行完事,这就说明我们的主线程没有被阻塞,验证说明NSURLSession为异步。

曾将看过一篇文章中,介绍过,那篇文章里介绍NSURLSession 采用的是 “异步阻塞” 模型,即所有请求在发出后都进入 2# 线程执行,在 2# 线程内部按照阻塞队列模式执行。初步判断,此阻塞特性为 [NSURLSession sharedSession] 单例模式的结果。

一步一步搭建自己的iOS网络请求库(二)

大家好,我是LastDay,上一次分享了简单体验并且测试下一下NSURLSession。

我的博客地址:http://lastday.github.io

进行简单的封装

我们接下来将要加入动态的动态的HTTP参数(parameters)的功能,之后封装出我们自己的接口。

首先呢,我们先来对上一次的代码进行一次简单的封装,建立一个新的类LyNetWork,继承于NSObject类 。新建一个静态的request方法。将请求方式和URL传入

代码如下:

+(void)request :(NSString *)method URL:(NSString *)URL{
NSURL *url = [NSURL URLWithString:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *reponse,NSError *error){ //NSdata转String
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}];
[task resume]; }

OK

让我们在ViewController中进行一下测试,代码如下:


@IBAction func mainButtonBeTapped(sender: AnyObject) {
[LyNetWork request:@"GET" URL:@"http://cityuit.sinaapp.com/1.php"];
}

接下来运行一下:OK 依然显示我们正确的测试结果:succeed

使用Block处理请求返回值

简单的介绍下闭包(block),对于OC来说是一个新词,但不是新的概念,不是新的东西。学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也支持闭包, 也就是OC中所提到的Block。

现在对我们的request函数进行修改,LyNetWork.m代码如下:

+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSURL *url = [NSURL URLWithString:URL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
} }]; [task resume];
}

接下来修改ViewController中的函数调用,代码修改后如下:


- (IBAction)test:(id)sender {
[LyNetWork requestMethod:@"GET"
URL:@"http://cityuit.sinaapp.com/1.php"
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}

测试结果依然返回succeed,测试结果正确

接下来进行我们最难处理的地方,增加parameters处理能力

我们先来处理GET方法吧

GET 方法下,params 在经过 url encode 之后直接附在 URL 末尾发送给服务器

类似于这个样子 GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

修改我们的requestMethod方法,将其进行一下更改,引入parameters参数

+(void)requestMethod:(nullable NSString *)method
URL:(nullable NSString *)URL
parameters:(nullable id) parameters
success:(nullable void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(nullable void (^)(NSError *__nullable error))failure;

接下来就该处理我们的parameters参数了

我们从AFNetworking中借鉴一下他的处理方案(其实这里本人就是模仿编写罢了)

我们新建一个类起名为LYURLRequestSerialization,在LYURLRequestSerialization.h添加一下方法

+(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters;

进入我们的LYURLRequestSerialization.m文件中,添加以下代码:


#import "LYURLRequestSerialization.h" @interface LYURLRequestSerialization() @property (readwrite, nonatomic, strong) id value;
@property (readwrite, nonatomic, strong) id field; @end @implementation LYURLRequestSerialization - (id)initWithField:(id)field value:(id)value {
self = [super init];
if (!self) {
return nil;
} self.field = field;
self.value = value; return self;
} #pragma mark - FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary);
FOUNDATION_EXPORT NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value); +(NSString *)LYQueryStringFromParameters:(NSDictionary *)parameters {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (LYURLRequestSerialization *pair in LYQueryStringPairsFromDictionary(parameters)) { [mutablePairs addObject:[pair URLEncodedStringValue]];
} return [mutablePairs componentsJoinedByString:@"&"];
} NSArray * LYQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return LYQueryStringPairsFromKeyAndValue(nil, dictionary);
} NSArray * LYQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:LYQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[LYURLRequestSerialization alloc] initWithField:key value:value]];
} return mutableQueryStringComponents;
} static NSString * LYPercentEscapedStringFromString(NSString *string) {
static NSString * const kLYCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kLYCharactersSubDelimitersToEncode = @"!$&'()*+,;="; NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kLYCharactersGeneralDelimitersToEncode stringByAppendingString:kLYCharactersSubDelimitersToEncode]]; static NSUInteger const batchSize = 50; NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy; while (index < string.length) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu"
NSUInteger length = MIN(string.length - index, batchSize);
#pragma GCC diagnostic pop
NSRange range = NSMakeRange(index, length); range = [string rangeOfComposedCharacterSequencesForRange:range]; NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
[escaped appendString:encoded]; index += range.length;
} return escaped;
} - (NSString *)URLEncodedStringValue {
if (!self.value || [self.value isEqual:[NSNull null]]) {
return LYPercentEscapedStringFromString([self.field description]);
} else {
return [NSString stringWithFormat:@"%@=%@", LYPercentEscapedStringFromString([self.field description]), LYPercentEscapedStringFromString([self.value description])];
}
} @end

简单的说一下吧,以上的方法都是为了处理传入的NSDictonary参数,因为我们在使用的时候为了方便我们传入动态的parameters,所以他的的格式是这样的:

id parmenters = @{
@"value":@"LastDays",
};

将它处理后我们希望得到的样式应该是这样,对吧?

http:URL.php?value=LastDays

这个参数是一个动态的,我们不能确定里面到底有几组参数,而且还需要考虑的一个问题就是NSDictonary中嵌套NSDictonary的情况,我们处理这种问题的一个思想就是递归。从最里面开始处理。

OK,这样我们就实现了parameters处理能力

然后我们需要测试一下

为了进行测试我又重新更改了接口,提供了参数处理的能力,以下是新的接口:

http://cityuit.sinaapp.com/1.php  value=将要返回的值

更改下requestMethod方法


+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSString *newURL;
if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]]; NSLog(@"%@",newURL);
} NSURL *url = [NSURL URLWithString:newURL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method;
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
}
}];
[task resume];
}

其中变化的地方:

if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];
NSLog(@"%@",newURL);
}

以上代码的意思就是判断一下是否未GET请求,如果是的话将处理后的parameters加到尾部,以刚才的参数为例子,处理后的newURL为:http://cityuit.sinaapp.com/1.php?value=LastDays

也就是说返回值为LastDays

到ViewController.m中进行测试,测试代码如下:

- (IBAction)test:(id)sender {

    id parmenters = @{
@"value":@"LastDays",
};
[LyNetWork requestMethod:@"GET"
URL:@"http://cityuit.sinaapp.com/1.php"
parameters:parmenters
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}

ok返回结果为LastDays,成功添加入动态的动态的HTTP参数(parameters)的功能。

一步一步搭建自己的iOS网络请求库(三)

大家好,我是LastDay,上一次分享了简单的封装,和GET请求。这次带给大家POST方法

我的博客地址:http://lastday.github.io

POST方法

POST 下很很多协议可提供我们选择,因为我们没有写文件的上传,所以我们就采用 application/x-www-form-urlencoded 这种简单的方式发送请求吧。requestMethod 中进行一些修改,增加POST方法。

代码如下:

+(void)requestMethod:(NSString *)method
URL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
NSString *newURL;
if ([method isEqual:@"GET"]) {
newURL = [[URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:parameters]];
NSLog(@"%@",newURL);
}else{
newURL = URL;
} NSURL *url = [NSURL URLWithString:newURL];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = method; if([method isEqual:@"POST"]){
[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
request.HTTPBody =[[LYURLRequestSerialization LYQueryStringFromParameters:parameters] dataUsingEncoding:NSUTF8StringEncoding];
}
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data,NSURLResponse *response,NSError *error){
if (error) {
failure(error);
}else{
if (success) {
success(data,response);
}
}
}];
[task resume];
}

接下来我们进行测试,原来的那个接口不支持POST请求,为了测试我就新写了一个借口,有两个参数为username和password,只有当两个参数都为1的时候返回ok,其余返回no

我们给出POST请求测试代码:

- (IBAction)test:(id)sender {

    NSString *URL = @"http://cityuit.sinaapp.com/p.php";
id parmenters = @{
@"username":@"1",
@"password":@"1"
}; [LyNetWork requestMethod:@"POST"
URL:URL
parameters:parmenters
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
}
failure:^(NSError *error){
NSLog(@"%@",error);
}];
}

查看结果为:

若parmenters为1,222

id parmenters = @{
@"username":@"1",
@"password":@"222"
};

结果为:

一步一步搭建自己的iOS网络请求库(四)--解耦处理

LastDays HTTP Library
04 Dec 2015 in Lyhttplibrary  2.335 minutes read

对LyHttp进行降耦处理

大家好,我是LastDays,这次分享解耦处理,提高代码的可扩展性,和重用性。

我的博客地址:http://lastday.github.io

LyHttp项目地址

原来的那些代码虽然,看起来比较容易理解,但是最大的问题还是功能太单一,代码太杂乱了。接下来我们将是用适配器模型来实现独立于底层结构的网络API,构造我们自己真正的”库”

分析NSURLSESSION

1.构造 NSURLRequest

1.确定 URL

2.确定 HTTP 方法(GET、POST 等)

3.添加特定的 HTTP 头

4.填充 HTTP Body

2.驱动 [session dataTaskWithRequest] 方法,开始请求

开始搞

新建一个LYHTTPRequestOperationManager类,然后初始化一些参数


#import "LYHTTPRequestOperationManager.h"
#import "LYURLRequestSerialization.h" @interface LYHTTPRequestOperationManager() @property(nonatomic,strong) NSString *URL;
@property(nonatomic,strong) NSString *method;
@property(nonatomic,strong) NSDictionary *parameters;
@property(nonatomic,strong) NSMutableURLRequest *request;
@property(nonatomic,strong) NSURLSession *session;
@property(nonatomic,strong) NSURLSessionDataTask *task; @end @implementation LYHTTPRequestOperationManager - (instancetype)initWithMethod:(NSString *)method URL:(NSString *)URL parameters:(id)parameters
{
self = [super init];
if (!self) {
return nil;
}
self.URL = URL;
self.method = method;
self.parameters = parameters;
self.request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]];
self.session = [NSURLSession sharedSession];
return self;
} @end

看看我们刚才分析东西:

1.构造 NSURLRequest

1.确定 URL

2.确定 HTTP 方法(GET、POST 等)

3.添加特定的 HTTP 头

4.填充 HTTP Body

根据上面的分析,我们建立一个setRequest函数:

-(void)setRequest{
if ([self.method isEqual:@"GET"]&&self.parameters.count>0) { self.request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[[self.URL stringByAppendingString:@"?"] stringByAppendingString: [LYURLRequestSerialization LYQueryStringFromParameters:self.parameters]]]];
}
self.request.HTTPMethod = self.method; if (self.parameters.count>0) {
[self.request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
}

setRequest完成了我们已经分析的前三个步骤

接下来创建setBody函数:

-(void)setBody{
if (self.parameters.count>0&&![self.method isEqual:@"GET"]) { self.request.HTTPBody = [[LYURLRequestSerialization LYQueryStringFromParameters:self.parameters] dataUsingEncoding:NSUTF8StringEncoding];
}
}

setBody就是完成了我们最后一个步骤

以上处理完成了构造 NSURLREQUEST

我们该进行驱动 [SESSION DATATASKWITHREQUEST] 方法,开始请求

-(void)driveTask:(void(^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{
[self setRequest];
[self setBody];
[self setTaskWithSuccess:success failure:failure];
}

采用适配器模式封装LyHttp

简单的来介绍一下适配器的概念:

适配器模式,可以这么说,用于连接两种不同种类的对象,使其毫无问题地协同工作。思想其实非常的简单。适配器实现客户端需要的某种接口的行为。同时它又连接到另一个具有不同行为的对象。一边是客户端懂得如何使用的目标接口,另一边还客户端一无所知的适配者,适配器站在两者中间。适配器主要的作用是把适配者的行为传递给管道另一端的客户端,其实这种所谓的很高大赏的适配器模型很多人其实已经使用过了

接下来就是来修改我们的LyNetWork

封装多级API

不带parameters:

+(void)requestWithMethod:(NSString *)method
URL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{ LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:method URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}

不带parameters的GET方法:

+(void)requestGetWithURL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{ LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"GET" URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}

带parameters的GET方法:

//GET带parameters
+(void)requestGetWithURL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{ LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"GET" URL:URL parameters:parameters];
[manange driveTask:success failure:failure];
}

POST不带parameters

+(void)requestPostWithURL:(NSString *)URL
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{ LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"POST" URL:URL parameters:nil];
[manange driveTask:success failure:failure];
}

POST带parameters

+(void)requestPostWithURL:(NSString *)URL
parameters:(id) parameters
success:(void (^)(NSData *__nullable data,NSURLResponse * __nullable response))success
failure:(void (^)(NSError *__nullable error))failure
{ LYHTTPRequestOperationManager *manange = [[LYHTTPRequestOperationManager alloc] initWithMethod:@"POST" URL:URL parameters:parameters];
[manange driveTask:success failure:failure];
}

接下来就是进入我们的修改ViewController代码进行测试:

- (IBAction)test:(id)sender {
NSString *postURL = @"http://cityuit.sinaapp.com/p.php";
NSString *getURL= @"http://cityuit.sinaapp.com/1.php"; id parmentersPost = @{
@"username":@"1",
@"password":@"1"
};
id parmentersGet = @{
@"value":@"Lastday",
}; [LyNetWork requestWithMethod:@"POST"
URL:@"http://cityuit.sinaapp.com/1.php?value=Lastday"
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestWithMethod = %@",string);
}
failure:^(NSError *error){
NSLog(@"====%@",error);
}]; [LyNetWork requestPostWithURL:postURL
parameters:parmentersPost
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestPostWithURL(带参数) = %@",string);
}
failure:^(NSError *error){ }];
[LyNetWork requestPostWithURL:postURL
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestPostWithURL(不带参数) = %@",string);
}
failure:^(NSError *error){ }]; [LyNetWork requestGetWithURL:getURL
parameters:parmentersGet
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestGetWithURL(带参数) = %@",string);
}
failure:^(NSError *error){ }]; [LyNetWork requestGetWithURL:getURL
success:^(NSData *data,NSURLResponse *response){
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"requestGetWithURL(不带参数) = %@",string);
}
failure:^(NSError *error){ }]; }

看一下执行结果

【转载】一步一步搭建自己的iOS网络请求库的更多相关文章

  1. 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)

    首先,展示一下封装好之后的项目的层级结构. 1.先创建一个RetrofitApiService.java package com.xdw.retrofitrxmvpdemo.http; import ...

  2. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  3. 一步一步使用ABP框架搭建正式项目系列教程之本地化详解

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 本篇目录 扯扯本地化 ABP中的本地化 小结 扯扯本地化 本节来说说本地化,也有叫国际化.全球化的,不管怎么个叫法,反正道理都是一 ...

  4. 一步一步了解Cocos2dx 3.0 正式版本开发环境搭建(Win32/Android)

    cocos2d-x 3.0发布有一段时间了,作为一个初学者,我一直觉得cocos2d-x很坑.每个比较大的版本变动,都会有不一样的项目创建方式,每次的跨度都挺大…… 但是凭心而论,3.0RC版本开始 ...

  5. 一步一步教你编写与搭建自动化测试框架——python篇

    [本文出自天外归云的博客园] 这两天用python写了一个自动化测试框架,取名为Auty.准备用来做Web方面的接口测试,以下为Auty框架一步一步的搭建过程——

  6. 一步一步搭建Jenkins环境

    Jenkins使用经验谈1(一步一步搭建Jenkins环境)在公司使用 Jenkins 软件已经有一段时间了,走了很多弯路,但也积累了一些经验,可以和大家分享一下.我们来一起搭建Jenkins环境.首 ...

  7. 一步一步搭建客服系统 (2) 如何搭建SimpleWebRTC信令服务器

    上次介绍了<3分钟实现网页版多人文本.视频聊天室 (含完整源码)>使用的是default 信令服务器,只是为了方便快速开始而已.SimapleWebRTC官方文档里第一条就讲到,不要在生产 ...

  8. [ALM]一步一步搭建MS ALM环境 - 安装TFS + SQL SERVER

    描述: 安装SQL SERVER 2012,安装TFS 2013,配置TFS,挽起袖子,准备干活儿 步骤: 1,打开Hyper-V Manager,参考[Hyper-V]使用操作系统模板创建新的虚拟机 ...

  9. 一步一步搭建 oracle 11gR2 rac + dg 之前传 (一)【转】

    一步一步在RHEL6.5+VMware Workstation 10上搭建 oracle 11gR2 rac + dg  之前传 (一) 转自 一步一步搭建 oracle 11gR2 rac + dg ...

随机推荐

  1. HTML5区域范围文本框实例页面

    CSS代码: input { font-size: 14px; font-weight: bold; } input[type=range]:before { content: attr(min); ...

  2. 利用row_number over 函数删除重复记录

    开窗函数                Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行 SQ ...

  3. hdu 4465 Candy(二次项概率)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4465 参考博客:http://www.cnblogs.com/goagain/archive/2012 ...

  4. openstack 启用spice

    Openstack启用spice协议 #控制节点 #安装 ? 1 apt-get install nova-spiceproxy spice-html5 spice-vdagent #配置 nano ...

  5. nginx做负载均衡器以及proxy缓存配置 - SegmentFault

    nginx做负载均衡器以及proxy缓存配置 - SegmentFault nginx做负载均衡器以及proxy缓存配置

  6. sql Server 发送邮件 错误类型及原因

    设置警报         在[常规项]中做以下设置 新建警报 设置警报名称 选择数据库 选择严重性     在[响应项]中可以做以下设置 选择要邮件通知的操作员 可以设置执行一个警报作业    在选项 ...

  7. ecshop获取浏览器各个版本

    <?php /** * 获得浏览器名称和版本 * * @access public * @return string */ function get_user_browser() { if (e ...

  8. HTML5简易在线画图工具

    继上次学习了HTML5的路径画圆做了动态时钟.异次元空间的反转做了运动的太阳系,这两天将画线.画圆.填充等知识点结合起来做了一个简易的在线画图工具: 查看DEMO:HTML5简易在线画图工具 功能包括 ...

  9. Linux系统的Cache工作原理和管理机制

    Linux系统Cache 管理是 Linux 内核中一个很重要并且较难理解的组成部分.本文详细介绍了 Linux 内核中文件 Cache 管理的各个方面,希望能够帮助到你. 操作系统和文件 Cache ...

  10. poj2406--Power Strings(KMP求最小循环节)

    Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 33178   Accepted: 13792 D ...