Una Introducción a Loopj
() translation by (you can also view the original English article)
Loopj es una librería para Android que permite realizar peticiones HTTP de manera asíncrona. Me gusta por su sencillez y facilidad de uso. Creada por James Smith, también es conocida como "Android Asynchronous HTTP Client", y es usada por compañías como Instagram, Pinterest, y muchas otras. Es un buen primer paso en el mundo de las librerías HTTP, y te permitirá comprender conceptos importantes de manera sencilla.
Para aprender a usar esta librería, vamos a crear Movie Trivia, una sencilla app que se conectará a un servicio web para obtener información acerca de películas o series de TV y mostrará esa información al usuario.
1. Configuración
Para comenzar, crea un nuevo proyecto de Android Studio, con una activity vacía. Para añadir Loopj, copia la dependencia desde el sitio web oficial. La encontrarás en la sección "Installation and basic usage" (o simplemente copia la línea siguiente).
1 |
compile 'com.loopj.android:android-async-http:1.4.9' |
Aparecerá el mensaje "Sync Now" en la esquina superior derecha. Haz click en él para que Gradle descargue la librería y la incluya en tu proyecto.
Puesto que la app se conectará a internet, debemos declarar el permiso correspondiente para que el usuario lo autorice. Abre el archivo AndroidManifest.xml
y, justo antes de la etiqueta application
, escribe:
1 |
<uses-permission android:name="android.permission.INTERNET"/> |
Ya puedes empezar a usar Loopj en tu app.
2. Implementación
Vamos a crear la interfaz gráfica mas sencilla posible: tan sólo un TextField
para insertar las palabras a buscar, un Button
para iniciar la búsqueda y un TextView
para mostrar los resultados. Abre activity_mail.xml
y añade los componentes de la interfaz gráfica como se muestra a continuación.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
xmlns:tools="http://schemas.android.com/tools" |
4 |
android:layout_width="match_parent" |
5 |
android:layout_height="match_parent" |
6 |
android:orientation="vertical" |
7 |
android:padding="@dimen/activity_vertical_margin" |
8 |
tools:context="com.pdrogfer.movietrivia.MainActivity"> |
9 |
|
10 |
<LinearLayout
|
11 |
android:layout_width="match_parent" |
12 |
android:layout_height="wrap_content" |
13 |
android:orientation="horizontal"> |
14 |
|
15 |
<EditText
|
16 |
android:id="@+id/etSearchTerms" |
17 |
android:layout_width="0dp" |
18 |
android:layout_weight="3" |
19 |
android:layout_height="wrap_content" |
20 |
android:hint="movie or tv show" /> |
21 |
|
22 |
<Button
|
23 |
android:id="@+id/btnSearch" |
24 |
android:layout_width="0dp" |
25 |
android:layout_weight="1" |
26 |
android:layout_height="wrap_content" |
27 |
android:text="Search" /> |
28 |
|
29 |
</LinearLayout>
|
30 |
|
31 |
<TextView
|
32 |
android:id="@+id/tvSearchResults" |
33 |
android:layout_width="match_parent" |
34 |
android:layout_height="wrap_content" |
35 |
android:layout_marginTop="24dp" |
36 |
android:hint="search results"/> |
37 |
</LinearLayout>
|
Ahora, como siempre, enlaza estos componentes en tu MainActivity.java
.
1 |
public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
2 |
|
3 |
EditText etSearchTerms; |
4 |
Button btnSearch; |
5 |
TextView tvSearchResults; |
6 |
|
7 |
@Override
|
8 |
protected void onCreate(Bundle savedInstanceState) { |
9 |
super.onCreate(savedInstanceState); |
10 |
setContentView(R.layout.activity_main); |
11 |
|
12 |
etSearchTerms = (EditText) findViewById(R.id.etSearchTerms); |
13 |
btnSearch = (Button) findViewById(R.id.btnSearch); |
14 |
tvSearchResults = (TextView) findViewById(R.id.tvSearchResults); |
15 |
|
16 |
btnSearch.setOnClickListener(this); |
17 |
}
|
18 |
|
19 |
@Override
|
20 |
public void onClick(View v) { |
21 |
String searchTerm = etSearchTerms.getText().toString(); |
22 |
etSearchTerms.setText(""); |
23 |
// make Loopj HTTP call
|
24 |
}
|
25 |
}
|
Para mantener el código limpio y organizado, crea una clase java en su propio archivo, MyLoopjTask.java
, donde escribiremos todo el código y operaciones relacionados con Loopj. Necesitarás dos variables de instancia, una de tipo RequestParams
para integrar los detalles de la busqueda en la URL, y otra de tipo AsyncHttpClient
para hacer la petición HTTP en sí. Antes de seguir, comprueba que Android Studio ha añadido los imports necesarios.
1 |
import org.json.JSONObject; |
2 |
import cz.msebera.android.httpclient.Header; |
Crea también un método que tome el término de búsqueda introducido por el usuario como argumento—aqui es donde realmente se realizará el trabajo.
1 |
public class MyLoopjTask { |
2 |
|
3 |
private static final String TAG = "MOVIE_TRIVIA"; |
4 |
|
5 |
AsyncHttpClient asyncHttpClient; |
6 |
RequestParams requestParams; |
7 |
|
8 |
String BASE_URL = "http://www.omdbapi.com/?"; |
9 |
String jsonResponse; |
10 |
|
11 |
public MyLoopjTask() { |
12 |
asyncHttpClient = new AsyncHttpClient(); |
13 |
requestParams = new RequestParams(); |
14 |
}
|
15 |
|
16 |
public void executeLoopjCall(String queryTerm) { |
17 |
requestParams.put("s", queryTerm); |
18 |
asyncHttpClient.get(BASE_URL, requestParams, new JsonHttpResponseHandler() { |
19 |
@Override
|
20 |
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { |
21 |
super.onSuccess(statusCode, headers, response); |
22 |
jsonResponse = response.toString(); |
23 |
Log.i(TAG, "onSuccess: " + jsonResponse); |
24 |
}
|
25 |
|
26 |
@Override
|
27 |
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) { |
28 |
super.onFailure(statusCode, headers, throwable, errorResponse); |
29 |
Log.e(TAG, "onFailure: " + errorResponse); |
30 |
}
|
31 |
});
|
32 |
}
|
33 |
}
|
Como puedes ver, puedes añadir todos los parámetros de búsqueda que la API requiera con la instancia de RequestParams
(en este caso, basta con el término introducido por el usuario). Esta versión del método get()
devuelve un objeto JSON en onSuccess
, pero hay otras variantes disponibles para ajustarlo a tus necesidades. (Usa Ctrl+O) para ver las variantes de este método.)
Esto es todo lo que necesitas para implementar un cliente Loopj y hacer peticiones HTTP a un servicio web. En nuestro case, queremos enviar nuestra petición cuando el usuario pulse el botón "Search". Para ello, en MainActivity
, crea una instancia de MyLoopjTask
y dentro de onClick
llama a executeLoopjCall
con el término introducido por el usuario. MainActivity
quedará como sigue.
1 |
public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
2 |
|
3 |
EditText etSearchTerms; |
4 |
Button btnSearch; |
5 |
TextView tvSearchResults; |
6 |
MyLoopjTask myLoopjTask; |
7 |
|
8 |
@Override
|
9 |
protected void onCreate(Bundle savedInstanceState) { |
10 |
super.onCreate(savedInstanceState); |
11 |
setContentView(R.layout.activity_main); |
12 |
|
13 |
etSearchTerms = (EditText) findViewById(R.id.etSearchTerms); |
14 |
btnSearch = (Button) findViewById(R.id.btnSearch); |
15 |
tvSearchResults = (TextView) findViewById(R.id.tvSearchResults); |
16 |
|
17 |
btnSearch.setOnClickListener(this); |
18 |
|
19 |
myLoopjTask = new MyLoopjTask(); |
20 |
}
|
21 |
|
22 |
@Override
|
23 |
public void onClick(View v) { |
24 |
String searchTerm = etSearchTerms.getText().toString(); |
25 |
etSearchTerms.setText(""); |
26 |
// make loopj http call
|
27 |
myLoopjTask.executeLoopjCall(searchTerm); |
28 |
}
|
29 |
}
|
Ahora, si lanzas la app, deberías ver los resultados de la petición en la ventana de logs.
3. Publicar los Resultados en la UI
Separar las operaciones asíncronas en clases propias ayuda a mantaner nuestro código limpio, pero provoca que no tengamos acceso directo a los elementos de la UI (interfaz gráfica). Para mostrar los resultados de estas peticiones, recomiendo crear una interfaz listener. Esta es una estrategia muy usada, como puedes ver en este hilo de Stack Overflow. Tiene tres sencillos pasos.
Crear una Interfaz
Primer, crea una interfaz con un único método que será llamado cuando se obtengan los resultados de la petición HTTP realizada con Loopj.
1 |
public interface OnLoopjCompleted { |
2 |
public void taskCompleted(String results); |
3 |
}
|
Actualiza el Asynchronous Task Handler
En MyLoopjTask
, modifica el constructor para que acepte un Context
y una instancia de OnLoopjCompleted
como parámetros.
1 |
public MyLoopjTask(Context context, OnLoopjCompleted listener) { |
2 |
asyncHttpClient = new AsyncHttpClient(); |
3 |
requestParams = new RequestParams(); |
4 |
this.context = context; |
5 |
this.loopjListener = listener; |
6 |
}
|
Ahora, cuando los resultados de la petición están disponibles en MyLoopjTask
, pásalos al método del listener de la interfaz.
1 |
@Override
|
2 |
public void onSuccess(int statusCode, Header[] headers, JSONObject response) { |
3 |
super.onSuccess(statusCode, headers, response); |
4 |
jsonResponse = response.toString(); |
5 |
loopjListener.taskCompleted(jsonResponse); |
6 |
Log.i(TAG, "onSuccess: " + jsonResponse); |
7 |
}
|
Actualiza la Activity
Finalmente, haz que la activity que quieres actualizar--en este caso MainActivity
--implemente OnLoopjCompleted
. Cambia la inicialización de myLoopjTask
a myLoopjTask = new MyLoopjTask(this, this);
.
Puesto que tu activity ahora implementa OnLoopjCompleted
, Android Studio te obligará a implementar el método taskCompleted
. En él, puedes actualizar la UI con los nuevos datos.
1 |
@Override
|
2 |
public void taskCompleted(String results) { |
3 |
tvSearchResults.setText(results); |
4 |
}
|
4. Conclusión
Ya lo tienes. Cuando ejecutes la app, todos los datos obtenidos por la petición HTTP asíncrona se mostrarán al usuario. Naturalmente, deberás parsear el JSON recibido para extraer sólo las partes que necesites. Por ejemplo, podrías mostrar el póster de la película pasando la URL del mismo a Picasso.
En este tutorial, has visto como usar Loopj, una libreria para realizar peticiones HTTP asíncronas en Android. Loopj es sencillo de usar con sólo unas pocas líneas de código. Ahora ya no tienes ninguna excusa para no mantener tu app actualizada con contenido de tu servicion web favorito!