In this android volley tutorial, we’ll be implementing the Volley library in our application. If you aren’t aware of the features of Volley, we recommend you to read this article before proceeding ahead.

在此android volley教程中,我们将在应用程序中实现Volley库。 如果你不知道的抽射功能,我们建议您阅读此继续前进之前的文章。

Android Volley (Android Volley)

Network Requests in a Volley are added to a RequestQueue. Instead of creating a new instance of RequestQueue every time, we follow the singleton pattern by creating a single instance of RequestQueue throughout our application.

将Volley中的网络请求添加到RequestQueue 。 并非每次都创建一个RequestQueue的新实例,而是通过在整个应用程序中创建单个RequestQueue的实例来遵循单例模式 。

In the application below, we’ll be implementing GET and POST StringRequest and JsonObjectRequests. We’ll use Gson library to parse the response and display the results in a RecyclerView.

在下面的应用程序中,我们将实现GET和POST StringRequestJsonObjectRequests 。 我们将使用Gson库解析响应并将结果显示在RecyclerView中。

Furthermore, we’ll implement a CustomRequest and load images from a URL in the ImageView.

此外,我们将实现CustomRequest并从ImageView中的URL加载图像。

Android Volley教程项目结构 (Android Volley Tutorial Project Structure)

Android Volley Gradle依赖关系 (Android Volley Gradle Dependencies)

Before we get onto the coding aspect of this tutorial, add the following dependencies in your build.gradle file.

在开始学习本教程的编码之前,请在build.gradle文件中添加以下依赖build.gradle

compile 'com.android.support:cardview-v7:26.1.0'compile 'com.android.support:recyclerview-v7:26.1.0'compile 'com.android.support:design:26.1.0'compile 'com.google.code.gson:gson:2.8.0'compile 'com.android.volley:volley:1.0.0'

Android Volley示例代码 (Android Volley Example Code)

Layout – activity_main.xml
The code for the activity_main.xml layout that holds the UI for the MainActivity.java is given below.

布局– activity_main.xml
下面给出了activity_main.xml布局的代码,该布局保存MainActivity.java的UI。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"xmlns:tools="https://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.journaldev.volley.RecyclerViewActivity"><Buttonandroid:id="@+id/btnImageLoader"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/networkImageView"android:layout_alignStart="@+id/networkImageView"android:layout_below="@+id/networkImageView"android:layout_marginTop="16dp"android:text="LOAD IMAGE" /><Buttonandroid:id="@+id/btnImageRequest"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBaseline="@+id/btnImageLoader"android:layout_alignBottom="@+id/btnImageLoader"android:layout_marginLeft="8dp"android:layout_marginStart="8dp"android:layout_marginTop="16dp"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_toEndOf="@+id/imageView"android:layout_toRightOf="@+id/imageView"android:text="IMAGE REQUEST" /><com.android.volley.toolbox.NetworkImageViewandroid:id="@+id/networkImageView"android:layout_width="100dp"android:layout_height="100dp"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:layout_below="@+id/imageView"android:layout_marginEnd="16dp"android:layout_marginRight="16dp"android:layout_marginTop="8dp" /><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:layout_marginTop="8dp" /><Buttonandroid:id="@+id/btnGET"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignEnd="@+id/btnPOST"android:layout_alignLeft="@+id/btnPOST"android:layout_alignRight="@+id/btnPOST"android:layout_alignStart="@+id/btnPOST"android:layout_centerVertical="true"android:text="GET String JSON" /><Buttonandroid:id="@+id/btnPOST"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/btnGET"android:layout_centerHorizontal="true"android:layout_marginTop="8dp"android:text="POST String JSON" /><Buttonandroid:id="@+id/btnCustomRequest"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignEnd="@+id/btnPOST"android:layout_alignLeft="@+id/btnPOST"android:layout_alignRight="@+id/btnPOST"android:layout_alignStart="@+id/btnPOST"android:layout_below="@+id/btnPOST"android:layout_marginTop="8dp"android:text="CUSTOM REQUEST" /></RelativeLayout>

SingletonRequestQueue.java

SingletonRequestQueue.java

