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 StringRequest
和JsonObjectRequests
。 我们将使用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">
<Button
android: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" />
<Button
android: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.NetworkImageView
android: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" />
<ImageView
android: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" />
<Button
android: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" />
<Button
android: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" />
<Button
android: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;
@Override
protected 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);
}
@Override
public 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() {
@Override
public 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>() {
@Override
public 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) {
@Override
public Priority getPriority() {
return Priority.LOW;
}
};
queue.add(stringRequest);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {
@Override
public 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) {
@Override
public String getBodyContentType() {
return "application/json";
}
@Override
public Priority getPriority() {
return Priority.IMMEDIATE;
}
};
queue.add(jsonObjectRequest);
queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {
@Override
public 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:
上面代码中要注意的重点:
- We’ve created an instance of ErrorListener that’ll be used throughout the Activity. 我们创建了一个ErrorListener实例,该实例将在整个Activity中使用。
- We’ve chained two requests in the RequestQueue. 我们在RequestQueue中链接了两个请求。
- 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的优先级设置为低。 因此,此请求应最终完成(在服务器快速响应的情况下,优先级将不起作用)。 - 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应该首先完成。
- We join the Lists returned from both the requests in
mUserDataList
ArrayList. 我们在mUserDataList
ArrayList中加入了两个请求返回的列表。 - Inside the
addRequestFinishedListener
callback listener, we check if both the requests are over(by checking thenumberOfRequestsCompleted
counter. 在addRequestFinishedListener
回调侦听器内部,我们检查两个请求是否都已结束(通过检查numberOfRequestsCompleted
计数器。 - Besides, inside
addRequestFinishedListener
callback, we can retrieve the response from theCache.Entry
此外,在addRequestFinishedListener
回调内部,我们可以从Cache.Entry
检索响应。 - Try setting
setShouldCache()
to false on the Requests and you find the response in the cache. 尝试在RequestssetShouldCache()
设置为false,然后在缓存中找到响应。 - 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.RecyclerView
android: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;
@Override
protected 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.CardView
android:layout_width="match_parent"
android:layout_height="60dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/imgNetwork"
android:layout_width="48dp"
android:layout_centerVertical="true"
android:layout_height="48dp" />
<TextView
android: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);
}
});
}
@Override
public 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;
}
@Override
public 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);
}
@Override
public 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() {
@Override
public void onResponse(String response) {
VolleyLog.wtf(response, "utf-8");
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public Priority getPriority() {
return Priority.LOW;
}
@Override
public Map getParams() {
Map params = new HashMap();
params.put("name", "Anupam");
params.put("job", "Android Developer");
return params;
}
@Override
public 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() {
@Override
public void onResponse(JSONObject response) {
VolleyLog.wtf(response.toString(), "utf-8");
Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public int getMethod() {
return Method.POST;
}
@Override
public Priority getPriority() {
return Priority.NORMAL;
}
};
StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener() {
@Override
public void onResponse(String response) {
VolleyLog.wtf(response);
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public Priority getPriority() {
return Priority.HIGH;
}
@Override
public Map getHeaders() throws AuthFailureError {
HashMap headers = new HashMap();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
@Override
public 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>() {
@Override
public 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() {
@Override
public 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;
}
@Override
public Map getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
@Override
protected Map getParams() throws AuthFailureError {
return params != null ? params : super.getParams();
}
@Override
protected void deliverResponse(T response) {
if(null != listener){
listener.onResponse(response);
}
}
@Override
protected 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.
自定义请求需要覆盖parseNetworkResponse
和deliverResponse
这两种方法。
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;
@Override
protected 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);
}
@Override
public 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>() {
@Override
public 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) {
@Override
public Priority getPriority() {
return Priority.LOW;
}
};
queue.add(stringRequest);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(uri_page_two, null, new Response.Listener<JSONObject>() {
@Override
public 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) {
@Override
public String getBodyContentType() {
return "application/json";
}
@Override
public Priority getPriority() {
return Priority.IMMEDIATE;
}
};
queue.add(jsonObjectRequest);
queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() {
@Override
public 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>() {
@Override
public void onResponse(String response) {
VolleyLog.wtf(response);
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public Priority getPriority() {
return Priority.LOW;
}
@Override
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("name", "Anupam");
params.put("job", "Android Developer");
return params;
}
@Override
public 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>() {
@Override
public void onResponse(JSONObject response) {
VolleyLog.wtf(response.toString());
Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public int getMethod() {
return Method.POST;
}
@Override
public Priority getPriority() {
return Priority.NORMAL;
}
};
StringRequest stringRequestPOSTJSON = new StringRequest(Request.Method.POST, uri, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
VolleyLog.wtf(response);
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
}
}, errorListener) {
@Override
public Priority getPriority() {
return Priority.HIGH;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
@Override
public 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>() {
@Override
public 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() {
@Override
public 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>() {
@Override
public 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 。
翻译自: https://www.journaldev.com/17198/android-volley-tutorial