entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

3votos

Problemas al cargar listView (internet) con imagenes

Buenas, me he dado cuenta que en una aplicación que tengo, en la que obtengo los datos a través de una URL y desde Android los muestro en un listview (personalizado), pues al tener como unas 10 o 12 noticias más o menos tengo un problema que pienso que sobrecarga la pila y cuando intento acceder a una noticia en concreto en lugar de entrar me vuelve al inicio de la aplicación. Sé que es problema de las imágenes porque he probado a no mostrarlas y lo hace todo bien.

Pues buscando en internet, me encontré con esto: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap

Necesito implementar estos 2 métodos:

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

Pero no tengo muy claro como hacerlo porque en el ejemplo lo hacen con una imagen que están en drawable y en mi caso la imagen la obtengo de un arrayList y no sé que datos pasar ni qué tengo que modificar del método.
¿Cómo puedo resolver este problema que tengo con las imágenes?
Muchas gracias y un saludo

0voto

white comentado

Como inflas la vista en tu adaptador? cual es el código con el que muestras la imagen? cuando cargas la url de las imagenes lo haces asincronicamente?

0voto

danielreales7 comentado

Buenas, no lo estoy haciendo asíncronamente. Te comento como lo hago todo.

class ListViewItem {
    public String id;
    public String contenido;
    public Bitmap ThumbnailResource;
    public int ThumbnailResourceNull;
    public int MeGusta;
    public String numeroMegusta;
    public String Title;
    public String SubTitle;
    public String URLImagen;
}

public void getData(){
    String result = "";
    InputStream isr = null;
    List<ListViewItem> items = new ArrayList<Noticias.ListViewItem>();
    try{
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("http://www.xxx.com/xxx/noticias.php"); //YOUR PHP SCRIPT ADDRESS 
        HttpResponse response = httpclient.execute(httppost);
        HttpEntity entity = response.getEntity();
        isr = entity.getContent();
    }
    catch(Exception e){
            e.printStackTrace();
    }
    //convert response to string
    try{
        BufferedReader reader = new BufferedReader(new InputStreamReader(isr,"iso-8859-1"),8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
        }
        isr.close();

        result=sb.toString();
    }
    catch(Exception e){
        e.printStackTrace();
    }

    //parse json data
    try {
       String s = "";
       JSONArray jArray = new JSONArray(result);
       for(int i=0; i<jArray.length();i++){
           final JSONObject json = jArray.getJSONObject(i);
           final String imagenURL = json.getString("imagen");
           bitmap = getBitmapFromURL(imagenURL);
           if(imagenURL.equals("null")){
               items.add(new ListViewItem(){{
                    id = json.getString("id_noticia");
                    ThumbnailResourceNull = R.drawable.launcher_icon;
                    Title = json.getString("titulo");
                    contenido = json.getString("contenido");
                    URLImagen = json.getString("imagen");
                    SubTitle = json.getString("f_alta");
                    MeGusta = R.drawable.star;
                    numeroMegusta = json.getString("favoritos");
                }});
           }else{
               items.add(new ListViewItem(){{
                    id = json.getString("id_noticia");
                    ThumbnailResource = bitmap;
                    Title = json.getString("titulo");
                    contenido = json.getString("contenido");
                    URLImagen = json.getString("imagen");
                    SubTitle = json.getString("f_alta");
                    MeGusta = R.drawable.star;
                    numeroMegusta = json.getString("favoritos");
                }});
           }
       }

        final CustomListViewAdapterNoticias adapter = new CustomListViewAdapterNoticias(this, items);
        listNoticias.setAdapter(adapter);

        listNoticias.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // TODO Auto-generated method stub
                ListViewItem chapter = adapter.getCodeLearnChapter(position);

                Intent actividadNoticiaID = new Intent(getApplicationContext(), NoticiaId.class );
                actividadNoticiaID.putExtra("id", chapter.id);
                actividadNoticiaID.putExtra("titulo", chapter.Title);
                actividadNoticiaID.putExtra("contenido", chapter.contenido);
                actividadNoticiaID.putExtra("imagen", chapter.ThumbnailResource);
                actividadNoticiaID.putExtra("imagenNula", chapter.ThumbnailResourceNull);
                actividadNoticiaID.putExtra("urlImagen", chapter.URLImagen);
                actividadNoticiaID.putExtra("fecha", chapter.SubTitle);
                actividadNoticiaID.putExtra("numeroMeGusta", chapter.numeroMegusta);
                startActivity(actividadNoticiaID);        

                //Toast.makeText(getApplicationContext(), chapter.id, Toast.LENGTH_SHORT).show();
            }

        });

       } catch (Exception e) {
        // TODO: handle exception
           e.printStackTrace();
       }

}