package com.journaldev.volley;import android.content.Context;import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;public class SingletonRequestQueue {private static SingletonRequestQueue mInstance;private Context mContext;private RequestQueue mRequestQueue;private SingletonRequestQueue(Context context) {mContext = context;mRequestQueue = getRequestQueue();}public static synchronized SingletonRequestQueue getInstance(Context context) {if (mInstance == null) {mInstance = new SingletonRequestQueue(context);}return mInstance;}public RequestQueue getRequestQueue() {if (mRequestQueue == null) {mRequestQueue = Volley.newRequestQueue(mContext);}return mRequestQueue;}
}

getInstance() and getRequestQueue() methods create an instance of SingletonRequestQueue and RequestQueue respectively for the first time and re-use it everywhere.

getInstance()getRequestQueue()方法分别首次创建SingletonRequestQueue和RequestQueue的实例,并在各处重复使用。

Linking the layout to the MainActivity.java

将布局链接到MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {Button btnGET, btnPOST, btnImageLoader, btnCustomRequest, btnImageRequest;NetworkImageView networkImageView;ImageView imageView;ArrayList<UserList.UserDataList> mUserDataList = new ArrayList<>();String BASE_URL = "https://reqres.in";String IMAGE_URL = "https://www.android.com/static/2016/img/share/oreo-lg.jpg";int numberOfRequestsCompleted;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnGET = findViewById(R.id.btnGET);btnPOST = findViewById(R.id.btnPOST);btnImageLoader = findViewById(R.id.btnImageLoader);btnImageRequest = findViewById(R.id.btnImageRequest);btnCustomRequest = findViewById(R.id.btnCustomRequest);networkImageView = findViewById(R.id.networkImageView);imageView = findViewById(R.id.imageView);btnGET.setOnClickListener(this);btnPOST.setOnClickListener(this);btnImageLoader.setOnClickListener(this);btnCustomRequest.setOnClickListener(this);btnImageRequest.setOnClickListener(this);networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);networkImageView.setErrorImageResId(R.drawable.ic_error);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btnGET:GETStringAndJSONRequest("2", "4");break;case R.id.btnPOST:POSTStringAndJSONRequest();case R.id.btnImageLoader:imageLoader();case R.id.btnImageRequest:imageRequest();case R.id.btnCustomRequest:customRequest();break;}}
}

There are 5 buttons for GET, POST, ImageLoader, ImageRequest, CustomRequest processing. Each of the features are triggered in the onClickListener separately.

有5个按钮用于GET,POST,ImageLoader,ImageRequest,CustomRequest处理。 每个功能都分别在onClickListener中触发。

We’ll look at each of the methods separately

我们将分别研究每种方法

  • GETStringAndJSONRequest()GETStringAndJSONRequest()
  • POSTStringAndJSONRequest()POSTStringAndJSONRequest()
  • imageLoader()imageLoader()
  • imageRequest()imageRequest()
  • customRequest()customRequest()

We’ll be using the REST API available at www.reqres.in.

我们将使用www.reqres.in上的REST API。

The UserList.java class is the POJO class for serialising the response using Gson.

UserList.java类是用于使用Gson序列化响应的POJO类。

UserList.java

UserList.java

package com.journaldev.volley;import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;public class UserList implements Serializable {@SerializedName("page")public Integer page;@SerializedName("per_page")public Integer perPage;@SerializedName("total")public Integer total;@SerializedName("total_pages")public Integer totalPages;@SerializedName("data")public List<UserDataList> userDataList;public class UserDataList implements Serializable {@SerializedName("id")public Integer id;@SerializedName("first_name")public String first_name;@SerializedName("last_name")public String last_name;@SerializedName("avatar")public String avatar;}
}

The above class implements Serializable since an instance of it would passed as Bundle in Intents

上面的类实现了Serializable因为它的一个实例将作为Intent中的Bundle传递

Let’s look at the methods triggered by the Button click in the MainActivity.java that encapsulate a Volley Request.

让我们看看封装了Volley Request的MainActivity.java中由Button单击触发的方法。

GETStringAndJSONRequest()

GETStringAndJSONRequest()

