关于多次重复网络请求问题
Posted 梁飞宇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于多次重复网络请求问题相关的知识,希望对你有一定的参考价值。
问题分析
一个页面,可以通过点击不同的模块获取相应的数据。但是,当用户频繁点击的时候,有的模块网络请求数据返回会比较慢,这个时候返回的数据就会覆盖当前模块的数据。
解决方法
加锁处理
切换模块时,会对同一个API进行多次请求,但因为调用的接口都是一样的,所以最好就是加上锁,防止重复请求造成网络资源浪费。
@synchronized (self) //加锁,避免数组重复创建添加等问题 static NSMutableArray * successBlocks;//用数组保存回调 static NSMutableArray * failureBlocks; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^//仅创建一次数组 successBlocks = [NSMutableArray new]; failureBlocks = [NSMutableArray new]; ); if (success) //每调用一次此函数,就把回调加进数组中 [successBlocks addObject:success]; if (failure) [failureBlocks addObject:failure]; static BOOL isProcessing = NO; if (isProcessing == YES) //如果已经在请求了,就不再发出新的请求 return; isProcessing = YES; [self callerPostTransactionId:transactionId parameters:dic showActivityIndicator:showActivityIndicator showErrorAlterView:showErrorAlterView success:^(id responseObject) @synchronized (self) //网络请求的回调也要加锁,这里是另一个线程了 for (successBlock eachSuccess in successBlocks) //遍历回调数组,把结果发给每个调用者 eachSuccess(responseObject); [successBlocks removeAllObjects]; [failureBlocks removeAllObjects]; isProcessing = NO; failure:^(id data) @synchronized (self) for (failureBlock eachFailure in failureBlocks) eachFailure(data); [successBlocks removeAllObjects]; [failureBlocks removeAllObjects]; isProcessing = NO; ];
取消请求
取消全部请求:
[manager.operationQueue cancelAllOperations];
取消单个请求,以post请求为例:
AFHTTPRequestOperation *post =[manager POST:nil parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) //doing something failure:^(AFHTTPRequestOperation *operation, NSError *error) // error handling. ]; //Cancel operation [post cancel];
AFNetworking取消正在进行的网络请求:
//单例模式 + (HttpManager *)sharedManager static dispatch_once_t once; dispatch_once(&once, ^ httpManager = [[HttpManager alloc] init]; ); return httpManager; //网络类初始化 - (id)init self = [super init]; if(self) manager = [AFHTTPSessionManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; return self;
[[HttpManager sharedManager] dataFromWithBaseURL:BaseURL path:url method:@"POST" timeInterval:10 params:parmas success:^(NSURLRequest *request, NSURLResponse *response, id JSON) failure:^(NSURLRequest *request, NSURLResponse *response, NSError *error, id JSON) error:^(id JSON) finish:^(id JSON) ];
取消正在进行的网络请求
- (void)cancelRequest if ([manager.tasks count] > 0) NSLog(@"返回时取消网络请求"); [manager.tasks makeObjectsPerformSelector:@selector(cancel)]; //NSLog(@"tasks = %@",manager.tasks);
同一个请求多次请求时,短时间忽略相同的请求
当进行刷新操作时,如果在请求还没有返回之前,一直在刷新操作,不管是狂点还是乱点。那么第一个请求发出后,短时间内可以不进行重复请求。
同一个请求多次请求时,取消之前发出的请求
如果是在搜索操作,那么每次输入关键字的时候,之前发出的请求可以取消,仅仅显示最后的请求结果。 采用的方法为创建一个BaseViewModel,所有的请求操作继承BaseViewModel,在发起请求之前进行一次判断。
#pragma mark - 忽略请求 /** 忽略请求,当请求的url和参数都是一样的时候,在短时间内不发起再次请求, 默认3秒 */ - (BOOL)ignoreRequestWithUrl:(NSString *)url params:(NSDictionary *)params; /** 忽略请求,当请求的url和参数都是一样的时候,在短时间内不发起再次请求 */ - (BOOL)ignoreRequestWithUrl:(NSString *)url params:(NSDictionary *)params timeInterval:(NSTimeInterval)timeInterval; #pragma mark - 取消之前的请求 /** 取消之前的同一个url的网络请求 * 在failure分支中,判断如果是取消操作,那么不做任何处理 * 在success和failure分支中,都要调用clearTaskSessionWithUrl:方法,进行内存释放 */ - (void)cancelLastTaskSessionWithUrl:(NSString *)url currentTaskSession:(NSURLSessionTask *)task; /** 清除url绑定的sessionTask */ - (void)clearTaskSessionWithUrl:(NSString *)url;
@property (nonatomic, strong) NSMutableDictionary *requestTimeMDic; @property (nonatomic, strong) NSMutableDictionary *cancelTaskMDic; - (BOOL)ignoreRequestWithUrl:(NSString *)url params:(NSDictionary *)params return [self ignoreRequestWithUrl:url params:params timeInterval:kRequestTimeInterval]; - (BOOL)ignoreRequestWithUrl:(NSString *)url params:(NSDictionary *)params timeInterval:(NSTimeInterval)timeInterval NSString *requestStr = [NSString stringWithFormat:@"%@%@", url, [params uq_URLQueryString]]; NSString *requestMD5 = [NSString md5:requestStr]; NSTimeInterval nowTime = [[NSDate date] timeIntervalSince1970]; NSNumber *lastTimeNum = [self.requestTimeMDic objectForKey:requestMD5]; WS(weakSelf); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^ // 超过忽略时间后,将值清空 [weakSelf.requestTimeMDic removeObjectForKey:requestMD5]; ); if (timeInterval < (nowTime - [lastTimeNum doubleValue])) if (0.01 > [lastTimeNum doubleValue]) [self.requestTimeMDic setObject:@(nowTime) forKey:requestMD5]; return NO; else return YES; - (void)cancelLastTaskSessionWithUrl:(NSString *)url currentTaskSession:(NSURLSessionTask *)task NSURLSessionTask *lastSessionTask = [self.cancelTaskMDic objectForKey:url]; if (nil == lastSessionTask) [self.cancelTaskMDic setObject:task forKey:url]; return; [lastSessionTask cancel]; - (void)clearTaskSessionWithUrl:(NSString *)url [self.cancelTaskMDic removeObjectForKey:url];
#pragma mark - Getter Methods - (NSMutableDictionary *)requestTimeMDic if (nil == _requestTimeMDic) _requestTimeMDic = [[NSMutableDictionary alloc] initWithCapacity:5]; return _requestTimeMDic; - (NSMutableDictionary *)cancelTaskMDic if (nil == _cancelTaskMDic) _cancelTaskMDic = [[NSMutableDictionary alloc] initWithCapacity:5]; return _cancelTaskMDic;
PGNetworkHelper
PGNetworkHelper - PINCache作为AFNetworking缓存层,将AFNetworking请求的数据缓存起来,支持取消当前网络请求,以及取消所有的网络请求,除了常用的Get,Post方法,也将上传图片以及下载文件进行了封装,同样支持同步请求,使用方法极其简单。
Android防止按钮快速重复点击
问题发现
做android开发时很可能会遇到这样的场景:
一个Button响应点击后发起网络请求。由于当前网络情况较差等原因请求结果没有及时返回,这个按钮又被用户重复点击,或者用户故意快速点击,造成请求多次发起。
快速重复点击引起的网络请求多次发起,往往都不是我们希望看到的,会产生交互上的逻辑混乱,如果是涉及到提交订单这样的请求,还可能会对用户造成损失,所以这样的情况需要避免。
防止快速重复点击的方案很多。可以在服务端做校验,可以在客户端交互上做限制,也可以在客户端响应点击事件时做校验。其中,在客户端响应点击事件时做校验的方法,可以很方便在网上搜索到:
一、全局
public class Utils {
// 两次点击按钮之间的点击间隔不能少于1000毫秒
private static final int MIN_CLICK_DELAY_TIME = 1000;
private static long lastClickTime;
public static boolean isFastClick() {
boolean flag = false;
long curClickTime = System.currentTimeMillis();
if ((curClickTime - lastClickTime) >= MIN_CLICK_DELAY_TIME) {
flag = true;
}
lastClickTime = curClickTime;
return flag;
}
}
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Utils.isFastClick()) {
// 进行点击事件后的逻辑操作
}
}
参考
1、https://zhuanlan.zhihu.com/p/34841081
2、https://www.cnblogs.com/dingxiansen/p/10442255.html
以上是关于关于多次重复网络请求问题的主要内容,如果未能解决你的问题,请参考以下文章