From 85125958f9d046c85759e45426abb02b45bfe980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 20:55:47 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E7=BC=96=E5=86=99Volley=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes http/volley-source.md | 33 +++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.DS_Store b/.DS_Store index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..98d38dff106640c027ab6a45121f0a01ae938559 100644 GIT binary patch literal 6148 zcmeHK&2G~`5S~p#u-l6fAXVbxBS=w|wxDoy(-f(Pim0wyA&P=sTaA(HwQMI5iX!>U znJ3`?JrJCD0C*HmVP$m3ZrrI zC9A1S1Cfb2GT49@kiz+Xyu{Xte^CK?cP5+xhY^HOd4K%OkGYSd^wW5Res?AeBY-*# zpuj8Lj~95~h=*RA&4~7!=a2JL&G*w!<0vm$tsktmQoq)?ZkVfUbXhl6pSc4*b_=f< z<{dA4Dtb{6`YP^u#o#hN;yj+mo_`#L zoqG><4xXgbS8v|Fd;j6%r_W!+BLl;~g0PzkFX1Z&bKypAmc%?c#~krZID|defi4^% zZomZui_)?~WRbK?N!x%UcnrH&a=#O|^186AO)H=k&&rw)Pl;yzG z;e)9=Gj&2?;_f)VE$F};iMrJaXayD(Sdm?e_W!*;o~Xs@-=pQDozuar11!9Z-q$fd1#9bFjaZ3++_g{4Hypy>|*A%kwT0)JJ3U!u8; A2mk;8 delta 69 zcmZoMXfc=|#>AjHu~2NHo+1YW5HK<@2yFhyEXJ~lWft>hb`E|Hpgd6EJM(0I5k*d* SG(!SN-DDFU<;^i7E0_Tq_YVO8 diff --git a/http/volley-source.md b/http/volley-source.md index ea1a5bb..2c0b207 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -1,11 +1,36 @@ # Volley源码剖析 ## 网络数据请求详解 +在了解了Volley的基本使用之后我们都知道,不论是实现http请求,还是对网络图片做缓存加载,除了使用ImageLoader方式,都会经历几个主要步骤: +1.使用Volley创建一个RequestQueue队列 +2.新建一个相应的Request +3.将新建的Request添加到队列中 -1.从RequestQueue入手,new、start、add都做了些什么? -2.看看StringRequest是怎么实现的? -3.参考StringRequest定制自己的请求类 -4.进阶优化,进行封装组合 +那么我们从Volley入手,来看看整个库是怎么工作的。 +我们打开Volley类。可以看到,Volley当中只有两个重载的方法newRequestQueue。用于创建一个请求队列。 +一般我们默认使用newRequestQueue(Context context) 只传递一个context参数的方法。这个方法则是调用了上面两个参数的方法,后面的参数传递为null。 + +``Java +if (stack == null) { + if (Build.VERSION.SDK_INT >= 9) { + stack = new HurlStack(); + } else { + // Prior to Gingerbread, HttpUrlConnection was unreliable. + // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html + stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); + } + } + + Network network = new BasicNetwork(stack); + +``Java +从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 + + +1.从RequestQueue入手,new、start、add都做了些什么? +2.看看StringRequest是怎么实现的? +3.参考StringRequest定制自己的请求类 +4.进阶优化,进行封装组合 ## 网络图片缓存加载详解 From f9ce449547cd22a89e710415e0c538630370a166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 21:02:07 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E5=95=8A=E5=95=8A=E5=95=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes http/volley-source.md | 11 ++++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.DS_Store b/.DS_Store index 98d38dff106640c027ab6a45121f0a01ae938559..c0801a7001751ed83f8bd82866505c2bf0eaf1b6 100644 GIT binary patch delta 20 bcmZoMXffEJ!_01IuA^XNVY=Cv`JxB_I%WlM delta 20 bcmZoMXffEJ!_01BtfOFLZnW8$`JxB_I&}qa diff --git a/http/volley-source.md b/http/volley-source.md index 2c0b207..a2f969c 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -10,7 +10,7 @@ 我们打开Volley类。可以看到,Volley当中只有两个重载的方法newRequestQueue。用于创建一个请求队列。 一般我们默认使用newRequestQueue(Context context) 只传递一个context参数的方法。这个方法则是调用了上面两个参数的方法,后面的参数传递为null。 -``Java +```java if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); @@ -21,10 +21,11 @@ if (stack == null) { } } - Network network = new BasicNetwork(stack); - -``Java -从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 + Network network = new BasicNetwork(stack); +``` + +从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 +那么这个方法具体做了什么事情呢 1.从RequestQueue入手,new、start、add都做了些什么? From 1f01b095c93ce8bd9d503542cd08423089709dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 21:36:44 +0800 Subject: [PATCH 03/14] 2 --- .DS_Store | Bin 6148 -> 6148 bytes http/volley-source.md | 31 ++++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.DS_Store b/.DS_Store index c0801a7001751ed83f8bd82866505c2bf0eaf1b6..0dc51ca7919a05341d389daf0e61d6d2e823594b 100644 GIT binary patch delta 21 ccmZoMXffEJ&CFq9VWOj8XlA_GnE9dz06%C2qW}N^ delta 21 ccmZoMXffEJ&CFqFXs)ARWMR75nE9dz06#DVp#T5? diff --git a/http/volley-source.md b/http/volley-source.md index a2f969c..db9d2fe 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -10,7 +10,28 @@ 我们打开Volley类。可以看到,Volley当中只有两个重载的方法newRequestQueue。用于创建一个请求队列。 一般我们默认使用newRequestQueue(Context context) 只传递一个context参数的方法。这个方法则是调用了上面两个参数的方法,后面的参数传递为null。 -```java +在这个方法,主要做了几个事情: + 1.设置默认的缓存文件夹 + ```java + private static final String DEFAULT_CACHE_DIR = "volley"; + + File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); + ``` + + 2.获取APP的包名,版本号,添加userAgent到请求头中,如果获取失败则默认使用Volley/0: + ```java + String userAgent = "volley/0"; + try { + String packageName = context.getPackageName(); + PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + userAgent = packageName + "/" + info.versionCode; + } catch (NameNotFoundException e) { + } + + + 3.对stack进行相关操作,得到NetWork对象。从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 + + ```java if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); @@ -24,8 +45,12 @@ if (stack == null) { Network network = new BasicNetwork(stack); ``` -从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 -那么这个方法具体做了什么事情呢 + 4.最后,根据设定的缓存文件夹新建一个缓存对象,创建一个请求队列,参数为上面创建的缓存对象及NetWork对象,然后启动请求队列,同时将队列对象作为返回值返回,我们调用这个方法就会将返回值赋值给我们创建的全局队列对象。 + + ```java + RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); + queue.start(); +``` 1.从RequestQueue入手,new、start、add都做了些什么? From 16030bfd431f88eecc8f70b2335ba662254bc17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 22:01:52 +0800 Subject: [PATCH 04/14] 2 --- http/volley-source.md | 66 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/http/volley-source.md b/http/volley-source.md index db9d2fe..ab2b813 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -2,15 +2,15 @@ ## 网络数据请求详解 在了解了Volley的基本使用之后我们都知道,不论是实现http请求,还是对网络图片做缓存加载,除了使用ImageLoader方式,都会经历几个主要步骤: -1.使用Volley创建一个RequestQueue队列 -2.新建一个相应的Request -3.将新建的Request添加到队列中 - +1.使用Volley创建一个RequestQueue队列 +2.新建一个相应的Request +3.将新建的Request添加到队列中 +一:Volley.java类 那么我们从Volley入手,来看看整个库是怎么工作的。 我们打开Volley类。可以看到,Volley当中只有两个重载的方法newRequestQueue。用于创建一个请求队列。 一般我们默认使用newRequestQueue(Context context) 只传递一个context参数的方法。这个方法则是调用了上面两个参数的方法,后面的参数传递为null。 -在这个方法,主要做了几个事情: +在这个方法,主要做了几个事情: 1.设置默认的缓存文件夹 ```java private static final String DEFAULT_CACHE_DIR = "volley"; @@ -29,7 +29,7 @@ } - 3.对stack进行相关操作,得到NetWork对象。从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法来创建队列。 + 3.对stack进行相关操作,得到NetWork对象。从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。在2.3以前得版本,使用HttpClient来实现请求,在2.3及之后的版本则都是使用HttpUrlConnection来实现,具体实现思路大家可以回顾一下极客学院关于HttpClient和HttpUrlConnection的视频,查看HurlStack和HttpClientStack的源码来了解一下,这里就不再详细讲解。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法,自己新建一个Stack对象传递进来就可以。 ```java if (stack == null) { @@ -47,11 +47,63 @@ if (stack == null) { 4.最后,根据设定的缓存文件夹新建一个缓存对象,创建一个请求队列,参数为上面创建的缓存对象及NetWork对象,然后启动请求队列,同时将队列对象作为返回值返回,我们调用这个方法就会将返回值赋值给我们创建的全局队列对象。 - ```java + ```java RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); ``` +二:RequestQueue.java +接着,我们来看看RequestQueue这个类 +首先,看看它的构造函数: + +```java +public RequestQueue(Cache cache, Network network) { + this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); + } +``` + + +```java +public RequestQueue(Cache cache, Network network, int threadPoolSize) { + this(cache, network, threadPoolSize, + new ExecutorDelivery(new Handler(Looper.getMainLooper()))); + } +``` + +```java +public RequestQueue(Cache cache, Network network, int threadPoolSize, + ResponseDelivery delivery) { + mCache = cache; + mNetwork = network; + mDispatchers = new NetworkDispatcher[threadPoolSize]; + mDelivery = delivery; + } +``` +它有三个重载的构造函数,从传递缓存对象,网络对象,衍生到设置并发请求数量,再到设置回调。 +这里,并发请求数量默认为4,我们也可以自己根据需要定义更多的并发数量。 +在构造函数中主要是设置一些初始值 +接着我们看start方法: + +```java +public void start() { + stop(); // Make sure any currently running dispatchers are stopped. + // Create the cache dispatcher and start it. + mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); + mCacheDispatcher.start(); + + // Create network dispatchers (and corresponding threads) up to the pool size. + for (int i = 0; i < mDispatchers.length; i++) { + NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, + mCache, mDelivery); + mDispatchers[i] = networkDispatcher; + networkDispatcher.start(); + } + } + ``` + + 首先,他会将现有队列停止掉,然后分别创建一个缓存线程以及我们所设定并发数量的网络线程。并且将他们启动。 + + 1.从RequestQueue入手,new、start、add都做了些什么? 2.看看StringRequest是怎么实现的? From 12ad37da9299e314115396f5cf6acda8bc129b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 23:15:19 +0800 Subject: [PATCH 05/14] 4 --- http/volley-source.md | 203 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 189 insertions(+), 14 deletions(-) diff --git a/http/volley-source.md b/http/volley-source.md index ab2b813..3217922 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -5,20 +5,22 @@ 1.使用Volley创建一个RequestQueue队列 2.新建一个相应的Request 3.将新建的Request添加到队列中 -一:Volley.java类 +###Volley.java类 那么我们从Volley入手,来看看整个库是怎么工作的。 我们打开Volley类。可以看到,Volley当中只有两个重载的方法newRequestQueue。用于创建一个请求队列。 一般我们默认使用newRequestQueue(Context context) 只传递一个context参数的方法。这个方法则是调用了上面两个参数的方法,后面的参数传递为null。 在这个方法,主要做了几个事情: - 1.设置默认的缓存文件夹 - ```java + 1.设置默认的缓存文件夹 + +```java private static final String DEFAULT_CACHE_DIR = "volley"; File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); - ``` +``` + + 2.获取APP的包名,版本号,添加userAgent到请求头中,如果获取失败则默认使用Volley/0: - 2.获取APP的包名,版本号,添加userAgent到请求头中,如果获取失败则默认使用Volley/0: ```java String userAgent = "volley/0"; try { @@ -27,11 +29,11 @@ userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } - +``` 3.对stack进行相关操作,得到NetWork对象。从这个代码段我们可以看出。如果stack为空得话volley会根据系统版本,选择对应的方式来创建。在2.3以前得版本,使用HttpClient来实现请求,在2.3及之后的版本则都是使用HttpUrlConnection来实现,具体实现思路大家可以回顾一下极客学院关于HttpClient和HttpUrlConnection的视频,查看HurlStack和HttpClientStack的源码来了解一下,这里就不再详细讲解。如果我们传递了自己自定义的stack 那么就直接使用。因此,如果你想要个性化自己来实现stack,就可以直接调用这个方法,自己新建一个Stack对象传递进来就可以。 - ```java +```java if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); @@ -52,7 +54,7 @@ if (stack == null) { queue.start(); ``` -二:RequestQueue.java +###RequestQueue.java 接着,我们来看看RequestQueue这个类 首先,看看它的构造函数: @@ -79,18 +81,18 @@ public RequestQueue(Cache cache, Network network, int threadPoolSize, mDelivery = delivery; } ``` -它有三个重载的构造函数,从传递缓存对象,网络对象,衍生到设置并发请求数量,再到设置回调。 + +它有三个重载的构造函数,从传递缓存对象,网络对象,衍生到设置并发请求数量,再到设置分发接口。 这里,并发请求数量默认为4,我们也可以自己根据需要定义更多的并发数量。 在构造函数中主要是设置一些初始值 接着我们看start方法: -```java +```java public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); - // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, @@ -98,10 +100,183 @@ public void start() { mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } + } +``` + +首先,他会将现有队列停止掉,然后分别创建一个缓存线程以及我们所设定并发数量的网络线程。并且将他们启动。 + +调用完构造函数,我们会创建一些请求,添加到队列中,我们可以看看add函数: + +```java +public Request add(Request request) { + // Tag the request as belonging to this queue and add it to the set of current requests. + request.setRequestQueue(this); + synchronized (mCurrentRequests) { + mCurrentRequests.add(request); + } + + // Process requests in the order they are added. + request.setSequence(getSequenceNumber()); + request.addMarker("add-to-queue"); + + // If the request is uncacheable, skip the cache queue and go straight to the network. + if (!request.shouldCache()) { + mNetworkQueue.add(request); + return request; + } + + // Insert request into stage if there's already a request with the same cache key in flight. + synchronized (mWaitingRequests) { + String cacheKey = request.getCacheKey(); + if (mWaitingRequests.containsKey(cacheKey)) { + // There is already a request in flight. Queue up. + Queue> stagedRequests = mWaitingRequests.get(cacheKey); + if (stagedRequests == null) { + stagedRequests = new LinkedList>(); + } + stagedRequests.add(request); + mWaitingRequests.put(cacheKey, stagedRequests); + if (VolleyLog.DEBUG) { + VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); + } + } else { + // Insert 'null' queue for this cacheKey, indicating there is now a request in + // flight. + mWaitingRequests.put(cacheKey, null); + mCacheQueue.add(request); + } + return request; + } } - ``` - - 首先,他会将现有队列停止掉,然后分别创建一个缓存线程以及我们所设定并发数量的网络线程。并且将他们启动。 +``` + +这里主要做了几件事情: +1.将请求添加到mCurrentRequests中,同时,给请求添加一个num编号,设置标签为以及添加到队列。 +2.会判断这个请求是否可以被缓存。如果不需要,直接添加到网络队列当中 +3.如果需要,就会取出这个请求的key值,判断等待队列中是否已经有同样的请求,就从当中取出,添加到队列中,如果没有,就创建一个空队列,并且讲请求添加到缓存队列中 +做完这些事情,我们在RequestQueue的start中所运行的2个主要对象mCacheDispatcher和networkDispatcher就开始起作用,他们分别是用户处理缓存队列中的请求以及网络队列中的请求。 +###NetworkDispatcher.java +首先,我们来看看networkDispatcher: +它是继承于线程类,在run方法中主要做了几件事情: +1.从网络队列中取到请求对象: + +```java +Request request; + try { + // Take a request from the queue. + request = mQueue.take(); + } catch (InterruptedException e) { + // We may have been interrupted because it was time to quit. + if (mQuit) { + return; + } + continue; + } +``` + +2.判断请求是否被取消了,如果已经被取消,直接关闭,继续拿下一个请求: + +```java +if (request.isCanceled()) { + request.finish("network-discard-cancelled"); + continue; + } +``` + +3.执行请求,得到NetworkResponse,判断请求是否成功,如果失败了。将请求关闭,继续取下一个请求: + +```java +NetworkResponse networkResponse = mNetwork.performRequest(request); + request.addMarker("network-http-complete"); + // If the server returned 304 AND we delivered a response already, + // we're done -- don't deliver a second identical response. + if (networkResponse.notModified && request.hasHadResponseDelivered()) { + request.finish("not-modified"); + continue; + } +``` + +4.解析请求结果,同时判断这个请求是否允许缓存,如果允许,就使用缓存对象将请求结果保存起来,最后通过分发接口,讲请求结果分发出去 +这个是网络线程一直重复在做的事情,如果网络队列中的请求都执行完了。就会继续等待请求的加入继续执行。 + +###CacheDispatcher +接着我们看看缓存线程: +它同样是继承于线程,在run中做了几件事: +1.从缓存队列中取出请求对象: + +```java +final Request request = mCacheQueue.take(); +request.addMarker("cache-queue-take"); +``` + +2.判断请求是否被取消了,如果已经被取消,同样关闭请求,继续取下一个: + +```java +if (request.isCanceled()) { + request.finish("cache-discard-canceled"); + continue; + } +``` + +3.在缓存对象中取出这个请求的key所保存的缓存数据,判断是否有数据,如果没有就把请求添加到网络队列去继续请求: + +```java +Cache.Entry entry = mCache.get(request.getCacheKey()); + if (entry == null) { + request.addMarker("cache-miss"); + // Cache miss; send off to the network dispatcher. + mNetworkQueue.put(request); + continue; + } + ``` + +4.如果缓存数据已经失效,那么就将缓存数据对象设置到请求中,将请求添加到网络队列去更新缓存数据: + +```java +if (entry.isExpired()) { + request.addMarker("cache-hit-expired"); + request.setCacheEntry(entry); + mNetworkQueue.put(request); + continue; + } + ``` + +5.获取缓存数据的新旧程度,如果较新,就直接使用接口分发出去,如果是间隔比较久的缓存,会在分发的同时,将请求添加到网络队列中去更新缓存数据: + +```java +request.addMarker("cache-hit"); + Response response = request.parseNetworkResponse( + new NetworkResponse(entry.data, entry.responseHeaders)); + request.addMarker("cache-hit-parsed"); + if (!entry.refreshNeeded()) { + // Completely unexpired cache hit. Just deliver the response. + mDelivery.postResponse(request, response); + } else { + // Soft-expired cache hit. We can deliver the cached response, + // but we need to also send the request to the network for + // refreshing. + request.addMarker("cache-hit-refresh-needed"); + request.setCacheEntry(entry); + // Mark the response as intermediate. + response.intermediate = true; + // Post the intermediate response back to the user and have + // the delivery then forward the request along to the network. + mDelivery.postResponse(request, response, new Runnable() { + @Override + public void run() { + try { + mNetworkQueue.put(request); + } catch (InterruptedException e) { + // Not much we can do about this. + } + } + }); + ``` + +以上就是缓存线程所在重复做的事情,同样会在缓存队列空的时候等待新请求进来继续执行。 + + + From aded729cb2850fa89b0918477e7bbda4b5e48f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Thu, 5 Feb 2015 23:21:16 +0800 Subject: [PATCH 06/14] 5 --- http/volley-source.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/http/volley-source.md b/http/volley-source.md index 3217922..5580c25 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -228,7 +228,8 @@ Cache.Entry entry = mCache.get(request.getCacheKey()); mNetworkQueue.put(request); continue; } - ``` +``` + 4.如果缓存数据已经失效,那么就将缓存数据对象设置到请求中,将请求添加到网络队列去更新缓存数据: @@ -239,7 +240,8 @@ if (entry.isExpired()) { mNetworkQueue.put(request); continue; } - ``` +``` + 5.获取缓存数据的新旧程度,如果较新,就直接使用接口分发出去,如果是间隔比较久的缓存,会在分发的同时,将请求添加到网络队列中去更新缓存数据: @@ -271,7 +273,8 @@ request.addMarker("cache-hit"); } } }); - ``` +``` + 以上就是缓存线程所在重复做的事情,同样会在缓存队列空的时候等待新请求进来继续执行。 From d5982d3783944cd423de0b97f8482ceede3426f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Fri, 6 Feb 2015 00:46:31 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http/images/imageloader.png | Bin 0 -> 98700 bytes http/volley-source.md | 231 ++++++++++++++++++++++++++++++++++-- 2 files changed, 222 insertions(+), 9 deletions(-) create mode 100644 http/images/imageloader.png diff --git a/http/images/imageloader.png b/http/images/imageloader.png new file mode 100644 index 0000000000000000000000000000000000000000..214ebf363aa2b89d43cb768e11a5a8201ab90258 GIT binary patch literal 98700 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 literal 0 HcmV?d00001 diff --git a/http/volley-source.md b/http/volley-source.md index 5580c25..d45e79b 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -278,19 +278,232 @@ request.addMarker("cache-hit"); 以上就是缓存线程所在重复做的事情,同样会在缓存队列空的时候等待新请求进来继续执行。 +###Request +接着,我们来看看最常使用到的请求类Request,它是一个抽象类,我们所使用的StringRequest,JsonRequest等都是继承于它来实现的,这里我们不详细讲解它的实现方式,我们以StringRequest为例来看看一个特定类型的请求是怎么实现的 +我们可以看到,它只有很少的一部分代码,包括两个重载的构造函数,以及2个重写的方法,parseNetworkResponse,以及deliverResponse。 +parseNetworkResponse主要用于将请求得到的数据转换成我们所需要的对应格式的数据,如StringRequest就是将请求结果转为String: +```java +@Override + protected Response parseNetworkResponse(NetworkResponse response) { + String parsed; + try { + parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); + } catch (UnsupportedEncodingException e) { + parsed = new String(response.data); + } + return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); + } +``` + +而deliverResponse则是将请求结果以对应的数据格式传递给回调: + +```java +@Override + protected void deliverResponse(String response) { + mListener.onResponse(response); + } +``` + +这里,我们不妨来定义一个返回xml格式的请求: +我们在项目中新建一个XmlRequest,继承于Request:代码如下 + +```java +public class XmlRequest extends Request { + private final Listener mListener; + + + public XmlRequest(String url,Listener listener, ErrorListener errorListener) { + this(Method.GET,url,listener,errorListener); + + } + public XmlRequest(int mothod,String url,Listener listener, ErrorListener errorListener) { + super(mothod, url, errorListener); + mListener = listener; + } + + @Override + protected Response parseNetworkResponse( + NetworkResponse response) { + try{ + String xmlString=new String(response.data,HttpHeaderParser.parseCharset(response.headers)); + XmlPullParserFactory factory=XmlPullParserFactory.newInstance(); + XmlPullParser xmlPullParser=factory.newPullParser(); + xmlPullParser.setInput(new StringReader(xmlString)); + return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response)); + }catch(UnsupportedEncodingException e){ + return Response.error(new ParseError(e)); + }catch (XmlPullParserException e) { + return Response.error(new ParseError(e)); + } + } + + @Override + protected void deliverResponse(XmlPullParser response) { + mListener.onResponse(response); + } + +} +``` + +这样,我们就可以根据自己的需要定制自己想要的数据类型。我们也可以使用第三方库gson之类,直接将结果映射到实体上,定制出更加方便的请求。 +## 网络图片缓存加载详解 +接下来,我们来看看关于网络图片缓存加载的相关源码 +###ImageRequest +首先我们来看看ImageRequest,它是继承于Request的类,我们从前面的解析就能知道,ImageRequest是定制了Bitmap格式返回数据的请求,主要是对图片数据的一些处理,我们就不详细介绍。 + +###ImageLoader +那么我们来看看ImageLoader,使用ImageLoader是大部分人使用Volley来加载图片的方式,我们从构造函数入手: + +```java + public ImageLoader(RequestQueue queue, ImageCache imageCache) { + mRequestQueue = queue; + mCache = imageCache; + } +``` + +这里一般我们传入的是我们新建的ImageCache,大部分情况下我们都没做相关的操作,我们接着从get方法来看: +主要有两个重载方式,一个有设置最大宽高,一个则默认没有,在这里,主要做几件事: +1.判断加载的图片url是否在缓存中有数据,如果有,就取出来,通过接口分发出去,需要注意的是,这里所使用的是我们所新建的缓存对象,如果你默认没做处理,这里都是没有缓存数据,需要通过后面新建图片请求,来判断请求是否有缓存并返回: + +```java + final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight); + // Try to look up the request in the cache of remote images. + Bitmap cachedBitmap = mCache.getBitmap(cacheKey); + if (cachedBitmap != null) { + // Return the cached bitmap. + ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null); + imageListener.onResponse(container, true); + return container; + } +``` + +2.如果不存在缓存,先告诉传递空数据,让它知道要加载默认图片: + +```java + ImageContainer imageContainer = + new ImageContainer(null, requestUrl, cacheKey, imageListener); + // Update the caller to let them know that they should use the default bitmap. + imageListener.onResponse(imageContainer, true); +``` + +```java + public static ImageListener getImageListener(final ImageView view, + final int defaultImageResId, final int errorImageResId) { + return new ImageListener() { + @Override + public void onErrorResponse(VolleyError error) { + if (errorImageResId != 0) { + view.setImageResource(errorImageResId); + } + } + @Override + public void onResponse(ImageContainer response, boolean isImmediate) { + if (response.getBitmap() != null) { + view.setImageBitmap(response.getBitmap()); + } else if (defaultImageResId != 0) { + view.setImageResource(defaultImageResId); + } + } + }; + } +``` + +3.判断这个url是否已经存在请求队列中,如果存在,就等待请求,不继续操作: + +```java + BatchedImageRequest request = mInFlightRequests.get(cacheKey); + if (request != null) { + // If it is, add this request to the list of listeners. + request.addContainer(imageContainer); + return imageContainer; + } +``` + +4.如果不存在,创建一个请求,添加到队列中: + +```java + Request newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, cacheKey); + mRequestQueue.add(newRequest); + mInFlightRequests.put(cacheKey, + new BatchedImageRequest(newRequest, imageContainer)); + return imageContainer; +``` + +```java + protected Request makeImageRequest(String requestUrl, int maxWidth, int maxHeight, final String cacheKey) { + return new ImageRequest(requestUrl, new Listener() { + @Override + public void onResponse(Bitmap response) { + onGetImageSuccess(cacheKey, response); + } + }, maxWidth, maxHeight, + Config.RGB_565, new ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + onGetImageError(cacheKey, error); + } + }); + } +``` + +在获取数据成功之后,就会调用我们创建的cache对象来保存缓存数据,如果我们不做操作,则默认会在请求那边来保存缓存。 + +```java + protected void onGetImageSuccess(String cacheKey, Bitmap response) { + // cache the image that was fetched. + mCache.putBitmap(cacheKey, response); + // remove the request from the list of in-flight requests. + BatchedImageRequest request = mInFlightRequests.remove(cacheKey); + if (request != null) { + // Update the response bitmap. + request.mResponseBitmap = response; + // Send the batched response + batchResponse(cacheKey, request); + } + } +``` + +这里,我们可以看出ImageLoader的缓存流程是这样的: + +![volley](images/imageloader.png) + +Volley默认使用的是缓存到SD卡的方式,对于缓存图片来说,我们更喜欢缓存到内存上,因此,我们就可以通过自定义缓存的方式,来加大缓存图片的效率。我们可以新建一个内存缓存 LruBitmapCache: +```java +public class LruBitmapCache implements ImageCache { + private LruCache mCache; + public LruBitmapCache() { + int maxSize = 10 * 1024 * 1024; + mCache = new LruCache(maxSize) { + @Override + protected int sizeOf(String key, Bitmap bitmap) { + return bitmap.getRowBytes() * bitmap.getHeight(); + } + }; + } + @Override + public Bitmap getBitmap(String url) { + return mCache.get(url); + } + @Override + public void putBitmap(String url, Bitmap bitmap) { + mCache.put(url, bitmap); + } +} +``` -1.从RequestQueue入手,new、start、add都做了些什么? -2.看看StringRequest是怎么实现的? -3.参考StringRequest定制自己的请求类 -4.进阶优化,进行封装组合 +在使用ImageLoader的时候只要使用这个缓存作为参数就可以: -## 网络图片缓存加载详解 +```java +ImageLoader imageLoader = new ImageLoader(mQueue, new LruBitmapCache()); +``` +###NetworkImageView +最后,我们来看看Volley提供的自定义控件NetworkImageView +它是继承于ImageView 的自定义控件,在当中加入了设置默认图片及错误图片等方法,通过setImageUrl方法,传递ImageLoader对象,通过ImageLoader对象来加载。这里我们就不做太多介绍。 -1.ImageRequest的实现方式解析 -2.ImageLoader的操作流程 -3.进阶定制,增加缓存到内存的方式,提高加载效率 -4.NetworkImageView解析 \ No newline at end of file +##总结 +通过了解Volley的一些重要类的源码之后,我们都被谷歌工程师强大的逻辑和灵活的代码思维给折服了,我们可以从中学习到很多扩展性强大的代码结构方式。 +目前我们所讲解的仅仅是初步的源码分析,如果有兴趣大家也可以继续深入,把最内层的实现都分析清楚。研究完源码,不妨尝试着自己来封装一个类似的库出来。一步步完善。这就是开源的乐趣。 \ No newline at end of file From 039b66a08e5b7d4eae7a2e1c16e084cacb9eb2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Fri, 6 Feb 2015 01:25:57 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=A6=E5=A4=96?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes http/Android-Async-Http.md | 112 +++++++++++++++++++++++++++++++++++++ http/Ok-Http.md | 112 +++++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 http/Android-Async-Http.md create mode 100644 http/Ok-Http.md diff --git a/.DS_Store b/.DS_Store index 0dc51ca7919a05341d389daf0e61d6d2e823594b..d73c4813e82c74c1f3ec1e11ea99ff65e363b265 100644 GIT binary patch delta 21 ccmZoMXffEJ&CFqJVy>fLWM;Y9nE9dz06%yIr~m)} delta 21 ccmZoMXffEJ&CFq9VWOj8XlA_GnE9dz06%C2qW}N^ diff --git a/http/Android-Async-Http.md b/http/Android-Async-Http.md new file mode 100644 index 0000000..c892d55 --- /dev/null +++ b/http/Android-Async-Http.md @@ -0,0 +1,112 @@ +# Android-Async-Http基本使用介绍 + +## Android-Async-Http简介 + +为Android构建的基于异步回调的Http客户端,是基于Apache HttpClient库的。所有的请求都是独立于应用程序主线程 UI 之外,但任何回调逻辑跟在线程上通过Android的handler创建消息传递执行回调是一样的。 +以官网的说法,Twitter的app所使用的就是Android-Async-Http + +###特点 +相对于其他库,Android-Async-Http比较特有的地方就是可以通过RequestParams直接传递文件参数上传文件。这个功能,我个人还是挺喜欢的,在平时做图片和文件上传十分的方便。同时它对文件下载的封装也做得很好。 + + +源码托管地址: +https://github.com/loopj/android-async-http + +官方网站: +http://loopj.com/android-async-http/ + +## Android-Async-Http基本使用 + +### 下载Android-Async-Http源码 + +我们有几种方式来下载Android-Async-Http源码: + +* 1. 从官网下载jar包:http://loopj.com/android-async-http/ +* 2. 通过github使用git命令或者直接下载源码压缩包: https://github.com/loopj/android-async-http +* 3. 从极客学院课程资料当中 + +### 实现一个基本HTTP请求 + +接下来,我们来使用Android-Async-Http实现一个最简单的http请求。 + +所需权限: + +```xml + +``` +使用Android-Async-Http十分的简单,只要创建一个AsyncHttpClient对象通过这个对象就可以做我们想做的事情 +基本代码实现: + +```java +AsyncHttpClient client = new AsyncHttpClient(); +client.get("http://www.jikexueyuan.com", new AsyncHttpResponseHandler() { + + @Override + public void onStart() { + //请求开始回调 + } + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] response) { + //请求成功回调 + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { + // 请求失败回调 + } + + +}); +``` + +只需要简单几句代码,我们就可以实现一个基本的http请求。这样的代码量是不是写起来非常的痛快? + +### 实现Post请求方式并传递参数 + +使用Android-Async-Http来实现Post请求一样很简单,只需要调用post方法,并且用RequestParams来设定参数就可以: + +```java +RequestParams params = new RequestParams(); +params.put("key", "value"); +StringRequest mPostRequest=new StringRequest(Method.POST, "http://www.jikexueyuan.com", new Listener() { + + @Override + public void onResponse(String response) { + // TODO Auto-generated method stub + Log.e("jikexueyuan", "请求结果:"+response); + } + }, new ErrorListener() { + + @Override + public void onErrorResponse(VolleyError error) { + // TODO Auto-generated method stub + Log.e("jikexueyuan", "出错啦:"+error.getMessage()); + } + }){ + @Override + protected Map getParams() throws AuthFailureError { + // TODO Auto-generated method stub + Map map=new HashMap(); + map.put("参数名1", "参数值1"); + map.put("参数名2", "参数值2"); + return map; + } + }; + mQueue.add(mPostRequest); +``` + +### 实现文件上传,下载 + + + +## 总结 + +以上就是Android-Async-Http的一些基本使用方法 + + + + + + + diff --git a/http/Ok-Http.md b/http/Ok-Http.md new file mode 100644 index 0000000..e4852b0 --- /dev/null +++ b/http/Ok-Http.md @@ -0,0 +1,112 @@ +# Ok-Http基本使用介绍 + +## Ok-Http简介 + +为Android构建的基于异步回调的Http客户端,是基于Apache HttpClient库的。所有的请求都是独立于应用程序主线程 UI 之外,但任何回调逻辑跟在线程上通过Android的handler创建消息传递执行回调是一样的。 +以官网的说法,Twitter的app所使用的就是Android-Async-Http + +###特点 +相对于其他库,Android-Async-Http比较特有的地方就是可以通过RequestParams直接传递文件参数上传文件。这个功能,我个人还是挺喜欢的,在平时做图片和文件上传十分的方便。同时它对文件下载的封装也做得很好。 + + +源码托管地址: +https://github.com/loopj/android-async-http + +官方网站: +http://loopj.com/android-async-http/ + +## Ok-Http基本使用 + +### 下载Ok-Http源码 + +我们有几种方式来下载Ok-Http源码: + +* 1. 从官网下载jar包:http://loopj.com/android-async-http/ +* 2. 通过github使用git命令或者直接下载源码压缩包: https://github.com/loopj/android-async-http +* 3. 从极客学院课程资料当中 + +### 实现一个基本HTTP请求 + +接下来,我们来使用Ok-Http实现一个最简单的http请求。 + +所需权限: + +```xml + +``` +使用Ok-Http十分的简单,只要创建一个AsyncHttpClient对象通过这个对象就可以做我们想做的事情 +基本代码实现: + +```java +AsyncHttpClient client = new AsyncHttpClient(); +client.get("http://www.jikexueyuan.com", new AsyncHttpResponseHandler() { + + @Override + public void onStart() { + //请求开始回调 + } + + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] response) { + //请求成功回调 + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { + // 请求失败回调 + } + + +}); +``` + +只需要简单几句代码,我们就可以实现一个基本的http请求。这样的代码量是不是写起来非常的痛快? + +### 实现Post请求方式并传递参数 + +使用Ok-Http来实现Post请求一样很简单,只需要调用post方法,并且用RequestParams来设定参数就可以: + +```java +RequestParams params = new RequestParams(); +params.put("key", "value"); +StringRequest mPostRequest=new StringRequest(Method.POST, "http://www.jikexueyuan.com", new Listener() { + + @Override + public void onResponse(String response) { + // TODO Auto-generated method stub + Log.e("jikexueyuan", "请求结果:"+response); + } + }, new ErrorListener() { + + @Override + public void onErrorResponse(VolleyError error) { + // TODO Auto-generated method stub + Log.e("jikexueyuan", "出错啦:"+error.getMessage()); + } + }){ + @Override + protected Map getParams() throws AuthFailureError { + // TODO Auto-generated method stub + Map map=new HashMap(); + map.put("参数名1", "参数值1"); + map.put("参数名2", "参数值2"); + return map; + } + }; + mQueue.add(mPostRequest); +``` + +### 实现文件上传,下载 + + + +## 总结 + +以上就是Ok-Http的一些基本使用方法 + + + + + + + From b771ea9354d506bf4047c0ba98f7645d6524ce06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Fri, 6 Feb 2015 01:47:55 +0800 Subject: [PATCH 09/14] 2 --- http/volley.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/volley.md b/http/volley.md index ef38a3e..a98a28d 100644 --- a/http/volley.md +++ b/http/volley.md @@ -20,7 +20,7 @@ http://developer.android.com/training/volley/index.html ### 下载Volley源码 -我们有几种方式来下载Volley源码: +我们有几种方式来下载'Volley'源码: * 1. git命令克隆:git clone https://android.googlesource.com/platform/frameworks/volley * 2. 直接访问 https://android.googlesource.com/platform/frameworks/volley From f2839f8e2df03377ac1ce8295ff04aabdde7a81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Fri, 6 Feb 2015 01:48:34 +0800 Subject: [PATCH 10/14] 3 --- http/volley.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/volley.md b/http/volley.md index a98a28d..c3c99a3 100644 --- a/http/volley.md +++ b/http/volley.md @@ -20,7 +20,7 @@ http://developer.android.com/training/volley/index.html ### 下载Volley源码 -我们有几种方式来下载'Volley'源码: +我们有几种方式来下载`Volley`源码: * 1. git命令克隆:git clone https://android.googlesource.com/platform/frameworks/volley * 2. 直接访问 https://android.googlesource.com/platform/frameworks/volley From 4bb6fe6f5cce7dfb23de66d9f0d1e8bab15dc914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Fri, 6 Feb 2015 09:21:47 +0800 Subject: [PATCH 11/14] 5 --- http/volley-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/volley-source.md b/http/volley-source.md index d45e79b..2305612 100644 --- a/http/volley-source.md +++ b/http/volley-source.md @@ -505,5 +505,5 @@ ImageLoader imageLoader = new ImageLoader(mQueue, new LruBitmapCache()); 它是继承于ImageView 的自定义控件,在当中加入了设置默认图片及错误图片等方法,通过setImageUrl方法,传递ImageLoader对象,通过ImageLoader对象来加载。这里我们就不做太多介绍。 ##总结 -通过了解Volley的一些重要类的源码之后,我们都被谷歌工程师强大的逻辑和灵活的代码思维给折服了,我们可以从中学习到很多扩展性强大的代码结构方式。 +通过了解Volley的一些重要类的源码之后,我们都被谷歌工程师强大的逻辑和灵活的代码结构给折服了,我们可以从中学习到很多扩展性强大的代码设计方式。 目前我们所讲解的仅仅是初步的源码分析,如果有兴趣大家也可以继续深入,把最内层的实现都分析清楚。研究完源码,不妨尝试着自己来封装一个类似的库出来。一步步完善。这就是开源的乐趣。 \ No newline at end of file From b866f30bbf332019426d6c8eb04292ac8e1399f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Tue, 3 Mar 2015 10:50:10 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes http/Android-Async-Http.md | 71 ++++++++++++++++++++++++++----------- http/Ok-Http.md | 61 ++----------------------------- 3 files changed, 54 insertions(+), 78 deletions(-) diff --git a/.DS_Store b/.DS_Store index d73c4813e82c74c1f3ec1e11ea99ff65e363b265..0f9a11e8e353447b41cee2db9e6a8dad7af90a77 100644 GIT binary patch delta 76 zcmV-S0JHyuFoZC$eF6dalYRoKE*E=yF*!FZAT>69EFgO~H!v(9G&47SeGr%k2pcIi iK}}h3eTt%^q@|{(sKUgPR|6jb#j|$^2>uVtNgAL4 delta 77 zcmV-T0J8stFoZC$eF6dblYRoKFBp4!Gc-3WATl;NeJmh*H#aaWAT%>KeSHv=2nZV~ jH9<{TaD9rRqok##r>MillU4&C0mid-1CRu>2MGNS-Rm0D diff --git a/http/Android-Async-Http.md b/http/Android-Async-Http.md index c892d55..01f8c1e 100644 --- a/http/Android-Async-Http.md +++ b/http/Android-Async-Http.md @@ -59,50 +59,81 @@ client.get("http://www.jikexueyuan.com", new AsyncHttpResponseHandler() { }); ``` +在这里。Android-Async-Http提供了许多不同返回类型的回调提供给我们使用 +只需要简单几句代码,我们就可以实现一个基本的http请求。这样的代码量是不是写起来非常的痛快? +除了以上三个基本的回调。Android-Async-Http还提供了许多相关回调方便我们在请求的各个过程做各做处理操作。 +包括有: + +```java +@Override + public void onFinish() { + // TODO Auto-generated method stub + super.onFinish(); + } + + @Override + public void onCancel() { + // TODO Auto-generated method stub + super.onCancel(); + } + + @Override + public void onProgress(int bytesWritten, int totalSize) { + // TODO Auto-generated method stub + super.onProgress(bytesWritten, totalSize); + } + + @Override + public void onRetry(int retryNo) { + // TODO Auto-generated method stub + super.onRetry(retryNo); + } +``` + -只需要简单几句代码,我们就可以实现一个基本的http请求。这样的代码量是不是写起来非常的痛快? ### 实现Post请求方式并传递参数 使用Android-Async-Http来实现Post请求一样很简单,只需要调用post方法,并且用RequestParams来设定参数就可以: ```java -RequestParams params = new RequestParams(); -params.put("key", "value"); -StringRequest mPostRequest=new StringRequest(Method.POST, "http://www.jikexueyuan.com", new Listener() { - +AsyncHttpClient mClient=new AsyncHttpClient(); +RequestParams mParams = new RequestParams(); +mParams.put("username", "admin"); +mParams.put("password", "123456"); +mClient.get("http://www.jikexueyuan.com",mParams,new AsyncHttpResponseHandler() { + @Override - public void onResponse(String response) { + public void onSuccess(int arg0, Header[] arg1, byte[] arg2) { // TODO Auto-generated method stub - Log.e("jikexueyuan", "请求结果:"+response); + } - }, new ErrorListener() { - + @Override - public void onErrorResponse(VolleyError error) { + public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) { // TODO Auto-generated method stub - Log.e("jikexueyuan", "出错啦:"+error.getMessage()); + } - }){ @Override - protected Map getParams() throws AuthFailureError { + public void onStart() { // TODO Auto-generated method stub - Map map=new HashMap(); - map.put("参数名1", "参数值1"); - map.put("参数名2", "参数值2"); - return map; + super.onStart(); } - }; - mQueue.add(mPostRequest); + }); + } ``` ### 实现文件上传,下载 +很多时候,我们经常会需要上传图片或者文件到服务器,或者实现版本更新的时候从服务器下载文件。这时候Android-Async-Http可以很好得帮助我们来实现这些操作。 + +上传文件我们只需要在RequestParams的参数中传入File类型或者InputStream类型的数据。带入到请求中。下载的话只需要使用获取byte[]类型数据的回调就可以。 + ## 总结 -以上就是Android-Async-Http的一些基本使用方法 +以上就是Android-Async-Http的一些基本使用方法,使用它,我们可以很方便的在项目开发当中快速的实现各种各样的网络请求。甚至是上传文件,下载文件都只需要简单的几句代码就可以做到。是不是十分方便呢。 diff --git a/http/Ok-Http.md b/http/Ok-Http.md index e4852b0..ba8f03c 100644 --- a/http/Ok-Http.md +++ b/http/Ok-Http.md @@ -2,11 +2,10 @@ ## Ok-Http简介 -为Android构建的基于异步回调的Http客户端,是基于Apache HttpClient库的。所有的请求都是独立于应用程序主线程 UI 之外,但任何回调逻辑跟在线程上通过Android的handler创建消息传递执行回调是一样的。 -以官网的说法,Twitter的app所使用的就是Android-Async-Http + ###特点 -相对于其他库,Android-Async-Http比较特有的地方就是可以通过RequestParams直接传递文件参数上传文件。这个功能,我个人还是挺喜欢的,在平时做图片和文件上传十分的方便。同时它对文件下载的封装也做得很好。 + 源码托管地址: @@ -37,64 +36,10 @@ http://loopj.com/android-async-http/ 使用Ok-Http十分的简单,只要创建一个AsyncHttpClient对象通过这个对象就可以做我们想做的事情 基本代码实现: -```java -AsyncHttpClient client = new AsyncHttpClient(); -client.get("http://www.jikexueyuan.com", new AsyncHttpResponseHandler() { - - @Override - public void onStart() { - //请求开始回调 - } - - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] response) { - //请求成功回调 - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { - // 请求失败回调 - } - - -}); -``` - -只需要简单几句代码,我们就可以实现一个基本的http请求。这样的代码量是不是写起来非常的痛快? ### 实现Post请求方式并传递参数 -使用Ok-Http来实现Post请求一样很简单,只需要调用post方法,并且用RequestParams来设定参数就可以: - -```java -RequestParams params = new RequestParams(); -params.put("key", "value"); -StringRequest mPostRequest=new StringRequest(Method.POST, "http://www.jikexueyuan.com", new Listener() { - - @Override - public void onResponse(String response) { - // TODO Auto-generated method stub - Log.e("jikexueyuan", "请求结果:"+response); - } - }, new ErrorListener() { - - @Override - public void onErrorResponse(VolleyError error) { - // TODO Auto-generated method stub - Log.e("jikexueyuan", "出错啦:"+error.getMessage()); - } - }){ - @Override - protected Map getParams() throws AuthFailureError { - // TODO Auto-generated method stub - Map map=new HashMap(); - map.put("参数名1", "参数值1"); - map.put("参数名2", "参数值2"); - return map; - } - }; - mQueue.add(mPostRequest); -``` + ### 实现文件上传,下载 From 18d28d273321a4b85501fb12e1d8482fdee4ad8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Tue, 3 Mar 2015 10:51:58 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E7=9B=AE=E5=BD=95=E5=A2=9E=E5=8A=A0volle?= =?UTF-8?q?y=E6=BA=90=E7=A0=81=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 1 + 2 files changed, 1 insertion(+) diff --git a/.DS_Store b/.DS_Store index 0f9a11e8e353447b41cee2db9e6a8dad7af90a77..b52789e3f9d4a8b7ab7c8618953ad85eb7fa8943 100644 GIT binary patch delta 21 ccmZoMXffE3$i&F9If*Hfk&$`x9%c^_07U@>!~g&Q delta 21 ccmZoMXffE3$i&FBIf*Hfk&$up9%c^_07TmbzyJUM diff --git a/README.md b/README.md index bce6c72..2d2f299 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Android开发中,越来越多优秀的开源组件涌现处出来,可以帮 * Http请求组件 * [Volley](http/volley.md) + * [Volley源码解析](http/volley-source.md) * [android-async-http](http/android-async-http.md) * [okhttp](http/okhttp.md) * json数据解析组件 From ad67f85eb2717fb83f3f09a88e4f49042e796a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A7=91=E7=88=B7?= Date: Tue, 1 Sep 2015 21:41:51 +0800 Subject: [PATCH 14/14] Update volley.md --- http/volley.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/http/volley.md b/http/volley.md index c3c99a3..5b2a7a9 100644 --- a/http/volley.md +++ b/http/volley.md @@ -32,8 +32,10 @@ http://developer.android.com/training/volley/index.html 所需权限: -```xml +``` xml + + ``` 我们只需要三部曲就可以实现: @@ -44,7 +46,8 @@ http://developer.android.com/training/volley/index.html 基本代码实现: -```java +``` java + RequestQueue mQueue=Volley.newRequestQueue(this); StringRequest mRequest=new StringRequest( "http://www.jikexueyuan.com", new Listener() { @@ -62,6 +65,7 @@ StringRequest mRequest=new StringRequest( "http://www.jikexueyuan.com", new List } }); mQueue.add(mRequest); + ``` 只需要简单几句代码,我们就可以实现一个基本的http请求。不再需要顾虑线程等复杂问题。