Response.ErrorListener errorListener = new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {if (error instanceof NetworkError) {Toast.makeText(getApplicationContext(), "No network available", Toast.LENGTH_LONG).show();} else {Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();}}};private void GETStringAndJSONRequest(String page_1, String page_2) {mUserDataList.clear();numberOfRequestsCompleted = 0;VolleyLog.DEBUG = true;RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();String uri_page_one = String.format(BASE_URL + "/api/users?page=%1$s", page_1);final String uri_page_two = String.format(BASE_URL + "/api/users?page=%1$s", page_2);StringRequest stringRequest = new StringRequest(Request.Method.GET, uri_page_one, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response, "utf-8");GsonBuilder builder = new GsonBuilder();Gson mGson = builder.create();UserList userList = mGson.fromJson(response, UserList.class);mUserDataList.addAll(userList.userDataList);++numberOfRequestsCompleted;}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.LOW;}};queue.add(stringRequest);JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {@Overridepublic void onResponse(JSONObject response) {VolleyLog.wtf(response.toString(), "utf-8");GsonBuilder builder = new GsonBuilder();Gson mGson = builder.create();UserList userList = mGson.fromJson(response.toString(), UserList.class);mUserDataList.addAll(userList.userDataList);++numberOfRequestsCompleted;}}, errorListener) {@Overridepublic String getBodyContentType() {return "application/json";}@Overridepublic Priority getPriority() {return Priority.IMMEDIATE;}};queue.add(jsonObjectRequest);queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {@Overridepublic void onRequestFinished(Request<Object> request) {try {if (request.getCacheEntry() != null) {String cacheValue = new String(request.getCacheEntry().data, "UTF-8");VolleyLog.d(request.getCacheKey() + " " + cacheValue);}} catch (UnsupportedEncodingException e) {e.printStackTrace();}if (numberOfRequestsCompleted == 2) {numberOfRequestsCompleted = 0;startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));}}});}

Important points to note in the above code:

上面代码中要注意的重点:

  1. We’ve created an instance of ErrorListener that’ll be used throughout the Activity.我们创建了一个ErrorListener实例,该实例将在整个Activity中使用。
  2. We’ve chained two requests in the RequestQueue.我们在RequestQueue中链接了两个请求。
  3. The first Request is a StringRequest. page acts as a URL encoded parameter in the API /api/users?. The response is a JSONObject that’s serialized with Gson. We’ve set the priority of the StringRequest to low. Thus, this request should finish at last(in cases when the response from the server is quick, the priority won’t work).第一个请求是StringRequest。 page充当API /api/users?中的URL编码参数/api/users? 。 响应是使用Gson序列化的JSONObject。 我们已经将StringRequest的优先级设置为低。 因此,此请求应最终完成(在服务器快速响应的情况下,优先级将不起作用)。
  4. The second Request is a JsonObjectRequest. Since it is a GET request, we’ve set the request body as null(check the second parameter). Priority is set to Immediate. Thus the JsonObjectRequest should complete first.第二个请求是一个JsonObjectRequest。 由于这是一个GET请求,因此我们将请求正文设置为null(检查第二个参数)。 优先级设置为立即。 因此,JsonObjectRequest应该首先完成。
  5. We join the Lists returned from both the requests in mUserDataList ArrayList.我们在mUserDataList ArrayList中加入了两个请求返回的列表。
  6. Inside the addRequestFinishedListener callback listener, we check if both the requests are over(by checking the numberOfRequestsCompleted counter.在addRequestFinishedListener回调侦听器内部,我们检查两个请求是否都已结束(通过检查numberOfRequestsCompleted计数器。
  7. Besides, inside addRequestFinishedListener callback, we can retrieve the response from the Cache.Entry此外,在addRequestFinishedListener回调内部,我们可以从Cache.Entry检索响应。
  8. Try setting setShouldCache() to false on the Requests and you find the response in the cache.尝试在Requests setShouldCache()设置为false,然后在缓存中找到响应。
  9. Finally the user data list retrieved from both the requests is passed to the RecyclerViewActivity.java. This is where we’ll populate the ArrayList in a RecyclerView.最后,将从这两个请求中检索到的用户数据列表传递到RecyclerViewActivity.java 。 这是我们在RecyclerView中填充ArrayList的地方。

Let’s look at the RecyclerViewActivity and layout code.

让我们看一下RecyclerViewActivity和布局代码。

Layout – activity_recyclerview.xml

布局– activity_recyclerview.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"xmlns:tools="https://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.journaldev.volley.RecyclerViewActivity"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent" /></android.support.constraint.ConstraintLayout>

RecyclerViewActivity.java

RecyclerViewActivity.java

package com.journaldev.volley;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;public class RecyclerViewActivity extends AppCompatActivity {RecyclerView recyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_recyclerview);recyclerView = findViewById(R.id.recyclerView);recyclerView.setHasFixedSize(true);LinearLayoutManager layoutManager = new LinearLayoutManager(this);recyclerView.setLayoutManager(layoutManager);recyclerView.setItemAnimator(new DefaultItemAnimator());recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));ArrayList userDataLists = (ArrayList) getIntent().getSerializableExtra("users");RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, userDataLists);recyclerView.setAdapter(adapter);}
}

