Programación y Desarrollo para Android Subforo exclusivo para temas de programación de software para PDAs y desarrollo de aplicaciones, interfaces, etc bajo Android

Respuesta
 
Herramientas
  #1  
Viejo 28/01/17, 18:41:35
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

Pasar variable ArrayList<String> a doInBackground

Quiero pasar la variable pidList del tipo ArrayList<String> a doInBackground de una clase que extiende de AsyncTask llamada ActualizarFavoritos. Para ello hago lo siguiente:

if (pidList!=null){
new ActualizarFavoritos().execute(pidList);
}

Y en la clase ActualizarFavoritos:
class ActualizarFavoritos extends AsyncTask<ArrayList<String>, String, String> {
@override
protected void onPreExecute() {

}
protected String doInBackground(ArrayList<String>... args) {
ArrayList<String> pidListpassed = args[0];
HashMap<String, ArrayList<String>> params = new HashMap<String, ArrayList<String>>();
params.put("pidList", pidListpassed);
JSONObject json = jParser.makeHttpRequest(url_favoritos, "POST", params);
try {
//SUCCESS TAG
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {

}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
pDialog.dismiss();
}
Y me da error al ejecutar la aplicación. En el log pone:
Caused by: java.lang.NullPointerException
En la línea que corresponde a: int success = json.getInt(TAG_SUCCESS);
Llevo dándole vueltas un tiempo y no encuentro donde me equivoco. Agradecería a quién me pudiera orientar.
Responder Con Cita


  #2  
Viejo 28/01/17, 21:10:18
Array

[xs_avatar]
Nonamed Nonamed no está en línea
Colaborador/a
· Votos compra/venta: (4)
 
Fecha de registro: feb 2011
Localización: Madrid
Mensajes: 175,527

@Joakin60:,

Movemos a programación y desarrollo para Android.
__________________
Nonamed
Moderación y soporte a usuarios
Responder Con Cita
  #3  
Viejo 29/01/17, 17:35:32
Array

[xs_avatar]
kriogeN kriogeN no está en línea
Colaborador/a
· Votos compra/venta: (1)
 
Fecha de registro: oct 2010
Localización: Murcia
Mensajes: 4,637
Modelo de smartphone: Samsung Galaxy S7 Edge SM-G935F
Tu operador: Vodafone
Por lo que he estado leyendo parece ser que esa librería utiliza DefaultHttpClient, la cual lleva Deprecated casi desde que salió, y por fin eliminada en Android 6.0.

Prueba en un dispositivo con Lollipop o inferior, y si te funciona, tienes que poner esto en el Gradle para que funcione en Marshmallow:

android {
useLibrary 'org.apache.http.legacy'
}

De todas formas hay tropecientas librerías para hacer el trabajo de parseo y petición de datos, como por ejemplo la que uso yo, combinar Volley y GSON.
Responder Con Cita
Gracias de parte de:
  #4  
Viejo 30/01/17, 08:38:44
Array

[xs_avatar]
Dexafree Dexafree no está en línea
Mr. FAQMan
· Votos compra/venta: (1)
 
Fecha de registro: dic 2008
Mensajes: 8,021
Modelo de smartphone: Samsung Galaxy S i9000 + Galaxy Tab 10.1 WiFi
Tu operador: Movistar
KriogeN ya ha respondido la pregunta, pero aprovecho para añadir mi granito de arena a esto:

 Cita: Originalmente Escrito por kriogeN Ver Mensaje
combinar Volley y GSON
Retrofit también tiene integración directa con GSON para peticiones + parseo de datos:
http://square.github.io/retrofit

Las AsyncTask ya prácticamente ni se utilizan (por suerte).
Lo malo es que muchos tutoriales para principiantes son antiguos y por tanto es lo que utilizan (igual que todavía se ven muchos que hablan de usar Eclipse...).
Responder Con Cita
Gracias de parte de:
  #5  
Viejo 30/01/17, 11:34:45
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

He comprobado que los parámetros a pasar son correctos:
ArrayList<String> pidListpassed = args[0];
Log.d("pidListpassed", pidListpassed + " ,");
HashMap<String, ArrayList<String>> params = new HashMap<String, ArrayList<String>>();
params.put("pidList", pidListpassed);
La url también es correcta, así como el PHP, pero json es nulo:
JSONObject json = jParser.makeHttpRequest(url_favoritos, "POST", params);
if(json == null){
Log.d("KKKKKK", "json es nulo");
}
Luego el problema debería estar en el JSON, pero lo he utilizado en otros sitios y funciona, así que no se en que falla.
En lo referente a utilizar DefaultHttpClient no es el caso, y sí me tendré que poner con GSON cuando acabe esto, de momento no quiero mezclar librerías en la misma app. De Volley no he visto nada. Ente las dos ya me dirás con cual debería ponerme.
Te envío el JSONParser por si ves algo raro, pero como te he dicho me ha estado funcionando con la versión 6.

import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;

public class JSONParser {

String charset = "UTF-8";
HttpURLConnection conn;
DataOutputStream wr;
StringBuilder result = new StringBuilder();
URL urlObj;
JSONObject jObj = null;
StringBuilder sbParams;
String paramsString;

public JSONObject makeHttpRequest(String url, String method,
HashMap<String, ArrayList<String>> params) {

sbParams = new StringBuilder();
int i = 0;
for (String key : params.keySet()) {
try {
if (i != 0){
sbParams.append("&");
}
sbParams.append(key).append("=")
.append(URLEncoder.encode(params.get(key).toString (), "utf8"));

} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
i++;
}

if (method.equals("POST")) {
// request method is POST
try {
urlObj = new URL(url);
conn = (HttpURLConnection) urlObj.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", charset);
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.connect();
paramsString = sbParams.toString();

wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(paramsString);
wr.flush();
wr.close();

} catch (IOException e) {
e.printStackTrace();
}
}
else if(method.equals("GET")){
// request method is GET

if (sbParams.length() != 0) {
url += "?" + sbParams.toString();
}

try {
urlObj = new URL(url);
conn = (HttpURLConnection) urlObj.openConnection();
conn.setDoOutput(false);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept-Charset", charset);
conn.setConnectTimeout(15000);
conn.connect();

} catch (IOException e) {
e.printStackTrace();
}

}

try {
//Receive the response from the server
InputStream in = new BufferedInputStream(conn.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "iso-8859-1"), 8);
//BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}

Log.d("JSON Parser", "result: " + result.toString());

} catch (IOException e) {
e.printStackTrace();
}

conn.disconnect();

// try parse the string to a JSON object
try {
jObj = new JSONObject(result.toString());
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}

// return JSON Object
return jObj;
}
}
Responder Con Cita
  #6  
Viejo 31/01/17, 11:51:46
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

Cuando dices "Las AsyncTask ya prácticamente ni se utilizan (por suerte)" ¿porqué lo dices? No veo que tienen de malo.
Responder Con Cita
  #7  
Viejo 31/01/17, 12:57:36
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

