Android Volley教程

本文是一篇关于Android Volley的实战教程,介绍了如何在应用中实现Volley库,包括GET、POST请求,使用Gson解析响应,展示在RecyclerView中。同时讲解了如何创建SingletonRequestQueue,加载网络图片以及自定义请求GsonRequest。
摘要由CSDN通过智能技术生成

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">

    <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:

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

  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.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.

自定义请求需要覆盖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;

    @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 tutorial app

运行中的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值