The layout for each RecyclerView row is defined in recyclerview_row.xml.

每个RecyclerView行的布局在recyclerview_row.xml中定义。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.CardViewandroid:layout_width="match_parent"android:layout_height="60dp"><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="match_parent"><com.android.volley.toolbox.NetworkImageViewandroid:id="@+id/imgNetwork"android:layout_width="48dp"android:layout_centerVertical="true"android:layout_height="48dp" /><TextViewandroid:id="@+id/txtLabel"android:layout_toRightOf="@+id/imgNetwork"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_gravity="center"android:gravity="center" /></RelativeLayout></android.support.v7.widget.CardView></RelativeLayout>

RecyclerViewAdapter.java

RecyclerViewAdapter.java

package com.journaldev.volley;import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;
import java.util.List;public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.CustomRecyclerView> {private List<UserList.UserDataList> itemList;private RequestQueue mRequestQueue;private ImageLoader mImageLoader;public RecyclerViewAdapter(Context context, List<UserList.UserDataList> itemList) {this.itemList = itemList;mRequestQueue = SingletonRequestQueue.getInstance(context).getRequestQueue();mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {private final LruCache<String, Bitmap> mCache = new LruCache<>(10);public void putBitmap(String url, Bitmap bitmap) {mCache.put(url, bitmap);}public Bitmap getBitmap(String url) {return mCache.get(url);}});}@Overridepublic CustomRecyclerView onCreateViewHolder(ViewGroup parent, int viewType) {View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_row, null);CustomRecyclerView rcv = new CustomRecyclerView(layoutView);return rcv;}@Overridepublic void onBindViewHolder(CustomRecyclerView holder, int position) {UserList.UserDataList myData = itemList.get(position);holder.txtLabel.setText(myData.first_name + " " + myData.last_name);holder.avatar.setImageUrl(myData.avatar, mImageLoader);}@Overridepublic int getItemCount() {return this.itemList.size();}public class CustomRecyclerView extends RecyclerView.ViewHolder {TextView txtLabel;NetworkImageView avatar;CustomRecyclerView(View itemView) {super(itemView);txtLabel = itemView.findViewById(R.id.txtLabel);avatar = itemView.findViewById(R.id.imgNetwork);}}
}

We’ve initialized an ImageLoader that’ll display the Image from the URL in the NetworkImageView for each row.
The LRU cache is used for caching the image by implementing an ImageCache. The argument inside the LruCache constructor is the number of cache entries limit.

我们已经初始化了一个ImageLoader,它将显示NetworkImageView中每行的URL中的图像。
LRU缓存用于通过实现ImageCache来缓存图像。 LruCache构造函数内部的参数是缓存条目数限制。

POSTStringAndJSONRequest()
This method would chain multiple POST requests in a RequestQueue.

POSTStringAndJSONRequest()
此方法将在RequestQueue中链接多个POST请求。

