Android最基本的异步网络请求框架
本篇文章我们来一起写一个最基本的Android异步网络请求框架,借此来了解下Android中网络请求的相关知识。由于个人水平有限,文中难免存在疏忽和谬误,希望大家可以指出,谢谢大家。
1.同步网络请求
以HTTP的GET请求为例,我们来介绍一下Android中一个基本的同步请求框架的实现。直接贴代码:
publicclassHttpUtils{
publicstaticbyte[]get(StringurlString){
HttpURLConnectionurlConnection=null;
try{
URLurl=newURL(urlString);
urlConnection=(HttpURLConnection)url.openConnection();
//设置请求方法
urlConnection.setRequestMethod("GET");
//设置超时时间
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(3000);
//获取响应的状态码
intresponseCode=urlConnection.getResponseCode();
if(responseCode==200){
ByteArrayOutputStreambos=newByteArrayOutputStream();
InputStreamin=urlConnection.getInputStream();
byte[]buffer=newbyte[4*1024];
intlen=-1;
while((len=in.read(buffer))!=-1){
bos.write(buffer,0,len);
}
close(in);
byte[]result=bos.toByteArray();
close(bos);
returnresult;
}else{
returnnull;
}
}catch(Exceptione){
e.printStackTrace();
}finally{
if(urlConnection!=null){
urlConnection.disconnect();
}
}
returnnull;
}
privatestaticvoidclose(Closeablestream){
if(stream!=null){
try{
stream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
相信以上的代码我们大家都不陌生,以上代码就实现了基本的同步网络请求功能,get方法会返回一个byte[]数组,后续我们可以根据返回的相应类型(文本或图片)对这个字节数组作进一步处理。
2.异步网络请求
通常一个异步HTTPGET请求是这样的:发出get方法的调用后,相关任务会在后台线程中自动执行,而我们在主线程中继续处理其他工作,它成功获取GET请求的响应时,就会回调onSuccess方法。最直接的写法通常如下所示:
publicclassAsyncHttpUtils{publicstaticbyte[]get(Stringurl,ResponseHandlerhandler){
finalHandlermHandler=newHandler();
newThread(newRunnable(){
@Override
publicvoidrun(){
finalbyte[]result=HttpUtils.get(url);
handler.post(newRunnable(){
@Override
publicvoidrun(){
responseHandler.onSuccess(result);
}
});
}
});
}
}
其中,ResponseHandler接口的定义如下:
publicinterfaceResponseHandler{
voidonSucess(bytep[]result);
}
我们可以看到,以上实现异步GET请求的代码很直截了当,然而存在着以下问题:每次请求时都会创建一个线程,这样当请求比较频繁的情况下会创建大量大线程,这样的话创建、销毁线程以及线程调度的开销会很大。而且Thread对象是一个匿名内部类对象,会隐式持有外围类引用,可能会引起MemoryLeak。
针对以上问题,我们可以使用线程池来复用线程,以避免不必要的创建及销毁线程的开销,改进后AsyncHttpUtils类的代码如下:
publicclassAsyncHttpUtils{
//获取当前设备的CPU数
publicstaticfinalintCPU_COUNT=Runtime.getRuntime().availableProcessors();
//核心池大小设为CPU数加1
privatestaticfinalintCORE_POOL_SIZE=CPU_COUNT+1;
//设置线程池的最大大小
privatestaticfinalintMAX_POOL_SIZE=2*CPU_COUNT+1;
//存活时间
privatestaticfinallongKEEP_ALIVE=5L;
//创建线程池对象
publicstaticfinalExecutorthreadPoolExecutor=newThreadPoolExecutor(CORE_POOL_SIZE,
MAX_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,newLinkedBlockingQueue<Runnable>());
publicstaticvoidget(finalStringurl,finalResponseHandlerresponseHandler){
finalHandlermHandler=newHandler(Looper.getMainLooper());
//创建一个新的请求任务
RunnablerequestRunnable=newRunnable(){
@Override
publicvoidrun(){
finalbyte[]result=HttpUtils.get(url);
if(result!=null){
mHandler.post(newRunnable(){
@Override
publicvoidrun(){
//result不为空表明请求成功,回调onSuccess方法
responseHandler.onSuccess(result);
}
});
}
}
};
threadPoolExecutor.execute(requestRunnable);
}
}
以上代码主要就是使用了线程池来达到线程的复用的目的,希望本文所述对大家学习Android软件编程有所帮助。