android并发网络请求的处理
2016-03-01 10:37
567 查看
最近在做android客户端的统计sdk,为了保证数据统计的准确行,需要把一些基本信息,和无网络情况下用户的操作保存到SqlLite本地数据库中,等待有网了的时候进行传;
基本解决思路,离线操作的数据请求URL和请求参数进行封装,封装到对象中,转化为json存储到SQlLite数据库中;定时任务检测网络情况,如果有网,则把数据库中数据取出,进行网络上传;
取出数据库中请求,就需要处理大量网络请求,同时发送请求的情况,一般来说一个网络请求都会用使用到一个异步线程,大量的线程创建、运行、销毁又造成了系统资源的浪费,而且同时同时new出多个子线程也会造成客户端卡死现象;于是考虑到能不能做个请求队列去进行控制
在这个模型中,有高中低三个优先级信道如下:高优先级--1,中优先级--3,低优先级--2
规则:
1.正常情况下各个优先级使用各自信道(线程)
2.高级信道满载、中、低级信道空置,则高级请求可使用低级信道
构思:
UI线程将期望的网络请求url和参数通过一个封装好的Runnable提交给Service处理(当然也可以交给一个Thread处理,本例使用Service),Service接收到请求,判断优先级,加入到相应线程池中排队。线程池启动线程发起网络请求,最后通过监听器将结果返回给Service,Service发送广播通知UI线程,UI线程更新相关界面,结束。
废话说完,上例子:
首先是封装好的Runnable
public class HttpConnRunnable implements Runnable, Parcelable {
public static final int HIGH_LEVEL = 0;
public static final int NORMAL_LEVEL = 1;
public static final int LOW_LEVEL = 2;
private int mPriority = NORMAL_LEVEL;//优先级,默认为普通
private String mUrl = "";
private HttpConnListener mListener;//监听器
public HttpConnRunnable() {
super();
}
public HttpConnRunnable(int priority) {
super();
mPriority = priority;
}
@Override
public void run() {
Log.i(Thread.currentThread().getName(), "----Start to connect:" + mUrl + ", priority:" + mPriority + "-----");
try {
Thread.sleep(10000);
//TODO:进行网络请求相关操作,并通过listener返回结果
mListener.onSucceed("Connected to " + mUrl + " succeed!");
}
catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(Thread.currentThread().getName(), "----Finish to connect:" + mUrl + ", priority:" + mPriority + "-----");
}
public int getPriority() {
return mPriority;
}
public void setPriority(int priority) {
mPriority = priority;
}
public String getURL() {
return mUrl;
}
public void setURL(String url) {
mUrl = url;
}
public void setHttpConnListener(HttpConnListener listener) {
mListener = listener;
}
//序列化,为了传递给Service,如果是使用Thread处理本例,则无需序列化
public static final Parcelable.Creator CREATOR = new Creator() {
@Override
public HttpConnRunnable createFromParcel(Parcel source) {
HttpConnRunnable data = null;
Bundle bundle = source.readBundle();
if(bundle != null) {
data = new HttpConnRunnable(bundle.getInt("PRIORITY"));
data.mUrl = bundle.getString("URL");
}
return data;
}
@Override
public HttpConnRunnable[] newArray(int size) {
return new HttpConnRunnable[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Bundle bundle = new Bundle();
bundle.putInt("PRIORITY", mPriority);
bundle.putString("URL", mUrl);
dest.writeBundle(bundle);
}
}
public class HttpConnService extends Service implements HttpConnListener {
public static final String HTTP_POOL_PARAM_KEYWORD = "HttpPoolParam"; //网络参数传递的关键字
private final int HIGH_POOL_SIZE = 1;
private final int NORMAL_POOL_SIZE = 3;
private final int LOW_POOL_SIZE = 2;
// 可重用固定线程数的线程池
private ThreadPoolExecutor mHighPool;
private ThreadPoolExecutor mNormalPool;
private ThreadPoolExecutor mLowPool;
@Override
public void onCreate() {
//初始化所有
mHighPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(HIGH_POOL_SIZE);
mNormalPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(NORMAL_POOL_SIZE);
mLowPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOW_POOL_SIZE);
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//接受到来自UI线程的请求
//取出Runnable,并加入到相应队列
Bundle bundle = intent.getExtras();
HttpConnRunnable httpConnRunnable = bundle.getParcelable(HTTP_POOL_PARAM_KEYWORD);
if (httpConnRunnable != null) {
httpConnRunnable.setHttpConnListener(HttpConnService.this);
int level = httpConnRunnable.getPriority();
switch (level) {
case HttpConnRunnable.HIGH_LEVEL:
//如果高级池满而低级池未满交由低级池处理
//如果高级池满而普通池未满交由普通池处理
//如果高级池未满则交给高级池处理,否则,交由高级池排队等候
if (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
mLowPool.execute(httpConnRunnable);
}
else if (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mNormalPool.getActiveCount() < NORMAL_POOL_SIZE) {
mNormalPool.execute(httpConnRunnable);
}
else {
mHighPool.execute(httpConnRunnable);
}
break;
case HttpConnRunnable.NORMAL_LEVEL:
//如果普通池满而低级池未满交由低级池处理
//如果普通池未满则交给普通池处理,否则,交由普通池排队等候
if (mNormalPool.getActiveCount() == NORMAL_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
mLowPool.execute(httpConnRunnable);
}
else {
mNormalPool.execute(httpConnRunnable);
}
break;
case HttpConnRunnable.LOW_LEVEL:
mLowPool.execute(httpConnRunnable);
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
mHighPool.shutdownNow();
mNormalPool.shutdownNow();
mLowPool.shutdownNow();
mNormalPool = null;
mLowPool = null;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onSucceed(String result) {
Intent intent = new Intent();
intent.setAction("com.ezstudio.connpool.HttpConnReceiver");
// 要发送的内容
intent.putExtra("RESULT", result);
// 发送 一个无序广播
sendBroadcast(intent);
}
@Override
public void onFailed() {
// TODO Auto-generated method stub
}
}
public class HttpConnReceiver extends BroadcastReceiver {
private HttpConnListener mListener;
public void setHttpConnListener (HttpConnListener listener) {
mListener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("com.ezstudio.connpool.HttpConnReceiver")) {
String result = intent.getStringExtra("RESULT");
mListener.onSucceed(result);
}
}
}
基本解决思路,离线操作的数据请求URL和请求参数进行封装,封装到对象中,转化为json存储到SQlLite数据库中;定时任务检测网络情况,如果有网,则把数据库中数据取出,进行网络上传;
取出数据库中请求,就需要处理大量网络请求,同时发送请求的情况,一般来说一个网络请求都会用使用到一个异步线程,大量的线程创建、运行、销毁又造成了系统资源的浪费,而且同时同时new出多个子线程也会造成客户端卡死现象;于是考虑到能不能做个请求队列去进行控制
在这个模型中,有高中低三个优先级信道如下:高优先级--1,中优先级--3,低优先级--2
规则:
1.正常情况下各个优先级使用各自信道(线程)
2.高级信道满载、中、低级信道空置,则高级请求可使用低级信道
构思:
UI线程将期望的网络请求url和参数通过一个封装好的Runnable提交给Service处理(当然也可以交给一个Thread处理,本例使用Service),Service接收到请求,判断优先级,加入到相应线程池中排队。线程池启动线程发起网络请求,最后通过监听器将结果返回给Service,Service发送广播通知UI线程,UI线程更新相关界面,结束。
废话说完,上例子:
首先是封装好的Runnable
public class HttpConnRunnable implements Runnable, Parcelable {
public static final int HIGH_LEVEL = 0;
public static final int NORMAL_LEVEL = 1;
public static final int LOW_LEVEL = 2;
private int mPriority = NORMAL_LEVEL;//优先级,默认为普通
private String mUrl = "";
private HttpConnListener mListener;//监听器
public HttpConnRunnable() {
super();
}
public HttpConnRunnable(int priority) {
super();
mPriority = priority;
}
@Override
public void run() {
Log.i(Thread.currentThread().getName(), "----Start to connect:" + mUrl + ", priority:" + mPriority + "-----");
try {
Thread.sleep(10000);
//TODO:进行网络请求相关操作,并通过listener返回结果
mListener.onSucceed("Connected to " + mUrl + " succeed!");
}
catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(Thread.currentThread().getName(), "----Finish to connect:" + mUrl + ", priority:" + mPriority + "-----");
}
public int getPriority() {
return mPriority;
}
public void setPriority(int priority) {
mPriority = priority;
}
public String getURL() {
return mUrl;
}
public void setURL(String url) {
mUrl = url;
}
public void setHttpConnListener(HttpConnListener listener) {
mListener = listener;
}
//序列化,为了传递给Service,如果是使用Thread处理本例,则无需序列化
public static final Parcelable.Creator CREATOR = new Creator() {
@Override
public HttpConnRunnable createFromParcel(Parcel source) {
HttpConnRunnable data = null;
Bundle bundle = source.readBundle();
if(bundle != null) {
data = new HttpConnRunnable(bundle.getInt("PRIORITY"));
data.mUrl = bundle.getString("URL");
}
return data;
}
@Override
public HttpConnRunnable[] newArray(int size) {
return new HttpConnRunnable[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Bundle bundle = new Bundle();
bundle.putInt("PRIORITY", mPriority);
bundle.putString("URL", mUrl);
dest.writeBundle(bundle);
}
}
Service的处理:
public class HttpConnService extends Service implements HttpConnListener {
public static final String HTTP_POOL_PARAM_KEYWORD = "HttpPoolParam"; //网络参数传递的关键字
private final int HIGH_POOL_SIZE = 1;
private final int NORMAL_POOL_SIZE = 3;
private final int LOW_POOL_SIZE = 2;
// 可重用固定线程数的线程池
private ThreadPoolExecutor mHighPool;
private ThreadPoolExecutor mNormalPool;
private ThreadPoolExecutor mLowPool;
@Override
public void onCreate() {
//初始化所有
mHighPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(HIGH_POOL_SIZE);
mNormalPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(NORMAL_POOL_SIZE);
mLowPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOW_POOL_SIZE);
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//接受到来自UI线程的请求
//取出Runnable,并加入到相应队列
Bundle bundle = intent.getExtras();
HttpConnRunnable httpConnRunnable = bundle.getParcelable(HTTP_POOL_PARAM_KEYWORD);
if (httpConnRunnable != null) {
httpConnRunnable.setHttpConnListener(HttpConnService.this);
int level = httpConnRunnable.getPriority();
switch (level) {
case HttpConnRunnable.HIGH_LEVEL:
//如果高级池满而低级池未满交由低级池处理
//如果高级池满而普通池未满交由普通池处理
//如果高级池未满则交给高级池处理,否则,交由高级池排队等候
if (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
mLowPool.execute(httpConnRunnable);
}
else if (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mNormalPool.getActiveCount() < NORMAL_POOL_SIZE) {
mNormalPool.execute(httpConnRunnable);
}
else {
mHighPool.execute(httpConnRunnable);
}
break;
case HttpConnRunnable.NORMAL_LEVEL:
//如果普通池满而低级池未满交由低级池处理
//如果普通池未满则交给普通池处理,否则,交由普通池排队等候
if (mNormalPool.getActiveCount() == NORMAL_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
mLowPool.execute(httpConnRunnable);
}
else {
mNormalPool.execute(httpConnRunnable);
}
break;
case HttpConnRunnable.LOW_LEVEL:
mLowPool.execute(httpConnRunnable);
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
mHighPool.shutdownNow();
mNormalPool.shutdownNow();
mLowPool.shutdownNow();
mNormalPool = null;
mLowPool = null;
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onSucceed(String result) {
Intent intent = new Intent();
intent.setAction("com.ezstudio.connpool.HttpConnReceiver");
// 要发送的内容
intent.putExtra("RESULT", result);
// 发送 一个无序广播
sendBroadcast(intent);
}
@Override
public void onFailed() {
// TODO Auto-generated method stub
}
}
Receiver的处理比较简单:
public class HttpConnReceiver extends BroadcastReceiver {
private HttpConnListener mListener;
public void setHttpConnListener (HttpConnListener listener) {
mListener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("com.ezstudio.connpool.HttpConnReceiver")) {
String result = intent.getStringExtra("RESULT");
mListener.onSucceed(result);
}
}
}
相关文章推荐
- 网络出版新规来了 自媒体行业也要审批办证?
- linux开机自动启动网络
- QPS到26---工具用http_load
- https://projecteuler.net/problem=12
- [国嵌攻略][089][网络协议分析]
- Java网络连接之HttpURLConnection与HttpClient 区别及联系
- iOS9 beta 请求出现App Transport Security has blocked a cleartext HTTP (http://)
- ArcGIS网络分析之构建网络分析数据集(一)
- xUtils网络请求时的参数问题
- 关于android 如何判断是否连接网络
- Python网络爬虫视频教程
- java apache commons HttpClient发送get和post请求的学习整理
- 为什么视频用udp不用tcp
- HTTPClient模块的HttpGet和HttpPost
- centos7安装桥接的网络后,主机开机无网络
- HttpClient使用详解
- 网络抓包工具 Fiddler
- 理解 Linux 网络栈(2):非虚拟化Linux 环境中的 Segmentation Offloading 技术
- iOS网络高级编程:iPhone和iPad的企业应用开发之错误处理
- tcp粘包问题(经典分析)