private void POSTStringAndJSONRequest() {RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();VolleyLog.DEBUG = true;String uri = BASE_URL + "/api/users";StringRequest stringRequest = new StringRequest(Request.Method.POST, uri, new Response.Listener() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response, "utf-8");Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.LOW;}@Overridepublic Map getParams() {Map params = new HashMap();params.put("name", "Anupam");params.put("job", "Android Developer");return params;}@Overridepublic Map getHeaders() throws AuthFailureError {HashMap headers = new HashMap();headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");return headers;}};JSONObject jsonObject = new JSONObject();try {jsonObject.put("name", "JournalDev.com");jsonObject.put("job", "To teach you the best");} catch (JSONException e) {e.printStackTrace();}JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri, jsonObject, new Response.Listener() {@Overridepublic void onResponse(JSONObject response) {VolleyLog.wtf(response.toString(), "utf-8");Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic int getMethod() {return Method.POST;}@Overridepublic Priority getPriority() {return Priority.NORMAL;}};StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response);Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.HIGH;}@Overridepublic Map getHeaders() throws AuthFailureError {HashMap headers = new HashMap();headers.put("Content-Type", "application/json; charset=utf-8");return headers;}@Overridepublic byte[] getBody() throws AuthFailureError {JSONObject jsonObject = new JSONObject();try {jsonObject.put("name", "Android Tutorials");jsonObject.put("job", "To implement Volley in an Android Application.");} catch (JSONException e) {e.printStackTrace();}String requestBody = jsonObject.toString();try {return requestBody == null ? null : requestBody.getBytes("utf-8");} catch (UnsupportedEncodingException uee) {VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8");return null;}}};queue.add(stringRequest);queue.add(jsonObjectRequest);queue.add(stringRequestPOSTJSON);}
  • stringRequest – To POST parameters in a StringRequest, we need to override getParams() and pass the parameters as a key value pair.stringRequest –要在StringRequest中发布参数,我们需要重写getParams()并将这些参数作为键值对传递。
  • jsonObjectRequest – To POST parameters in a JsonObjectRequest we pass the parameters inside a JSONObject and set them in the second parameter of the constructor.jsonObjectRequest –要在JsonObjectRequest中发布参数,我们将参数传递到JSONObject内,然后在构造函数的第二个参数中进行设置。
  • stringRequestPOSTJSON – To POST a JSON request body in a StringRequest, we override the method getBody().stringRequestPOSTJSON –要在StringRequest中发布JSON请求正文,我们重写方法getBody()

imageLoader()

imageLoader()

private void imageLoader() {RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {private final LruCache mCache = new LruCache(10);public void putBitmap(String url, Bitmap bitmap) {mCache.put(url, bitmap);}public Bitmap getBitmap(String url) {return mCache.get(url);}});networkImageView.setImageUrl(IMAGE_URL, imageLoader);imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(networkImageView, R.mipmap.ic_launcher, R.drawable.ic_error));}

getImageListener() handles the functionality of showing a default image until the network response is received, at which point it will switch to either the actual image or the error image.
The arguments passed inside the listener are the view’s instance, default image drawable, error image drawable.

getImageListener()处理显示默认图像的功能,直到收到网络响应为止,这时它将切换到实际图像或错误图像。
在侦听器内部传递的参数是视图的实例,默认图像可绘制,错误图像可绘制。

imageRequest()

imageRequest()

private void imageRequest() {RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();ImageRequest imageRequest = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() {@Overridepublic void onResponse(Bitmap response) {if (response != null) {imageView.setImageBitmap(response);}}}, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, errorListener);mRequestQueue.add(imageRequest);}

customRequest()

customRequest()

private void customRequest() {mUserDataList.clear();RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");HashMap headers = new HashMap();headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");GsonRequest gsonRequest = new GsonRequest(url, UserList.class, headers, new Response.Listener() {@Overridepublic void onResponse(UserList response) {mUserDataList.addAll(response.userDataList);startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));}}, errorListener);mRequestQueue.add(gsonRequest);}

We’ve created a CustomRequest named GsonRequest that serializes and converts the response into the POJO class internally. Also, the CustomRequest takes the headers as a constructor argument too.

我们创建了一个名为GsonRequest的CustomRequest,它在内部将响应序列化并将其转换为POJO类。 另外,CustomRequest也将标头用作构造函数参数。

Let’s see how the GsonRequest.java class is written.

让我们看看如何编写GsonRequest.java类。

GsonRequest.java

GsonRequest.java