 Cita: Originalmente Escrito por Joakin60 Ver Mensaje
Cuando dices "Las AsyncTask ya prácticamente ni se utilizan (por suerte)" ¿porqué lo dices? No veo que tienen de malo.
Imagino que @Dexafree tendrá otras razones, a mí no me gustan porque son muy feas Controlar su ciclo de vida es complicado, puede dar lugar a pérdidas de memoria y su comportamiento por defecto actual es que se ejecutan de forma secuencial y no en paralelo, así que si tienes una tarea que esté tardando más por cualquier motivo igual te impide que se ejecute otra que necesitas más urgentemente.

De hecho la propia documentación de Android (o en algún sitio oficial lo he visto) indican que es para tareas muy cortas. Para acceder a un recurso de red no se recomiendan, y menos existiendo bibliotecas "asíncronas" que te hacen todo el trabajo, te avisan con su listener y ya gestionan ellas los hilos que hagan falta y las conexiones. Con la madurez de las soluciones actuales mejor no reinventar la rueda.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Los siguientes 3 usuarios han agradecido a mocelet su comentario:
[ Mostrar/Ocultar listado de agradecimientos ]
  #8  
Viejo 31/01/17, 15:41:10
Array

[xs_avatar]
Dexafree Dexafree no está en línea
Mr. FAQMan
· Votos compra/venta: (1)
 
Fecha de registro: dic 2008
Mensajes: 8,021
Modelo de smartphone: Samsung Galaxy S i9000 + Galaxy Tab 10.1 WiFi
Tu operador: Movistar
 Cita: Originalmente Escrito por mocelet Ver Mensaje
a mí no me gustan porque son muy feas Controlar su ciclo de vida es complicado, puede dar lugar a pérdidas de memoria
Aparte de feas, lo segundo que comentas lo veo más importante.
Se inician con una referencia a la Activity que las inicia, así que si rotas la pantalla mientras se está ejecutando, ese enlace sigue existiendo y la Activity no será recolectada por el GC (a no ser que implementes tu propio método de detach).
Además, como comentas, existen librerías que hacen todo ese trabajo de forma asíncrona ofreciendo una API mucho más limpia, gestionando ellas el tema del Threading, y sin tantas complicaciones para el desarrollador.

Finalmente, como las he visto implementadas muchas veces es metidas directamente dentro de la Activity, con lo cuál:

1. La separación de principios no se está cumpliendo (la Activity hace de vista y "Controlador" a la vez)
2. Puedes tener tentaciones de actualizar componentes de la vista en otro hilo de ejecución (si la AsyncTask ha lanzado otro hilo), lo cuál puede dar errores
3. Fácilmente se pueden dar race conditions si no sabes gestionar bien tus variables (si sabes lo que estás haciendo no deberías tener problemas, pero hay de todo en el mundo).
Responder Con Cita
Gracias de parte de:
  #9  
Viejo 31/01/17, 21:35:40
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

El problema era una sandez, se me había olvidado poner el acceso a internet en el Manifest (perdón, no me lo tengáis en cuenta). Muchas gracias por vuestros comentarios, mira por donde he aprendido de rebote algo que es muy interesante. No creía que fuera tan problemático utilizar AsyncTask. He estado mirando diferencias entre Volley y Retrofit y se decantan por Retrofit, ¿Qué opináis?
Una duda que tengo en lo que me afecta es si con estas bibliotecas se puede hacer el servicio REST de forma secuencial, me explico en mi caso.
Quiero hacer la consulta a un mismo AsyncTask con diferentes parámetros u url´s y de forma secuencial, por ejemplo:
switch(tituloapartados) {
case "Arte":
if (pidList!=null) { url_favoritos="http://xxx.com/ phpconsult/favoritos/arte.php";
pid=….
apartado=…
new ActualizarFavoritos().execute(pidList, url_favoritos, apartado);
}
case "Naturaleza":
if (pidList!=null) {
url_favoritos="http://xxx.com/ phpconsult/favoritos/naturaleza.php";
pid=….
apartado=…
new ActualizarFavoritos().execute(pidList, url_favoritos, apartado);
}
case "Restauracion":
….
Es decir voy a ejecutar el mismo AsyncTask de forma secuencial, si es que se puede, que todo esto me lo supongo y no lo he hecho.
Responder Con Cita
  #10  
Viejo 01/02/17, 11:20:28
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

 Cita: Originalmente Escrito por Joakin60 Ver Mensaje
Una duda que tengo en lo que me afecta es si con estas bibliotecas se puede hacer el servicio REST de forma secuencial
La forma de obtener datos normalmente es con un método conectar(URL, listener). Puedes llamarlo todas las veces que quieras cuando quieras para distintas URL y en el listener que le pases a cada llamada haces lo que necesites con los datos cuando te los dé.

EDIT: Retrofit es el mismo perro con distinto collar, está hecho para que no uses URLs directamente sino llamadas a métodos Java, así que probablemente llamarías a un método getFavoritos("naturaleza") que tiene anotaciones para que haga un GET a "/phpconsult/favoritos/{categoria}.php". Y él por dentro hace la conexión y te devuelve los datos en forma de objeto. Supongo que por eso le gusta a la gente.

P.D: En el switch de antes te faltan los break, según está se ejecutarían todos los casos en cascada a partir del primero que se cumpla. Además que hay muchas líneas repetidas que podrían estar fuera del switch perfectamente. Tampoco entiendo a qué te referías con secuencial, precisamente el ejemplo del switch es para seleccionar uno entre varias opciones.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!

Última edición por mocelet Día 01/02/17 a las 11:29:13.
Responder Con Cita
  #11  
Viejo 01/02/17, 20:32:15
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

Crear apartado Favoritos

Olvidémonos del switch, era un ejemplo mal puesto. Te cuento lo que quiero hacer, cómo y el desastre.
Intento hacer un apartado de favoritos, y para ello he hecho lo siguiente:
Una base de datos SQLite que cuando le das a añadir guarda un número de identificación del registro que se corresponde con el del registro correspondiente de una base de datos externa MySQL y el nombre del apartado para saber que url y variables (una en mi caso) utilizar. Para ver los favoritos recupero el nombre de apartado y el pid de la siguiente forma:
….
public String[] apartadomatriz = {"Arte y cultura","Naturaleza","Ofertas para comer,…};
...
public void onClick(View v) {
//Vemos los registros de nuestra tabla
pids = new String[FDB.recuperarfavoritos().size()];
aparts = new String[FDB.recuperarfavoritos().size()];
apartadoListArte = new ArrayList<String>();
pidListArte = new ArrayList<String>();
for (int i = 0; i < FDB.recuperarfavoritos().size(); i++) {
pids[i] = FDB.recuperarfavoritos().get(i).getpid();
aparts[i] = FDB.recuperarfavoritos().get(i).getapartado();
//Registros del apartado Arte y Cultura
if(apartadomatriz[0].equals(aparts[i])){
pidListArte.add(pids[i]);
apartadoListArte.add(aparts[i]);
String url_fav_Arte="http://xxx/phpconsult/favoritos/arte.php";
ArrayList<String> urlArte = new ArrayList<String>(Arrays.asList(url_fav_Arte.split (",")));
Log.d("PIDSARTE", pidListArte + " ," + apartadoListArte);
if (pidListArte!=null){
new ActualizarFavoritos().execute (pidListArte,urlArte);
} else {
Toast.makeText(getApplicationContext(), "No tiene favoritos guardados", Toast.LENGTH_LONG).show();
}
}
Y con estos datos utilizar un AsyncTask (ActualizarFavoritos) y rellenar un RecyclerView. Hasta ahí, con sólo un apartado va bien. El problema es que son varios apartados (Naturaleza,Ofertas…), y si añado otro con estructura similar al anterior (y también llamando a new ActualizarFavoritos().execute (pidListNaturaleza,urlNaturaleza);) el json da error. Si utilizo dos AsyncTask uno para cada apartado (que ya es un engorro), se queda colgado en el ProgressDialog, sin contar como me las apañaría con el RecyclerView.
Así que si me puedes orientar te lo agradecería muchísimo.
Responder Con Cita
  #12  
Viejo 01/02/17, 20:44:43
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

El objeto jParser de tu código no sé dónde lo estás creando pero no puedes reutilizarlo de una petición a otra, probablemente por eso te da error. Tienes que crear uno nuevo cada vez que vayas a usarlo (cosa que no ocurre con una biblioteca en condiciones).

Sobre los engorros es porque haces mucho copy paste de código que podría solucionarse con un método al que le pases los parámetros que cambian y objetos que encapsulen de forma más "amigable" esos datos.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
  #13  
Viejo 01/02/17, 21:26:41
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

Probablemente no, seguro, daba un NullPointerException en el jParser en:
InputStream in = new BufferedInputStream(conn.getInputStream());
Y claramente es al reutilizarlo.
En cuanto al copy paste no digo que no lo utilice a menudo, pero en este caso me lo he currado enterito, desde el Json para recibir como parámetro ArrayList<String>, hasta el nuevo modo de conexión en las últimas versiones. Así como todo lo concerniente a la base de datos SQLite y recuperación de los parámetros. En cuanto al “método al que le pases los parámetros que cambian y objetos que encapsulen de forma más "amigable"” tienes toda la razón, pero son tres parámetros distintos para cada caso, y mi ignorancia me impide hacerlo de otra manera, de todas formas es muy a tener en cuenta y procuraré pulir ese aspecto.
Resumiendo que me voy a poner con Retrofit y a ver que saco en claro para solucionar esto.
De nuevo muchas gracias por tu tiempo y tus conocimientos.
Responder Con Cita
  #14  
Viejo 01/02/17, 21:39:32
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

Con copy paste no me refería a que copiaras código de por ahí, me refería a que tu propio código aparentemente se repite bastante cambiando cosas concretas (un nombre, un id...)

Por ejemplo, tienes una variable que es pidListArte, y así tendrás más ligadas a otras categorías. El código para todas las categorías supongo que hace lo mismo, de ahí lo de tener un método que le pases el nombre de categoría y no tengas que repetir código.

En cuanto veas que hay dos bloques de código parecidos o idénticos donde solo cambian algunos parámetros es signo de que puede generalizarse.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Gracias de parte de:
  #15  
Viejo 01/02/17, 22:09:16
Array

[xs_avatar]
Joakin60 Joakin60 no está en línea
Miembro del foro
 
Fecha de registro: oct 2015
Mensajes: 64
Tu operador: Movistar

Retrofit

Disculpa si me he mosqueado con el copy paste, pero es que cada vez que hago algo me cuesta sangre, sudor y lágrimas y me lo he tomado como una cosa que he visto y he pegado al “tututun” a ver si funciona.
En cuanto a los bloques de código parecidos, pidListArte es un caso concreto que he cambiado cuando he hecho la prueba con dos AsyncTask, en realidad siempre es pidList, así como url_fav_Arte se llama siempre url_fav.
Volviendo al tema. ¿Tu crees que si me pongo a estudiarme Retrofit podré solucionar el tema?
Responder Con Cita
  #16  
Viejo 01/02/17, 22:55:09
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

Si ya tienes todo hecho con la AsyncTask y la clase esa que se conecta no creo que vayas a ganar nada usando otra biblioteca.

Lo que sí sería una mejora es que abstraigas esa petición de datos en un método de forma que si mañana decides no usar el AsyncTask con esa clase solo tengas que cambiar código en un sitio para llamar a volley/retrofit/okhttp en vez de crear una AsyncTask por ejemplo.

Probablemente al hacer esa limpieza de código también descubras por qué falla al intentar actualizar dos categorías.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Respuesta

Estás aquí
Regresar   Portal | Indice > Todo sobre Android > Programación y Desarrollo para Android

Herramientas


Hora actual: 02:10:57 (GMT +1)



User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.

Contactar por correo / Contact by mail / 邮件联系 /