Android
Voleo
Buscar..
Introducción
Volley es una biblioteca HTTP de Android que fue introducida por Google para hacer que las llamadas de red sean mucho más simples. Por defecto, todas las llamadas de la red de Volley se realizan de forma asíncrona, manejando todo en un hilo de fondo y devolviendo los resultados en primer plano con el uso de devoluciones de llamada. Como la obtención de datos a través de una red es una de las tareas más comunes que se realizan en cualquier aplicación, la biblioteca Volley se creó para facilitar el desarrollo de aplicaciones para Android.
Sintaxis
- RequestQueue queue = Volley.newRequestQueue (contexto); // configurar la cola
- Request request = new SomeKindOfRequestClass (Request.Method, String url, Response.Listener, Response.ErrorListener); // configura algún tipo de solicitud, el tipo exacto y los argumentos cambian para cada tipo de solicitud
- queue.add (solicitud); // agregar la solicitud a la cola; se llamará al oyente de respuesta apropiado una vez que la solicitud haya finalizado (o finalizado por cualquier motivo)
Observaciones
Instalación
Puedes construir Volley desde el código fuente oficial de Google . Por un tiempo, esa fue la única opción. O usando una de las versiones pre-construidas de terceros. Sin embargo, Google finalmente lanzó un paquete oficial de maven en jcenter.
En su archivo build.gradle
nivel de build.gradle
, agregue esto a su lista de dependencias:
dependencies {
...
compile 'com.android.volley:volley:1.0.0'
}
Asegúrese de que el permiso de INTERNET
esté configurado en el manifiesto de su aplicación:
<uses-permission android:name="android.permission.INTERNET"/>
Documentacion oficial
Google no ha proporcionado una documentación muy extensa sobre esta biblioteca, y no la han tocado en años. Pero lo que está disponible se puede encontrar en:
https://developer.android.com/training/volley/index.html
Hay documentación no oficial alojada en GitHub, aunque debería haber una mejor ubicación para alojar esto en el futuro:
StringRequest básico utilizando el método GET
final TextView mTextView = (TextView) findViewById(R.id.text);
...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Cancelar una solicitud
// assume a Request and RequestQueue have already been initialized somewhere above
public static final String TAG = "SomeTag";
// Set the tag on the request.
request.setTag(TAG);
// Add the request to the RequestQueue.
mRequestQueue.add(request);
// To cancel this specific request
request.cancel();
// ... then, in some future life cycle event, for example in onStop()
// To cancel all requests with the specified tag in RequestQueue
mRequestQueue.cancelAll(TAG);
Agregar atributos de tiempo de diseño personalizados a NetworkImageView
Hay varios atributos adicionales que el Volley NetworkImageView
agrega al ImageView
estándar. Sin embargo, estos atributos solo se pueden establecer en código. El siguiente es un ejemplo de cómo hacer una clase de extensión que recogerá los atributos de su archivo de diseño XML y los aplicará a la instancia de NetworkImageView
por usted.
En su directorio ~/res/xml
, agregue un archivo llamado attrx.xml
:
<resources>
<declare-styleable name="MoreNetworkImageView">
<attr name="defaultImageResId" format="reference"/>
<attr name="errorImageResId" format="reference"/>
</declare-styleable>
</resources>
Agrega un nuevo archivo de clase a tu proyecto:
package my.namespace;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import com.android.volley.toolbox.NetworkImageView;
public class MoreNetworkImageView extends NetworkImageView {
public MoreNetworkImageView(@NonNull final Context context) {
super(context);
}
public MoreNetworkImageView(@NonNull final Context context, @NonNull final AttributeSet attrs) {
this(context, attrs, 0);
}
public MoreNetworkImageView(@NonNull final Context context, @NonNull final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MoreNetworkImageView, defStyle, 0);
// load defaultImageResId from XML
int defaultImageResId = attributes.getResourceId(R.styleable.MoreNetworkImageView_defaultImageResId, 0);
if (defaultImageResId > 0) {
setDefaultImageResId(defaultImageResId);
}
// load errorImageResId from XML
int errorImageResId = attributes.getResourceId(R.styleable.MoreNetworkImageView_errorImageResId, 0);
if (errorImageResId > 0) {
setErrorImageResId(errorImageResId);
}
}
}
Un archivo de diseño de ejemplo que muestra el uso de los atributos personalizados:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
<my.namespace.MoreNetworkImageView
android:layout_width="64dp"
android:layout_height="64dp"
app:errorImageResId="@drawable/error_img"
app:defaultImageResId="@drawable/default_img"
tools:defaultImageResId="@drawable/editor_only_default_img"/>
<!--
Note: The "tools:" prefix does NOT work for custom attributes in Android Studio 2.1 and
older at least, so in this example the defaultImageResId would show "default_img" in the
editor, not the "editor_only_default_img" drawable even though it should if it was
supported as an editor-only override correctly like standard Android properties.
-->
</android.support.v7.widget.CardView>
Solicita JSON
final TextView mTxtDisplay = (TextView) findViewById(R.id.txtDisplay);
ImageView mImageView;
String url = "http://ip.jsontest.com/";
final JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
mTxtDisplay.setText("Response: " + response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// ...
}
});
requestQueue.add(jsObjRequest);
Agregar encabezados personalizados a sus solicitudes [por ejemplo, para autenticación básica]
Si necesita agregar encabezados personalizados a sus solicitudes de volea, no puede hacer esto después de la inicialización, ya que los encabezados se guardan en una variable privada.
En su lugar, debe anular el método getHeaders()
de Request.class
como tal:
new JsonObjectRequest(REQUEST_METHOD, REQUEST_URL, REQUEST_BODY, RESP_LISTENER, ERR_LISTENER) {
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> customHeaders = new Hashmap<>();
customHeaders.put("KEY_0", "VALUE_0");
...
customHeaders.put("KEY_N", "VALUE_N");
return customHeaders;
}
};
Explicación de los parámetros:
-
REQUEST_METHOD
: cualquiera de las constantesRequest.Method.*
. -
REQUEST_URL
: la URL completa para enviar su solicitud. -
REQUEST_BODY
: un objetoJSONObject
contiene el cuerpo POST que se enviará (o nulo). -
RESP_LISTENER
: un objetoResponse.Listener<?>
, CuyoonResponse(T data)
cuando se completa con éxito. -
ERR_LISTENER
: un objetoResponse.ErrorListener
, cuyoonErrorResponse(VolleyError e)
se llama a una solicitud fallida.
Si desea crear una solicitud personalizada, también puede agregar los encabezados en ella:
public class MyCustomRequest extends Request {
...
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> customHeaders = new Hashmap<>();
customHeaders.put("KEY_0", "VALUE_0");
...
customHeaders.put("KEY_N", "VALUE_N");
return customHeaders;
}
...
}
Clase de ayuda para manejar los errores de volea
public class VolleyErrorHelper {
/**
* Returns appropriate message which is to be displayed to the user
* against the specified error object.
*
* @param error
* @param context
* @return
*/
public static String getMessage (Object error , Context context){
if(error instanceof TimeoutError){
return context.getResources().getString(R.string.timeout);
}else if (isServerProblem(error)){
return handleServerError(error ,context);
}else if(isNetworkProblem(error)){
return context.getResources().getString(R.string.nointernet);
}
return context.getResources().getString(R.string.generic_error);
}
private static String handleServerError(Object error, Context context) {
VolleyError er = (VolleyError)error;
NetworkResponse response = er.networkResponse;
if(response != null){
switch (response.statusCode){
case 404:
case 422:
case 401:
try {
// server might return error like this { "error": "Some error occured" }
// Use "Gson" to parse the result
HashMap<String, String> result = new Gson().fromJson(new String(response.data),
new TypeToken<Map<String, String>>() {
}.getType());
if (result != null && result.containsKey("error")) {
return result.get("error");
}
} catch (Exception e) {
e.printStackTrace();
}
// invalid request
return ((VolleyError) error).getMessage();
default:
return context.getResources().getString(R.string.timeout);
}
}
return context.getResources().getString(R.string.generic_error);
}
private static boolean isServerProblem(Object error) {
return (error instanceof ServerError || error instanceof AuthFailureError);
}
private static boolean isNetworkProblem (Object error){
return (error instanceof NetworkError || error instanceof NoConnectionError);
}
Autenticación del servidor remoto usando StringRequest a través del método POST
Por el bien de este ejemplo, supongamos que tenemos un servidor para manejar las solicitudes POST que haremos desde nuestra aplicación de Android:
// User input data.
String email = "[email protected]";
String password = "123";
// Our server URL for handling POST requests.
String URL = "http://my.server.com/login.php";
// When we create a StringRequest (or a JSONRequest) for sending
// data with Volley, we specify the Request Method as POST, and
// the URL that will be receiving our data.
StringRequest stringRequest =
new StringRequest(Request.Method.POST, URL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// At this point, Volley has sent the data to your URL
// and has a response back from it. I'm going to assume
// that the server sends an "OK" string.
if (response.equals("OK")) {
// Do login stuff.
} else {
// So the server didn't return an "OK" response.
// Depending on what you did to handle errors on your
// server, you can decide what action to take here.
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// This is when errors related to Volley happen.
// It's up to you what to do if that should happen, but
// it's usually not a good idea to be too clear as to
// what happened here to your users.
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
// Here is where we tell Volley what it should send in
// our POST request. For this example, we want to send
// both the email and the password.
// We will need key ids for our data, so our server can know
// what is what.
String key_email = "email";
String key_password = "password";
Map<String, String> map = new HashMap<String, String>();
// map.put(key, value);
map.put(key_email, email);
map.put(key_password, password);
return map;
}
};
// This is a policy that we need to specify to tell Volley, what
// to do if it gets a timeout, how many times to retry, etc.
stringRequest.setRetryPolicy(new RetryPolicy() {
@Override
public int getCurrentTimeout() {
// Here goes the timeout.
// The number is in milliseconds, 5000 is usually enough,
// but you can up or low that number to fit your needs.
return 50000;
}
@Override
public int getCurrentRetryCount() {
// The maximum number of attempts.
// Again, the number can be anything you need.
return 50000;
}
@Override
public void retry(VolleyError error) throws VolleyError {
// Here you could check if the retry count has gotten
// to the maximum number, and if so, send a VolleyError
// message or similar. For the sake of the example, I'll
// show a Toast.
Toast.makeText(getContext(), error.toString(), Toast.LENGTH_LONG).show();
}
});
// And finally, we create a Volley Queue. For this example, I'm using
// getContext(), because I was working with a Fragment. But context could
// be "this", "getContext()", etc.
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
requestQueue.add(stringRequest);
} else {
// If, for example, the user inputs an email that is not currently
// on your remote DB, here's where we can inform the user.
Toast.makeText(getContext(), "Wrong email", Toast.LENGTH_LONG).show();
}
Usando Volley para peticiones HTTP
Agregue la dependencia de Gradle en build.gradle a nivel de aplicación
compile 'com.android.volley:volley:1.0.0'
Además, agregue el permiso android.permission.INTERNET al manifiesto de su aplicación.
** Crear instancia de Volley RequestQueue singleton en su aplicación **
public class InitApplication extends Application {
private RequestQueue queue;
private static InitApplication sInstance;
private static final String TAG = InitApplication.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
Stetho.initializeWithDefaults(this);
}
public static synchronized InitApplication getInstance() {
return sInstance;
}
public <T> void addToQueue(Request<T> req, String tag) {
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getQueue().add(req);
}
public <T> void addToQueue(Request<T> req) {
req.setTag(TAG);
getQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (queue != null) {
queue.cancelAll(tag);
}
}
public RequestQueue getQueue() {
if (queue == null) {
queue = Volley.newRequestQueue(getApplicationContext());
return queue;
}
return queue;
}
}
Ahora, puede usar la instancia de volley usando el método getInstance () y agregar una nueva solicitud en la cola usando InitApplication.getInstance().addToQueue(request);
Un ejemplo simple para solicitar JsonObject desde el servidor es
JsonObjectRequest myRequest = new JsonObjectRequest(Method.GET,
url, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Error: " + error.getMessage());
}
});
myRequest.setRetryPolicy(new DefaultRetryPolicy(
MY_SOCKET_TIMEOUT_MS,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
Para manejar los tiempos de espera de Volley, debes usar una RetryPolicy
. Se usa una política de reintento en caso de que una solicitud no pueda completarse debido a una falla de la red o en otros casos.
Volley proporciona una manera fácil de implementar su RetryPolicy
para sus solicitudes. De forma predeterminada, Volley establece todos los tiempos de espera de conexión y socket en 5 segundos para todas las solicitudes. RetryPolicy
es una interfaz en la que necesita implementar su lógica de cómo desea reintentar una solicitud en particular cuando se produce un tiempo de espera.
El constructor toma los siguientes tres parámetros:
-
initialTimeoutMs
: especifica el tiempo de espera del socket en milisegundos para cada intento de reintento. -
maxNumRetries
: el número de veces que se intenta reintentar. -
backoffMultiplier
: un multiplicador que se utiliza para determinar el tiempo exponencial establecido en socket para cada intento de reintento.
Respuesta variable booleana del servidor con solicitud json en volea
puedes personalizar la clase debajo de una
private final String PROTOCOL_CONTENT_TYPE = String.format("application/json; charset=%s", PROTOCOL_CHARSET);
public BooleanRequest(int method, String url, String requestBody, Response.Listener<Boolean> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mRequestBody = requestBody;
}
@Override
protected Response<Boolean> parseNetworkResponse(NetworkResponse response) {
Boolean parsed;
try {
parsed = Boolean.valueOf(new String(response.data, HttpHeaderParser.parseCharset(response.headers)));
} catch (UnsupportedEncodingException e) {
parsed = Boolean.valueOf(new String(response.data));
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
@Override
protected void deliverResponse(Boolean response) {
mListener.onResponse(response);
}
@Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
@Override
public String getBodyContentType() {
return PROTOCOL_CONTENT_TYPE;
}
@Override
public byte[] getBody() throws AuthFailureError {
try {
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
}
usa esto con tu actividad
try {
JSONObject jsonBody;
jsonBody = new JSONObject();
jsonBody.put("Title", "Android Demo");
jsonBody.put("Author", "BNK");
jsonBody.put("Date", "2015/08/28");
String requestBody = jsonBody.toString();
BooleanRequest booleanRequest = new BooleanRequest(0, url, requestBody, new Response.Listener<Boolean>() {
@Override
public void onResponse(Boolean response) {
Toast.makeText(mContext, String.valueOf(response), Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, error.toString(), Toast.LENGTH_SHORT).show();
}
});
// Add the request to the RequestQueue.
queue.add(booleanRequest);
} catch (JSONException e) {
e.printStackTrace();
}
Usa JSONArray como cuerpo de solicitud
Las solicitudes predeterminadas integradas en volley no permiten pasar un JSONArray
como cuerpo de solicitud en una solicitud POST
. En su lugar, solo puede pasar un objeto JSON
como parámetro.
Sin embargo, en lugar de pasar un JSON
objeto como un parámetro para la solicitud constructor, es necesario anular el getBody()
método de la Request.class
. Debes pasar null
como tercer parámetro también:
JSONArray requestBody = new JSONArray();
new JsonObjectRequest(Request.Method.POST, REQUEST_URL, null, RESP_LISTENER, ERR_LISTENER) {
@Override
public byte[] getBody() {
try {
return requestBody.toString().getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
// error handling
return null;
}
}
};
Explicación de los parámetros:
-
REQUEST_URL
: la URL completa para enviar su solicitud. -
RESP_LISTENER
: un objetoResponse.Listener<?>
, CuyoonResponse(T data)
cuando se completa con éxito. -
ERR_LISTENER
: un objetoResponse.ErrorListener
, cuyoonErrorResponse(VolleyError e)
se llama a una solicitud fallida.