package com.journaldev.volley;import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;import java.io.UnsupportedEncodingException;
import java.util.Map;public class GsonRequest extends Request {private final Gson gson = new Gson();private final Class myClass;private final Map headers;private final Map params;private final Response.Listener listener;public GsonRequest(String url, Class myClass, Map headers,Response.Listener listener, Response.ErrorListener errorListener) {super(Method.GET, url, errorListener);this.myClass = myClass;this.headers = headers;this.params = null;this.listener = listener;}public GsonRequest(int type, String url, Class myClass, Map headers,Map params,Response.Listener listener, Response.ErrorListener errorListener) {super(type, url, errorListener);this.myClass = myClass;this.headers = headers;this.params = params;this.listener = listener;}@Overridepublic Map getHeaders() throws AuthFailureError {return headers != null ? headers : super.getHeaders();}@Overrideprotected Map getParams() throws AuthFailureError {return params != null ? params : super.getParams();}@Overrideprotected void deliverResponse(T response) {if(null != listener){listener.onResponse(response);}}@Overrideprotected Response parseNetworkResponse(NetworkResponse response) {try {String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));return Response.success(gson.fromJson(json, myClass), HttpHeaderParser.parseCacheHeaders(response));} catch (UnsupportedEncodingException e) {return Response.error(new ParseError(e));} catch (JsonSyntaxException e) {return Response.error(new ParseError(e));}}
}

A Custom Request requires the two methods, parseNetworkResponse and deliverResponse to be overridden.

自定义请求需要覆盖parseNetworkResponsedeliverResponse这两种方法。

The parseNetworkResponse parses the raw network response. In the above code, Gson library serializes it into a POJO class. The result is available in the deliverResponse method.

parseNetworkResponse解析原始网络响应。 在上面的代码中,Gson库将其序列化为POJO类。 结果可在deliverResponse方法中使用。

In the deliverResponse method, we’ve triggered a callback to the Response.Listener’s onResponse method.

deliverResponse方法中,我们触发了对Response.Listener的onResponse方法的回调。

Hasn’t the above GsonRequest Custom Request simplified and generalized the code for storing a response in a POJO class.

上面的GsonRequest自定义请求没有简化并泛化用于在POJO类中存储响应的代码。

The full source code for the MainActivity.java class is given below.

下面提供了MainActivity.java类的完整源代码。

