volley网络请求框架,支持java,kotlin发起网络请求
说两句
现在很多人都说volley已经过时了,因为现在主流的就是OKhttp和retrofit以及dragger2了,框架是主流的MVP框架,使用这些网络请求库更优良,这段时间刚好有空,想整理一下,我的理解里,没有过时不过时,没有哪个好,哪个不好,技术是用来解决实际问题的,有诸多的选择的时候,一定有一个最适合当前问题的解决方案,因为每一个工具都有其特点、优势、劣势,那些淘汰掉的是因为有更方便更优良的新生代出来了,我的项目目前使用的是volley网络框架,我先对这个网络框架进行一下总结,对于其他的网络框架还没有很多的研究,不敢多说是非,后续有了比较深入的研究再写个帖子说两句,也欢迎各位朋友指点批评。。。。
介绍&地址
volley是google官方推出的http网络请求库。
话不多说,先来官方资料,贴出官方地址:
- volley的GitHub地址 ,https://github.com/google/volley;
- volley的官方使用介绍地址 https://developer.android.com/training/volley/; (此处需要科学上网才可以访问,你懂得)
volley的特点
volley
最主要的特点是:
体积小、速度快,非常适合小数据量的频繁请求;
当然不适合大型下载或流媒体操作,
然而volley也对于这种它不适合的也给出了解决办法,
使用DownloadManager
替代。
特点
- 自动调度网络请求。
- 多个并发网络连接。
- 具有标准HTTP 缓存一致性的透明磁盘和内存响应缓存 。
- 支持请求优先级。
- 取消请求API。您可以取消单个请求,也可以设置要取消的请求块或范围。
- 易于定制,例如,重试和退避。
- 强大的排序,可以使用从网络异步获取的数据轻松正确填充UI。
- 调试和跟踪工具。
怎么样是不是有的看不懂什么意思?说实话其实我也是,哥们别着急,继续看。
Volley擅长用于填充UI的RPC类型操作,例如将搜索结果页面作为结构化数据获取。
Volley不适合大型下载或流媒体操作,因为Volley在解析期间将所有响应保存在内存中。对于大型下载操作,请考虑使用类似的替代方法DownloadManager
添加volley到项目中
Volley添加到项目的最简单方法是将以下依赖项添加到应用程序的build.gradle文件中:
方式1
dependencies {
...
compile 'com.android.volley:volley:1.1.1'
}
使用
implementation
替换compile
,因为从2018年底开始Google已经要删除这个关键字了,统一使用implementation
。
方式2
1,Git通过在命令行键入以下内容来克隆存储库:
git clone https://github.com/google/volley
2,将下载的源作为Android库模块导入到应用项目中。如何创建android库模块,后续再写一篇帖子说
。
发送简单的请求
可以通过创建RequestQueue
并传递 Request
对象来使用Volley 。在RequestQueue
管理诸多的网络请求子线程(网络请求属于耗时操作,是必须放在子线程的),这个队列负责网络请求子线程的网络请求操作、读取和写入到缓存中,解析响应管理工作线程等内容。Requests
负责解析原始响应,Volley负责将解析后的响应分发回主线程以进行传递。
- 要使用Volley,必须不能忘记将
android.permission.INTERNET
权限添加 到应用的清单中。如果没有这个,应用将无法连接到网络。-
发送一个请求使用Volley.newRequestQueue方法
,向这个方法中传入Request
对象,以发起网络请求,RequestQueue
可以不进行设置,直接使用默认值也可以启动队列;
先说发起一个网络请求的套路,稍后再说这个发起请求必须用到的这个RequestQueue
。
kotlin发起网络请求example
val textView = findViewById<TextView>(R.id.text)
// ...
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(this)
val url = "http://www.google.com"
// Request a string response from the provided URL.
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
// Display the first 500 characters of the response string.
textView.text = "Response is: ${response.substring(0, 500)}"
},
Response.ErrorListener { textView.text = "That didn't work!" })
// Add the request to the RequestQueue.
queue.add(stringRequest)
java发起网络请求example
final TextView mTextView = (TextView) findViewById(R.id.text);
// ...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Volley总是在主线程上提供已解析的响应。在主线程上运行可以方便地使用接收到的数据更新填充UI控件,因为可以直接从handler响应修改UI控件,
发送请求分析
要发送请求,只需构建一个请求并将其添加到RequestQueue使用 add()方法,就可以将这个请求添加进队列。添加请求后,它将在队列的管道中移动,获得服务,解析并传递其原始响应。
当调用add()时,Volley运行一个缓存处理线程和一个网络调度线程池。当向队列添加请求时,它会被缓存线程拾取并进行分类:如果请求可以从缓存中获得服务,则缓存响应将在缓存线程上进行解析,并且解析后的响应将在主线程上传递。如果无法从缓存中为请求提供服务,则将其置于网络队列中。第一个可用的网络线程从队列中获取请求,执行HTTP事务,解析工作线程上的响应,将响应写入缓存,并将解析的响应发送回主线程以进行传递。
注意,I / O阻塞、解析/解码等昂贵的操作是在工作线程上完成的。可以从任何线程添加请求,但响应始终在主线程上传递。
以上是volley发起网络请求的生命周期。
取消网络请求
要取消请求,通过Request对象调用cancel()方法完成。一旦取消,Volley保证永远不会调用当前http请求线程的响应handler。可以在activity的onstop()方法中直接取消所有待处理的请求。而不用做getActivity() == null
或者onSaveInstanceState()
是否已经执行等检查操作后再取消待处理的请求。
要利用此行为,您通常必须跟踪所有正在进行的请求,以便能够在适当的时间取消它们。有一种更简单的方法: 可以将标记对象与每个请求相关联。然后,您可以使用此标记提供取消请求的范围。
例如,您可以将所有请求标记为Activity
代表他们发出的请求,在onStop()
方法中执行requestQueue.cancelAll(this)
表示取消当前activity的所有待处理的请求。
同样,可以在ViewPager选项卡中使用各自的选项卡标记所有缩略图图像请求, 并在滑动时取消已经划过去的选项卡页面的待处理请求,以确保新选项卡不会被另一个选项卡的请求阻止阻塞。
使用标记的字符串值的示例:
1,定义标记并将其添加到您的请求中。
kotlin:
val TAG = "MyTag"
val stringRequest: StringRequest // Assume this exists.
val requestQueue: RequestQueue? // Assume this exists.
// Set the tag on the request.
stringRequest.tag = TAG
// Add the request to the RequestQueue.
requestQueue?.add(stringRequest)
java:
public static final String TAG = "MyTag";
StringRequest stringRequest; // Assume this exists.
RequestQueue mRequestQueue; // Assume this exists.
// Set the tag on the request.
stringRequest.setTag(TAG);
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
2,在活动的onStop()方法中,取消所有具有此标记的请求。
kotlin:
protected fun onStop() {
super.onStop()
requestQueue?.cancelAll(TAG)
}
java:
@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
取消request后,请求的相应handler是不会被执行的,请求直接就被停止了。
设置RequestQueque
上面是直接使用Volley.newRequestQueue
发起一个请求,使用的是默认的RequestQueue
;当然还可以创建一个RequestQueue
通过设置它来提供提强求的自定义行为。
RequestQueue
的创建最好使用单例模式,在APP的运行生命周期中一直保持RequestQueue
对象的存活。
RequestQueue
需要做两件事:一个用于执行request传输的网络请求,一个用于处理缓存线程的缓存。
Volley工具箱中DiskBasedCache
提供了这些标准实现:提供带有内存索引的单文件响应缓存,BasicNetwork
根据您首选的HTTP客户端提供网络传输。
BasicNetwork
是Volley的默认网络实现。BasicNetwork
必须使用HTTP客户端实例化,以便应用程序连接到网络. 通常这个HTTP客户端是一个HttpURLConnection
。
###设置RequestQueque
java:
RequestQueue mRequestQueue;
// Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);
// Start the queue
mRequestQueue.start();
String url ="http://www.example.com";
// Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Do something with the response
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
});
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
// ...
kotlin:
// Instantiate the cache
val cache = DiskBasedCache(cacheDir, 1024 * 1024) // 1MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
val network = BasicNetwork(HurlStack())
// Instantiate the RequestQueue with the cache and network. Start the queue.
val requestQueue = RequestQueue(cache, network).apply {
start()
}
val url = "http://www.example.com"
// Formulate the request and handle the response.
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
// Do something with the response
},
Response.ErrorListener { error ->
// Handle error
textView.text = "ERROR: %s".format(error.toString())
})
// Add the request to the RequestQueue.
requestQueue.add(stringRequest)
// ...
但是通常这个设置不用进行的,使用默认的设置就OK的,除非特殊的需要。
注意:
如果只发起一次网络请求,那么就可以使用上面的发送简单请求的方式,创建RequestQueue
发起请求,当请求response
返回以后或者请求出错以后调用stop()方法。使用Volley.newRequestQueue()
方法可以发起一次简单的网络请求,但是更多的时候是使用単例的方式创建RequestQueue
。
単例模式创建RequestQueue
如果应用程序不断使用网络,那么设置一个単例RequestQueue
对象,保持应用程序生命周期的过程中该对象都存活,这样的话可能效率最高。可以通过各种方式实现这一目标。推荐的方法是实现封装RequestQueue
和其他Volley功能的单例类。另一种方法是子类化Application
并设置 RequestQueue in Application.onCreate()
。但是这种方法是 不鼓励的 ; 静态单例可以以更模块化的方式提供相同的功能。
一个关键概念是RequestQueue
必须使用Application上下文实例化 ,而不是Activity上下文。这可确保在RequestQueue
应用程序的生命周期内持续使用,而不是每次重新创建活动时重新创建(例如,当用户旋转设备时)。
一句话,哥们创建一次RequestQueue
对象之后,整个APP就可以一直使用这个对象不需要重新开页面的时候重新创建一个新对象。
创建単例模式example
kotlin:
class MySingleton constructor(context: Context) {
companion object {
@Volatile
private var INSTANCE: MySingleton? = null
fun getInstance(context: Context) =
INSTANCE ?: synchronized(this) {
INSTANCE ?: MySingleton(context).also {
INSTANCE = it
}
}
}
val imageLoader: ImageLoader by lazy {
ImageLoader(requestQueue,
object : ImageLoader.ImageCache {
private val cache = LruCache<String, Bitmap>(20)
override fun getBitmap(url: String): Bitmap {
return cache.get(url)
}
override fun putBitmap(url: String, bitmap: Bitmap) {
cache.put(url, bitmap)
}
})
}
val requestQueue: RequestQueue by lazy {
// applicationContext is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
Volley.newRequestQueue(context.applicationContext)
}
fun <T> addToRequestQueue(req: Request<T>) {
requestQueue.add(req)
}
}
java:
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
使用単例对象example
kotlin:
// Get a RequestQueue
val queue = MySingleton.getInstance(this.applicationContext).requestQueue
// ...
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest)
java:
// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
// ...
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
发起标准请求
实现自定义请求
、