├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── itheima │ │ └── volleydemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── itheima │ │ │ └── volleydemo │ │ │ ├── GankBean.java │ │ │ ├── GsonRequest.java │ │ │ ├── MainActivity.java │ │ │ ├── MyApplication.java │ │ │ ├── NetworkListener.java │ │ │ └── NetworkManager.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── itheima │ └── volleydemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img └── volley-request.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Volley介绍 # 2 | Volley 是 Goole I/O 2013上发布的网络通信库,使网络通信更快、更简单、更健壮。 3 | 适用于数据不大但通信频繁的场景,不适合大文件下载。 4 | 5 | # Volley功能 # 6 | * Json,图像等异步下载 7 | * 网络请求的优先级处理 8 | * 缓存 9 | * 取消请求 10 | 11 | # Volley工作流程 # 12 | ![icon](img/volley-request.png) 13 | 14 | 1. 线程管理 15 | 2. 缓存的管理 16 | 3. 发送网络请求过程 17 | 1. 在主线程把请求加入请求队列 18 | 2. 缓存线程查询请求是否有缓存,如果有缓存,则从缓存中获取数据解析返回给主线程,如果没有缓存,把请求分发给网络线程 19 | 3. 网络线程发送请求,从服务器获取数据,解析后返回给主线程 20 | 21 | 22 | 23 | # Volley使用 # 24 | * [Github](https://github.com/mcxiaoke/android-volley) 25 | * [基本用法](http://blog.csdn.net/guolin_blog/article/details/17482095) 26 | * [加载图片](http://blog.csdn.net/guolin_blog/article/details/17482165) 27 | * [自定义请求](http://blog.csdn.net/guolin_blog/article/details/17612763) 28 | 29 | ## 1. 添加网络权限 ## 30 | 31 | ## 2. 添加volley依赖 ## 32 | compile 'com.android.volley:volley:1.0.0' 33 | ## 3. 字符串请求 ## 34 | public void onStartStringRequest(View view) { 35 | String url = "http://gank.io/api/data/Android/10/1"; 36 | StringRequest stringRequest = new StringRequest(url, mStringListener, mErrorListener); 37 | Volley.newRequestQueue(this).add(stringRequest); 38 | 39 | } 40 | 41 | private Response.Listener mStringListener = new Response.Listener() { 42 | @Override 43 | public void onResponse(String response) { 44 | Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show(); 45 | } 46 | }; 47 | 48 | private Response.ErrorListener mErrorListener = new Response.ErrorListener() { 49 | @Override 50 | public void onErrorResponse(VolleyError error) { 51 | Toast.makeText(MainActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show(); 52 | } 53 | }; 54 | ## 4. JsonObject请求 ## 55 | public void onStartJsonObjectRequest(View view) { 56 | String url = "http://gank.io/api/data/Android/10/1"; 57 | //Get请求第二个参数传null 58 | //Post请求第二个参数传JsonObject对象 59 | JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, mJSONObjectListener, mErrorListener); 60 | Volley.newRequestQueue(this).add(jsonObjectRequest); 61 | 62 | } 63 | 64 | private Response.Listener mJSONObjectListener = new Response.Listener() { 65 | @Override 66 | public void onResponse(JSONObject response) { 67 | try { 68 | //获取网络响应中results数组中第一个元素的"desc"字段 69 | String desc = response.getJSONArray("results").getJSONObject(0).getString("desc"); 70 | Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show(); 71 | } catch (JSONException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | }; 76 | 77 | ## 5. JsonArray请求 ## 78 | public void onStartJsonArrayRequest(View view) { 79 | String url = "https://api.github.com/users/octocat/repos"; 80 | JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url, mJSONArrayListener, mErrorListener); 81 | Volley.newRequestQueue(this).add(jsonArrayRequest); 82 | } 83 | 84 | private Response.Listener mJSONArrayListener = new Response.Listener() { 85 | 86 | @Override 87 | public void onResponse(JSONArray response) { 88 | try { 89 | //获取数组中第一个元素的"name"字段 90 | String name = response.getJSONObject(0).getString("name"); 91 | Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show(); 92 | } catch (JSONException e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | }; 97 | 98 | 99 | 100 | ## 6. 图片请求 ## 101 | public void onStartImageRequest(View view) { 102 | String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg"; 103 | //第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值, 104 | //则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。 105 | ImageRequest request = new ImageRequest(url, 106 | mBitmapListener, 107 | 0, 108 | 0, 109 | Bitmap.Config.RGB_565, 110 | mErrorListener); 111 | Volley.newRequestQueue(this).add(request); 112 | } 113 | 114 | private Response.Listener mBitmapListener = new Response.Listener() { 115 | @Override 116 | public void onResponse(Bitmap response) { 117 | mImageView.setImageBitmap(response); 118 | } 119 | }; 120 | 121 | # Volley的封装 # 122 | 123 | ## 1. 请求队列的封装 ## 124 | 一个应用只需一个RequestQueue, 不必每次发请求都创建一个请求队列。 125 | 126 | public class NetworkManager { 127 | 128 | private static NetworkManager sNetworkManager; 129 | 130 | private RequestQueue mQueue; 131 | 132 | public static NetworkManager getInstance() { 133 | if (sNetworkManager == null) { 134 | synchronized (NetworkManager.class) { 135 | if (sNetworkManager == null) { 136 | sNetworkManager = new NetworkManager(); 137 | } 138 | } 139 | } 140 | return sNetworkManager; 141 | } 142 | 143 | public void init(Context context) { 144 | mQueue = Volley.newRequestQueue(context); 145 | } 146 | 147 | public void sendRequest(Request request) { 148 | mQueue.add(request); 149 | } 150 | } 151 | 152 | ## 2. 回调的封装 ## 153 | public class NetworkListener implements Response.Listener, Response.ErrorListener{ 154 | @Override 155 | public void onErrorResponse(VolleyError error) { 156 | 157 | } 158 | 159 | @Override 160 | public void onResponse(T response) { 161 | 162 | } 163 | } 164 | 165 | ## 3. 自定义Gson请求 ## 166 | 167 | ### 添加Gson依赖 ### 168 | compile 'com.google.code.gson:gson:2.8.0' 169 | ### 创建Gson请求 ### 170 | 171 | public class GsonRequest extends JsonRequest { 172 | 173 | public GsonRequest(int method, String url, String requestBody, Response.Listener listener, Response.ErrorListener errorListener) { 174 | super(method, url, requestBody, listener, errorListener); 175 | } 176 | } 177 | 178 | ### 将网络请求结果转换成字符串 ### 179 | @Override 180 | protected Response parseNetworkResponse(NetworkResponse response) { 181 | String parsedString; 182 | try { 183 | //将网络响应的字节数组转换成字符串 184 | parsedString = new String(response.data, PROTOCOL_CHARSET); 185 | } catch (UnsupportedEncodingException e) { 186 | } 187 | 188 | } 189 | 190 | ### 将字符串转换成JavaBean ### 191 | //将字符串转换成java bean 192 | T result = mGson.fromJson(parsedString, mClass); 193 | 194 | ### 返回解析后的结果 ### 195 | @Override 196 | protected Response parseNetworkResponse(NetworkResponse response) { 197 | 198 | //返回解析后的结果,使用Response对象包装 199 | return Response.success(result, HttpHeaderParser.parseCacheHeaders(response)); 200 | } 201 | 202 | ### 发送请求 ### 203 | public void onStartGsonRequest(View view) { 204 | String url = "http://gank.io/api/data/Android/10/1"; 205 | GsonRequest request = new GsonRequest(GankBean.class, url, mGankBeanNetworkListener); 206 | NetworkManager.getInstance().sendRequest(request); 207 | } 208 | 209 | 210 | ## 4. ImageLoader的封装 ### 211 | ### NetworkImageView的使用 ### 212 | mNetworkImageView = (NetworkImageView) findViewById(R.id.network_image_view); 213 | mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher); 214 | String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg"; 215 | NetworkImageView.setImageUrl(url, NetworkManager.getInstance().getImageLoader()); 216 | 217 | ### ImageLoader的创建 ### 218 | 219 | 220 | ImageLoader是加载和缓存网络图片的工具。由于它也要用到RequestQueue, 一个应用也只需要一个ImageLoader,所以同样的封装到NetworkManager中。 221 | 222 | public void init(Context context) { 223 | mQueue = Volley.newRequestQueue(context); 224 | mImageLoader = new ImageLoader(mQueue, new ImageLruCache(DEFAULT_IMAGE_CACHE_SIZE)); 225 | } 226 | 227 | #### LRU原理 #### 228 | Least Recent Used。当访问一条数据时,数据会放在表头,当缓存超过最大值时,会删除表尾的数据。 229 | 230 | /** 231 | * 图片内存LRU缓存 232 | */ 233 | private static class ImageLruCache extends LruCache implements ImageLoader.ImageCache{ 234 | 235 | 236 | public ImageLruCache(int maxSize) { 237 | super(maxSize); 238 | } 239 | 240 | /** 241 | * 返回对应key的bitmap的大小,当存入缓存时,要计算是否超出缓存的最大值 242 | */ 243 | @Override 244 | protected int sizeOf(String key, Bitmap value) { 245 | return value.getByteCount(); 246 | } 247 | 248 | /** 249 | * 返回对应url的图片缓存 250 | */ 251 | @Override 252 | public Bitmap getBitmap(String url) { 253 | return get(url); 254 | } 255 | 256 | /** 257 | * 存入缓存 258 | */ 259 | @Override 260 | public void putBitmap(String url, Bitmap bitmap) { 261 | put(url, bitmap); 262 | } 263 | } 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | # Volley的封装层级 # 272 | Volley的封装级别类似Retrofit,[FunHttp](https://github.com/uncleleonfan/FunHttp)。 Retrofit,FunHttp都是对OKhttp的一层封装,解决了数据转换和线程切换等问题。 273 | Volley内部使用HttpClient或者HttpURLConnection完成网络请求,由于Volley的良好扩展性,还可以配置使用Okhttp进行网络请求。 274 | 可以看出HttpClient,HttpURLConnection,Okhttp属于同一层级,Retrofit,Volley,FunHttp属于同一层级。 275 | 276 | 277 | 278 | # Volley的源码分析 # 279 | 280 | ## 不要纠结细节,看主要逻辑和框架 ## 281 | [如何阅读源码](http://www.jianshu.com/p/be86e5678252) 282 | 283 | [源码分析大全](http://www.codekk.com/open-source-project-analysis) 284 | 285 | ## 请求队列的初始化 ## 286 | 1. 磁盘缓存的初始化(DiskBasedCache)mCache 287 | 2. 执行网络请求对象(Network)的创建 mNetwork 288 | 3. 初始化网络请求的线程池mDispatchers = new NetworkDispatcher[threadPoolSize];,默认大小是4. 289 | 4. 创建网络请求响应和错误的分发器mDelivery=new ExecutorDelivery(new Handler(Looper.getMainLooper())) 290 | 291 | ## 请求队列的启动 ## 292 | 1. 创建缓存分发器,启动该线程,执行run方法,run方法里面初始化磁盘缓存(把缓存文件的头读取出来,存入集合) 293 | 294 | mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); 295 | mCacheDispatcher.start(); 296 | 297 | 298 | 2. 创建网络分发器并且启动 299 | 300 | // Create network dispatchers (and corresponding threads) up to the pool size. 301 | for (int i = 0; i < mDispatchers.length; i++) { 302 | NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, 303 | mCache, mDelivery); 304 | mDispatchers[i] = networkDispatcher; 305 | networkDispatcher.start(); 306 | } 307 | 308 | ## 发送请求 ## 309 | 310 | 1. 首先网络请求添加到缓存请求队列mCacheQueue,CacheDispatcher的run方法里面的监控mCacheQueue,如果mCacheQueue有请求,则拿出来,查看是否有缓存,如果有并且没有过期,则解析网络缓存的结果,分发到主线程 311 | 2. 请求加入到网络请求队列mNetworkQueue,NetworkDispatcher的run方法里面监控mNetworkQueue,如果有请求,则拿出来发送网络请求,获取到结果后解析,然后存入缓存,最后分发到主线程。 312 | 313 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.itheima.volleydemo" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.1.0' 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.volley:volley:1.0.0' 30 | compile 'com.google.code.gson:gson:2.8.0' 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\software\AndroidStudio\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/itheima/volleydemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.itheima.volleydemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/GankBean.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import java.util.List; 4 | 5 | public class GankBean { 6 | 7 | /** 8 | * error : false 9 | * results : [{"_id":"59a65dd2421aa901c85e5fe9","createdAt":"2017-08-30T14:40:18.444Z","desc":"Android版ARKit","publishedAt":"2017-09-01T12:55:52.582Z","source":"web","type":"Android","url":"https://github.com/google-ar/arcore-android-sdk","used":true,"who":"JackHang"},{"_id":"59a79050421aa901bcb7dbd6","createdAt":"2017-08-31T12:28:00.485Z","desc":"How to create multiple apk files for android application","publishedAt":"2017-09-01T12:55:52.582Z","source":"web","type":"Android","url":"https://mindorks.com/blog/how-to-create-multiple-apk-files-for-android-application","used":true,"who":"AMIT SHEKHAR"},{"_id":"59a8b60a421aa901c1c0a8c2","createdAt":"2017-09-01T09:21:14.889Z","desc":"英语不好?打造一款AndroidStudio翻译插件","publishedAt":"2017-09-01T12:55:52.582Z","source":"web","type":"Android","url":"https://mp.weixin.qq.com/s?__biz=MzIwMzYwMTk1NA==&mid=2247486724&idx=1&sn=5a66e01a2ecb72dbd97c619718d906ab","used":true,"who":"陈宇明"},{"_id":"59a621eb421aa901bcb7dbcb","createdAt":"2017-08-30T10:24:43.354Z","desc":"一个滑动关闭Activity的组件,可以设置上下左右滑动关闭","images":["http://img.gank.io/d6ce9191-6f9a-4aa5-96cd-b175fb8eef3e"],"publishedAt":"2017-08-31T08:22:07.982Z","source":"web","type":"Android","url":"https://github.com/gongwen/SwipeBackLayout","used":true,"who":"龚文"},{"_id":"59a64ec7421aa901c1c0a8ab","createdAt":"2017-08-30T13:36:07.559Z","desc":"腾讯团队开源的 致力于提高项目 UI 开发效率的解决方案","publishedAt":"2017-08-31T08:22:07.982Z","source":"chrome","type":"Android","url":"http://qmuiteam.com/android/page/index.html","used":true,"who":"代码家"},{"_id":"59a64ef7421aa901c85e5fe7","createdAt":"2017-08-30T13:36:55.542Z","desc":"Glide 图像变换功能库。","publishedAt":"2017-08-31T08:22:07.982Z","source":"chrome","type":"Android","url":"https://github.com/wasabeef/glide-transformations","used":true,"who":"代码家"},{"_id":"59a6beb7421aa901c1c0a8b1","createdAt":"2017-08-30T21:33:43.862Z","desc":"Android WebView 详解","publishedAt":"2017-08-31T08:22:07.982Z","source":"web","type":"Android","url":"http://reezy.me/p/20170515/android-webview/","used":true,"who":"ezy"},{"_id":"59a4ea09421aa901b9dc4652","createdAt":"2017-08-29T12:14:01.783Z","desc":"在任何非 MIUI 设备上体验小米系统级推送。","images":["http://img.gank.io/1c974dca-f68d-4925-826e-863ac8a40d48"],"publishedAt":"2017-08-29T12:19:18.634Z","source":"chrome","type":"Android","url":"https://github.com/Trumeet/MiPushFramework","used":true,"who":"代码家"},{"_id":"59a4ea9d421aa901b9dc4655","createdAt":"2017-08-29T12:16:29.115Z","desc":"Box 效果的 EditText,很漂亮哦。","images":["http://img.gank.io/c55c1de8-ff13-47a9-b624-4b2dac5e91a0"],"publishedAt":"2017-08-29T12:19:18.634Z","source":"chrome","type":"Android","url":"https://github.com/HITGIF/TextFieldBoxes","used":true,"who":"代码家"},{"_id":"599e2d51421aa901c85e5fbd","createdAt":"2017-08-24T09:35:13.750Z","desc":"物联网来了,你还不会蓝牙开发?","publishedAt":"2017-08-24T12:43:10.124Z","source":"web","type":"Android","url":"http://url.cn/5ymK3Ps","used":true,"who":"陈宇明"}] 10 | */ 11 | 12 | private boolean error; 13 | private List results; 14 | 15 | public boolean isError() { 16 | return error; 17 | } 18 | 19 | public void setError(boolean error) { 20 | this.error = error; 21 | } 22 | 23 | public List getResults() { 24 | return results; 25 | } 26 | 27 | public void setResults(List results) { 28 | this.results = results; 29 | } 30 | 31 | public static class ResultsBean { 32 | /** 33 | * _id : 59a65dd2421aa901c85e5fe9 34 | * createdAt : 2017-08-30T14:40:18.444Z 35 | * desc : Android版ARKit 36 | * publishedAt : 2017-09-01T12:55:52.582Z 37 | * source : web 38 | * type : Android 39 | * url : https://github.com/google-ar/arcore-android-sdk 40 | * used : true 41 | * who : JackHang 42 | * images : ["http://img.gank.io/d6ce9191-6f9a-4aa5-96cd-b175fb8eef3e"] 43 | */ 44 | 45 | private String _id; 46 | private String createdAt; 47 | private String desc; 48 | private String publishedAt; 49 | private String source; 50 | private String type; 51 | private String url; 52 | private boolean used; 53 | private String who; 54 | private List images; 55 | 56 | public String get_id() { 57 | return _id; 58 | } 59 | 60 | public void set_id(String _id) { 61 | this._id = _id; 62 | } 63 | 64 | public String getCreatedAt() { 65 | return createdAt; 66 | } 67 | 68 | public void setCreatedAt(String createdAt) { 69 | this.createdAt = createdAt; 70 | } 71 | 72 | public String getDesc() { 73 | return desc; 74 | } 75 | 76 | public void setDesc(String desc) { 77 | this.desc = desc; 78 | } 79 | 80 | public String getPublishedAt() { 81 | return publishedAt; 82 | } 83 | 84 | public void setPublishedAt(String publishedAt) { 85 | this.publishedAt = publishedAt; 86 | } 87 | 88 | public String getSource() { 89 | return source; 90 | } 91 | 92 | public void setSource(String source) { 93 | this.source = source; 94 | } 95 | 96 | public String getType() { 97 | return type; 98 | } 99 | 100 | public void setType(String type) { 101 | this.type = type; 102 | } 103 | 104 | public String getUrl() { 105 | return url; 106 | } 107 | 108 | public void setUrl(String url) { 109 | this.url = url; 110 | } 111 | 112 | public boolean isUsed() { 113 | return used; 114 | } 115 | 116 | public void setUsed(boolean used) { 117 | this.used = used; 118 | } 119 | 120 | public String getWho() { 121 | return who; 122 | } 123 | 124 | public void setWho(String who) { 125 | this.who = who; 126 | } 127 | 128 | public List getImages() { 129 | return images; 130 | } 131 | 132 | public void setImages(List images) { 133 | this.images = images; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/GsonRequest.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import com.android.volley.NetworkResponse; 4 | import com.android.volley.Response; 5 | import com.android.volley.toolbox.HttpHeaderParser; 6 | import com.android.volley.toolbox.JsonRequest; 7 | import com.google.gson.Gson; 8 | 9 | import java.io.UnsupportedEncodingException; 10 | 11 | /** 12 | * Created by Leon on 2017/2/12. 13 | */ 14 | 15 | public class GsonRequest extends JsonRequest { 16 | 17 | private Gson mGson = new Gson(); 18 | 19 | private Class mClass;//要解析的类的类对象 20 | 21 | public GsonRequest(int method, String url, String requestBody, Response.Listener listener, Response.ErrorListener errorListener) { 22 | super(method, url, requestBody, listener, errorListener); 23 | } 24 | 25 | /** 26 | * GET请求 27 | * @param beanClass 网络解析的Java Bean类的Class对象 28 | * @param url 网络地址 29 | * @param listener 成功和失败的回调 30 | */ 31 | public GsonRequest(Class beanClass, String url, NetworkListener listener) { 32 | this(Method.GET, url, null, listener, listener); 33 | mClass = beanClass; 34 | } 35 | 36 | /** 37 | * 将网络请求的结果用Gson解析成期望的类型,在子线程中调用 38 | */ 39 | @Override 40 | protected Response parseNetworkResponse(NetworkResponse response) { 41 | String parsedString; 42 | try { 43 | //将网络响应的字节数组转换成字符串 44 | parsedString = new String(response.data, PROTOCOL_CHARSET); 45 | } catch (UnsupportedEncodingException e) { 46 | parsedString = new String(response.data); 47 | } 48 | //将字符串转换成java bean 49 | T result = mGson.fromJson(parsedString, mClass); 50 | //返回解析后的结果,使用Response对象包装 51 | return Response.success(result, HttpHeaderParser.parseCacheHeaders(response)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.Toast; 9 | 10 | import com.android.volley.Response; 11 | import com.android.volley.VolleyError; 12 | import com.android.volley.toolbox.ImageRequest; 13 | import com.android.volley.toolbox.JsonArrayRequest; 14 | import com.android.volley.toolbox.JsonObjectRequest; 15 | import com.android.volley.toolbox.NetworkImageView; 16 | import com.android.volley.toolbox.StringRequest; 17 | import com.android.volley.toolbox.Volley; 18 | 19 | import org.json.JSONArray; 20 | import org.json.JSONException; 21 | import org.json.JSONObject; 22 | 23 | public class MainActivity extends AppCompatActivity { 24 | 25 | private ImageView mImageView; 26 | 27 | private NetworkImageView mNetworkImageView; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_main); 33 | mImageView = (ImageView) findViewById(R.id.image_view); 34 | 35 | mNetworkImageView = (NetworkImageView) findViewById(R.id.network_image_view); 36 | mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher); 37 | String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg"; 38 | mNetworkImageView.setImageUrl(url, NetworkManager.getInstance().getImageLoader()); 39 | } 40 | 41 | //发送一个StringRequest 42 | public void onStartStringRequest(View view) { 43 | String url = "http://gank.io/api/data/Android/10/1"; 44 | StringRequest stringRequest = new StringRequest(url, mStringListener, mErrorListener); 45 | // Volley.newRequestQueue(this).add(stringRequest); 46 | NetworkManager.getInstance().sendRequest(stringRequest); 47 | } 48 | 49 | private Response.Listener mStringListener = new Response.Listener() { 50 | @Override 51 | public void onResponse(String response) { 52 | Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show(); 53 | } 54 | }; 55 | 56 | private Response.ErrorListener mErrorListener = new Response.ErrorListener() { 57 | @Override 58 | public void onErrorResponse(VolleyError error) { 59 | Toast.makeText(MainActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show(); 60 | } 61 | }; 62 | 63 | //发送一个JsonObjectRequest 64 | public void onStartJsonObjectRequest(View view) { 65 | String url = "http://gank.io/api/data/Android/10/1"; 66 | //Get请求第二个参数传null 67 | //Post请求第二个参数传JsonObject对象 68 | JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, mJSONObjectListener, mErrorListener); 69 | // Volley.newRequestQueue(this).add(jsonObjectRequest); 70 | NetworkManager.getInstance().sendRequest(jsonObjectRequest); 71 | } 72 | 73 | //获取一个json对象 74 | private Response.Listener mJSONObjectListener = new Response.Listener() { 75 | /** 76 | * 77 | * {"picture":["image/home01.jpg","image/home02.jpg","image/home03.jpg","image/home04.jpg","image/home05.jpg","image/home06.jpg","image/home07.jpg","image/home08.jpg"]} 78 | */ 79 | @Override 80 | public void onResponse(JSONObject response) { 81 | try { 82 | //获取网络响应中results数组中第一个元素的"desc"字段 83 | String desc = response.getJSONArray("results").getJSONObject(0).getString("desc"); 84 | Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show(); 85 | } catch (JSONException e) { 86 | e.printStackTrace(); 87 | } 88 | } 89 | }; 90 | 91 | //发送JsonArrayRequest请求获取一个json数组 92 | public void onStartJsonArrayRequest(View view) { 93 | String url = "https://api.github.com/users/octocat/repos"; 94 | JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url, mJSONArrayListener, mErrorListener); 95 | // Volley.newRequestQueue(this).add(jsonArrayRequest); 96 | NetworkManager.getInstance().sendRequest(jsonArrayRequest); 97 | } 98 | 99 | private Response.Listener mJSONArrayListener = new Response.Listener() { 100 | 101 | @Override 102 | public void onResponse(JSONArray response) { 103 | try { 104 | //获取数组中第一个元素的"name"字段 105 | String name = response.getJSONObject(0).getString("name"); 106 | Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show(); 107 | } catch (JSONException e) { 108 | e.printStackTrace(); 109 | } 110 | } 111 | }; 112 | 113 | //使用自定义请求获取网络结果解析成一个Bean对象 114 | public void onStartGsonRequest(View view) { 115 | String url = "http://gank.io/api/data/Android/10/1"; 116 | GsonRequest request = new GsonRequest(GankBean.class, url, mGankBeanNetworkListener); 117 | NetworkManager.getInstance().sendRequest(request); 118 | } 119 | 120 | private NetworkListener mGankBeanNetworkListener = new NetworkListener() { 121 | @Override 122 | public void onResponse(GankBean response) { 123 | //获取网络响应中results数组中第一个元素的"desc"字段 124 | String desc = response.getResults().get(0).getDesc(); 125 | Toast.makeText(MainActivity.this, desc, Toast.LENGTH_SHORT).show(); 126 | } 127 | }; 128 | 129 | 130 | public void onStartImageRequest(View view) { 131 | String url = "https://ws1.sinaimg.cn/large/610dc034ly1fj3w0emfcbj20u011iabm.jpg"; 132 | //第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值, 133 | //则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。 134 | ImageRequest request = new ImageRequest(url, 135 | mBitmapListener, 136 | 0, 137 | 0, 138 | Bitmap.Config.RGB_565, 139 | mErrorListener); 140 | Volley.newRequestQueue(this).add(request); 141 | } 142 | 143 | private Response.Listener mBitmapListener = new Response.Listener() { 144 | @Override 145 | public void onResponse(Bitmap response) { 146 | mImageView.setImageBitmap(response); 147 | } 148 | }; 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Created by Leon on 2017/2/12. 7 | */ 8 | 9 | public class MyApplication extends Application{ 10 | 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | NetworkManager.getInstance().init(getApplicationContext()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/NetworkListener.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import com.android.volley.Response; 4 | import com.android.volley.VolleyError; 5 | 6 | public class NetworkListener implements Response.Listener, Response.ErrorListener{ 7 | @Override 8 | public void onErrorResponse(VolleyError error) { 9 | 10 | } 11 | 12 | @Override 13 | public void onResponse(T response) { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/itheima/volleydemo/NetworkManager.java: -------------------------------------------------------------------------------- 1 | package com.itheima.volleydemo; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.util.LruCache; 6 | 7 | import com.android.volley.Request; 8 | import com.android.volley.RequestQueue; 9 | import com.android.volley.toolbox.ImageLoader; 10 | import com.android.volley.toolbox.Volley; 11 | 12 | /** 13 | * Created by Leon on 2017/2/12. 14 | */ 15 | 16 | public class NetworkManager { 17 | 18 | private static NetworkManager sNetworkManager; 19 | 20 | private RequestQueue mQueue; 21 | 22 | private ImageLoader mImageLoader; 23 | 24 | private static final int DEFAULT_IMAGE_CACHE_SIZE = 4 * 1024 * 1024;//4M 25 | 26 | 27 | public static NetworkManager getInstance() { 28 | if (sNetworkManager == null) { 29 | synchronized (NetworkManager.class) { 30 | if (sNetworkManager == null) { 31 | sNetworkManager = new NetworkManager(); 32 | } 33 | } 34 | } 35 | return sNetworkManager; 36 | } 37 | 38 | public void init(Context context) { 39 | mQueue = Volley.newRequestQueue(context); 40 | mImageLoader = new ImageLoader(mQueue, new ImageLruCache(DEFAULT_IMAGE_CACHE_SIZE)); 41 | } 42 | 43 | public void sendRequest(Request request) { 44 | mQueue.add(request); 45 | } 46 | 47 | public ImageLoader getImageLoader() { 48 | return mImageLoader; 49 | } 50 | 51 | /** 52 | * 图片内存LRU缓存 53 | */ 54 | private static class ImageLruCache extends LruCache implements ImageLoader.ImageCache{ 55 | 56 | //如果没有覆写sizeOf,maxSize表示能够保持的Bitmap的个数, 57 | // 如果覆写了sizeOf, maxSize表示缓存的字节数大写 58 | public ImageLruCache(int maxSize) { 59 | super(maxSize); 60 | } 61 | 62 | /** 63 | * 返回对应key的bitmap的大小,当存入缓存时,要计算是否超出缓存的最大值 64 | */ 65 | @Override 66 | protected int sizeOf(String key, Bitmap value) { 67 | return value.getByteCount(); 68 | } 69 | 70 | /** 71 | * 返回对应url的图片缓存 72 | */ 73 | @Override 74 | public Bitmap getBitmap(String url) { 75 | return get(url); 76 | } 77 | 78 | /** 79 | * 存入缓存 80 | */ 81 | @Override 82 | public void putBitmap(String url, Bitmap bitmap) { 83 | put(url, bitmap); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 |