package com.journaldev.volley;import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.LruCache;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;import com.android.volley.AuthFailureError;
import com.android.volley.NetworkError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;import org.json.JSONException;
import org.json.JSONObject;import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;public class MainActivity extends AppCompatActivity implements View.OnClickListener {Button btnGET, btnPOST, btnImageLoader, btnCustomRequest, btnImageRequest;NetworkImageView networkImageView;ImageView imageView;ArrayList<UserList.UserDataList> mUserDataList = new ArrayList<>();String BASE_URL = "https://reqres.in";String IMAGE_URL = "https://www.android.com/static/2016/img/share/oreo-lg.jpg";int numberOfRequestsCompleted;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnGET = findViewById(R.id.btnGET);btnPOST = findViewById(R.id.btnPOST);btnImageLoader = findViewById(R.id.btnImageLoader);btnImageRequest = findViewById(R.id.btnImageRequest);btnCustomRequest = findViewById(R.id.btnCustomRequest);networkImageView = findViewById(R.id.networkImageView);imageView = findViewById(R.id.imageView);btnGET.setOnClickListener(this);btnPOST.setOnClickListener(this);btnImageLoader.setOnClickListener(this);btnCustomRequest.setOnClickListener(this);btnImageRequest.setOnClickListener(this);networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);networkImageView.setErrorImageResId(R.drawable.ic_error);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btnGET:GETStringAndJSONRequest("2", "4");break;case R.id.btnPOST:POSTStringAndJSONRequest();break;case R.id.btnImageLoader:imageLoader();break;case R.id.btnImageRequest:imageRequest();break;case R.id.btnCustomRequest:customRequest();break;}}private void GETStringAndJSONRequest(String page_1, String page_2) {mUserDataList.clear();numberOfRequestsCompleted = 0;VolleyLog.DEBUG = true;RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();String uri_page_one = String.format(BASE_URL + "/api/users?page=%1$s", page_1);final String uri_page_two = String.format(BASE_URL + "/api/users?page=%1$s", page_2);StringRequest stringRequest = new StringRequest(Request.Method.GET, uri_page_one, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response, "utf-8");GsonBuilder builder = new GsonBuilder();Gson mGson = builder.create();UserList userList = mGson.fromJson(response, UserList.class);mUserDataList.addAll(userList.userDataList);++numberOfRequestsCompleted;}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.LOW;}};queue.add(stringRequest);JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {@Overridepublic void onResponse(JSONObject response) {VolleyLog.wtf(response.toString(), "utf-8");GsonBuilder builder = new GsonBuilder();Gson mGson = builder.create();UserList userList = mGson.fromJson(response.toString(), UserList.class);mUserDataList.addAll(userList.userDataList);++numberOfRequestsCompleted;}}, errorListener) {@Overridepublic String getBodyContentType() {return "application/json";}@Overridepublic Priority getPriority() {return Priority.IMMEDIATE;}};queue.add(jsonObjectRequest);queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {@Overridepublic void onRequestFinished(Request<Object> request) {try {if (request.getCacheEntry() != null) {String cacheValue = new String(request.getCacheEntry().data, "UTF-8");Log.d("API123", request.getCacheKey() + " " + cacheValue);}} catch (UnsupportedEncodingException e) {e.printStackTrace();}if (numberOfRequestsCompleted == 2) {numberOfRequestsCompleted = 0;startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));}}});}private void POSTStringAndJSONRequest() {RequestQueue queue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();VolleyLog.DEBUG = true;String uri = BASE_URL + "/api/users";StringRequest stringRequest = new StringRequest(Request.Method.POST, uri, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response);Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.LOW;}@Overridepublic Map<String, String> getParams() {Map<String, String> params = new HashMap<>();params.put("name", "Anupam");params.put("job", "Android Developer");return params;}@Overridepublic Map<String, String> getHeaders() throws AuthFailureError {HashMap<String, String> headers = new HashMap<>();headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");return headers;}};JSONObject jsonObject = new JSONObject();try {jsonObject.put("name", "JournalDev.com");jsonObject.put("job", "To teach you the best");} catch (JSONException e) {e.printStackTrace();}JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri, jsonObject, new Response.Listener<JSONObject>() {@Overridepublic void onResponse(JSONObject response) {VolleyLog.wtf(response.toString());Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic int getMethod() {return Method.POST;}@Overridepublic Priority getPriority() {return Priority.NORMAL;}};StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {VolleyLog.wtf(response);Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();}}, errorListener) {@Overridepublic Priority getPriority() {return Priority.HIGH;}@Overridepublic Map<String, String> getHeaders() throws AuthFailureError {HashMap<String, String> headers = new HashMap<>();headers.put("Content-Type", "application/json; charset=utf-8");return headers;}@Overridepublic byte[] getBody() throws AuthFailureError {JSONObject jsonObject = new JSONObject();try {jsonObject.put("name", "Android Tutorials");jsonObject.put("job", "To implement Volley in an Android Application.");} catch (JSONException e) {e.printStackTrace();}String requestBody = jsonObject.toString();try {return requestBody == null ? null : requestBody.getBytes("utf-8");} catch (UnsupportedEncodingException uee) {VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8");return null;}}};queue.add(stringRequest);queue.add(jsonObjectRequest);queue.add(stringRequestPOSTJSON);}private void imageLoader() {RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();ImageLoader imageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {private final LruCache<String, Bitmap> mCache = new LruCache<>(10);public void putBitmap(String url, Bitmap bitmap) {mCache.put(url, bitmap);}public Bitmap getBitmap(String url) {return mCache.get(url);}});networkImageView.setImageUrl(IMAGE_URL, imageLoader);imageLoader.get(IMAGE_URL, ImageLoader.getImageListener(networkImageView, R.mipmap.ic_launcher, R.drawable.ic_error));}private void imageRequest() {RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();ImageRequest imageRequest = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() {@Overridepublic void onResponse(Bitmap response) {if (response != null) {imageView.setImageBitmap(response);}}}, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, errorListener);mRequestQueue.add(imageRequest);}Response.ErrorListener errorListener = new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {if (error instanceof NetworkError) {Toast.makeText(getApplicationContext(), "No network available", Toast.LENGTH_LONG).show();} else {Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();}}};private void customRequest() {mUserDataList.clear();RequestQueue mRequestQueue = SingletonRequestQueue.getInstance(getApplicationContext()).getRequestQueue();String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");HashMap<String, String> headers = new HashMap<>();headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");GsonRequest<UserList> gsonRequest = new GsonRequest<>(url, UserList.class, headers, new Response.Listener<UserList>() {@Overridepublic void onResponse(UserList response) {mUserDataList.addAll(response.userDataList);startActivity(new Intent(MainActivity.this, RecyclerViewActivity.class).putExtra("users", mUserDataList));}}, errorListener);mRequestQueue.add(gsonRequest);}}

运行中的Android Volley教程应用程序 (Android Volley Tutorial App in Action)

The output of the android volley example application in action is given below.

运行中的android volley示例应用程序的输出如下。

下载Android Volley教程项目 (Download Android Volley Tutorial Project)

This brings an end to android volley tutorial. You can download the Android Volley Project from the link below.

这就结束了android volley教程。 您可以从下面的链接下载Android Volley Project

Download Android Volley Project下载Android Volley Project

翻译自: https://www.journaldev.com/17198/android-volley-tutorial

Android Volley教程相关推荐

  1. Android Volley

    In this tutorial, we'll be discussing at length, an important networking library in our application, ...

  2. Android Volley 库通过网络获取 JSON 数据

    本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 环境 演示 Volley 库通过网络获取 JSON 数据 参考资料 Android 关于网络操作一般都会介绍 HttpC ...

  3. 做了一个系列的Android开发教程列表

    做了一个系列的Android开发教程列表.花了半天多的专题 里面包含了 4个系列的教程. 也包含了很多Android开发资料. 喜欢的人可以收藏哦:http://dev.apkbus.com/

  4. 【Android开发教程】一、基础概念

    Android操作系统 Android是一个基于Linux.使用java作为程序接口的操作系统.他提供了一些工具,比如编译器.调试器.还有他自己的仿真器(DVM - Dalvik Virtual Ma ...

  5. Android Volley入门到精通:初识Volley的基本用法

    1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...

  6. 关于android基础教程一书的初步解读后发现的一些问题

    我是一个比较固执的人..在进行android基础教程一书的初步学习之后,说实话,这本书虽然说为了照顾有需要的童鞋,提供了所有的源代码,就连我也在亲自打了好久的代码之后最后决定放弃,也偷偷懒,进行简单无 ...

  7. Android Volley彻底解决(三),定制自己Request

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17612763 经过前面两篇文章的学习,我们已经掌握了Volley各种Request ...

  8. Android Volley完全解析3:定制自己的Request

    原文链接:http://blog.csdn.net/guolin_blog/article/details/17612763,CSDN 郭霖 经过前面两篇文章的学习,我们已经掌握了Volley各种Re ...

  9. Android Volley完全解析2:使用Volley加载网络图片

    原文链接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖 在上一篇文章中,我们了解了Volley到底是什么,以及它的 ...

最新文章

  1. dataset的去重计数 g2_去互联网公司面试,面试官问我SpringCloud,附答案
  2. CentOS 查看系统版本号
  3. PMCAFF产品经理社区原创专栏,产品圈的干货看这儿就够了
  4. linux 设置mysql 数据库编码utf8
  5. 中英文对照 —— 经济、金融学、财务
  6. 惊现“鬼影”!iPhone 11系列夜景拍照频频翻车
  7. 创新工场面试题——输出螺旋矩阵
  8. 海康VisionMaster绘制图形到显示窗口
  9. 带你动手编程的强化学习著作,每行代码都是它的温柔!
  10. 自己动手美化博客园个人博客
  11. Android应用开发进阶
  12. 2021HW参考|防守方经验总结
  13. qq飞车手游微信24区服务器,QQ飞车手游手游开服表_QQ飞车手游手游开服时间表_新服新区预告_第一手游网...
  14. React 360 全景VR交互项目实战
  15. “海潮效应”侵袭厨电市场,品牌突围时不我待
  16. 有关Nodejs的视频教程
  17. Blazor Day in China来喽,还不来赶紧报名参与
  18. 利用反正切函数展开计算∏的近似值
  19. 要学的东西太多了怎么办
  20. 大数据是什么,大数据的特点主要有哪些,应该怎么运用?

热门文章

  1. 解题报告:LeetCode Basic Calculator(简单计算器)
  2. Yii 自定义模型路径
  3. 提供我现用的Vs配色(灰黑色调)下载,有兴趣的朋友玩玩。
  4. [转载] python语言中表示赋值的符号是_Python 语言中 asterisk 符号用法小结
  5. vue项目实现详情页后退缓存之前的数据
  6. MyDAL - is null is not null 条件 使用
  7. cxVerticalGrid赋值是实时更新
  8. JavaScript错误和异常
  9. 解决filezilla中无法显示中文的文件名
  10. python--之Python内存监控模块memory_profiler测试