Tengo ese método en el que después lo llamo desde el onCreate y el adaptador del listView es donde pongo la imagen, que contiene lo siguiente:

public View getView(final int position, View convertView, ViewGroup parent) {  
    // TODO Auto-generated method stub  
    ListViewItem item = items.get(position);

    View vi=convertView;

    if(convertView==null)
        vi = inflater.inflate(R.layout.item_row_noticias, null);

    ImageView imgThumbnail = (ImageView)vi.findViewById(R.id.imgThumbnail);
    TextView txtTitle = (TextView)vi.findViewById(R.id.txtTitle);
    TextView txtSubtitle = (TextView)vi.findViewById(R.id.txtTitle2);
    ImageView estrella = (ImageView)vi.findViewById(R.id.megusta);
    TextView numeroMeGusta = (TextView)vi.findViewById(R.id.txtMegusta);

    imgThumbnail.setImageBitmap(item.ThumbnailResource);
    imgThumbnail.setImageResource(item.ThumbnailResourceNull);
    txtTitle.setText(item.Title);
    txtSubtitle.setText(item.SubTitle);
    estrella.setImageResource(item.MeGusta);
    numeroMeGusta.setText(item.numeroMegusta);

    return vi;  
}

1 Respuesta

3votos

white Puntos75820

Intenta usar una tarea asincrónica en la carga de imagenes.

antes del metodo:

public View getView(final int position, View convertView, ViewGroup parent)

agrega esta clase:

private class getImageUrl extends AsyncTask<String, Void, Bitmap> {

    ImageView image;

    public getImageUrl(ImageView image) {
        this.image = image;
    }

    protected Bitmap doInBackground(String... urls) {
        String url = urls[0];
        Bitmap img = null;
        try {
            InputStream in = new java.net.URL(url).openStream();
            img = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
        }
        return img;
    }

    protected void onPostExecute(Bitmap result) {
        image.setImageBitmap(result);
    }
}

en lugar de estas dos lineas:

imgThumbnail.setImageBitmap(item.ThumbnailResource);
imgThumbnail.setImageResource(item.ThumbnailResourceNull);

agrega esto:

new getImageUrl(imgThumbnail).execute(item.URLImagen);

remueve estas lineas:

bitmap = getBitmapFromURL(imagenURL);

ThumbnailResource = bitmap;

de esta forma cargas las imagenes de mejor forma, asi tu aplicacion tardaría menos en ejecutarse mejorando el performance, sería bueno que tambien sea asincrona la forma en que obtienes la informacion en json.


PD: a modo de sugerencia:

El uso de llaves dobles afecta de cierta forma en cuestion de performance, esto se debe a que por cada dato agregado crea una clase anonima.

new ListViewItem(){{ .. }}

una mejor manera es:

ListViewItem item = new ListViewItem();
item.contenido = ...

0voto

white comentado

que código tienes en el metodo putExtra? podrias agregar el codigo de tu actividad actividadNoticiaID?

el error FAILDER BINDER TRANSACTION se debe a que estas pasando informacion muy pesada, y no es para menos si se esta enviando un bitmap, agrega el codigo de tu actividad a ver si se puede hacer algo asincrono en esa actividad tambien.

0voto

danielreales7 comentado

Si te paso el código de la actividad donde se muestra cada noticia:

tituloView = (TextView) findViewById(R.id.textoTitulo);
    contenidoView = (TextView) findViewById(R.id.textoContenido);
    fechaView = (TextView) findViewById(R.id.textoFecha);
    imagen = (ImageView) findViewById(R.id.imgThumbnail);
    estrella = (ImageView) findViewById(R.id.imgStar);
    meGusta = (TextView) findViewById(R.id.textoFavoritos);

    Bundle bundle = getIntent().getExtras();
    tituloView.setText(bundle.getString("titulo"));
    contenidoView.setText(bundle.getString("contenido"));
    contenidoView.setMovementMethod(new ScrollingMovementMethod());
    fechaView.setText(bundle.getString("fecha"));
    if (bundle.getString("urlImagen").equals("null")) {
        imagen.setImageResource(R.drawable.launcher_icon);
    } else {
        imagen.setImageBitmap((Bitmap) bundle.getParcelable("imagen"));
    }
    estrella.setImageResource(R.drawable.star);
    meGusta.setText(bundle.getString("numeroMeGusta"));

    id = bundle.getString("id");
    favoritos = bundle.getString("numeroMeGusta");
    favoritosEntero = Integer.parseInt(favoritos);
    favoritosEntero = favoritosEntero + 1;

    final Button button = (Button) findViewById(R.id.buttonLike);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // Perform action on click
            TextView meGusta2 = (TextView) findViewById(R.id.textoFavoritos);
            String conver = String.valueOf(favoritosEntero);
            meGusta2.setText(conver);

            actualizarFavoritos();
            Toast.makeText(getApplicationContext(), "¡Te gusta!",
                    Toast.LENGTH_SHORT).show();
        }
    });

Este es un método para actualizar los favoritos de la noticia:

public void actualizarFavoritos() {
    String result = "";
    InputStream isr = null;
    try {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(
                "http://www.xxxxx.com/xxx/noticiaID.php?id="
                        + id + "&favoritos=" + favoritosEntero); // YOUR PHP
                                                                    // SCRIPT
                                                                    // ADDRESS
        HttpResponse response = httpclient.execute(httppost);
        HttpEntity entity = response.getEntity();
        isr = entity.getContent();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

0voto

white comentado

Hay varias soluciones, como:

  • guardar en el dispositivo las imagenes descargadas y obtenerlas desde este
  • usar una libreria para facilitar la carga de imagenes como picasso
  • usar asynctask en tu actividad para recuperar la imagen desde una url.

asynctask:

En tu actividad actividadNoticiaID agrega esta clase:

private class getImageUrl extends AsyncTask<String, Void, Bitmap> {

    private final WeakReference<ImageView> imageViewReference;

    public getImageUrl(ImageView image) {
        imageViewReference = new WeakReference<ImageView>(image);
    }

    protected Bitmap doInBackground(String... urls) {
        String url = urls[0];
        Bitmap bitmap = null;

        try
        {
            InputStream in = new java.net.URL(url).openStream();
            bitmap = BitmapFactory.decodeStream(in);
        }
        catch (Exception e) { Log.e("Error", e.getMessage()); }

        return bitmap;
    }

    protected void onPostExecute(Bitmap bitmap)
    {
        imageViewReference.get().setImageBitmap(bitmap);
    }
}

en lugar de:

else {
        imagen.setImageBitmap((Bitmap) bundle.getParcelable("imagen"));
    }

usa este código:

else {
        new getImageUrl(imagen).execute(bundle.getString("urlImagen"));
    }

elimina:

actividadNoticiaID.putExtra("imagen", chapter.ThumbnailResource);

actividadNoticiaID.putExtra("imagen", adapter.getThumbnail(position));

tambien olvida y elimina el metodo getThumbnail


picasso:

http://square.github.io/picasso/#download

en lugar de :

imagen.setImageBitmap((Bitmap) bundle.getParcelable("imagen"));

usa:

Picasso.with(context).load(bundle.getString("urlImagen")).into(imagen);

lo mismo podria hacerse para tu adaptador es una sola linea con esta libreria.


0voto

danielreales7 comentado

Todo genial!! Funciona perfectamente. Muchísimas gracias por la ayuda.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta