5

Tôi đang cố gắng để tạo ra một ứng dụng tương tự như một: An app with some images and description (cardview) in a recyclerviewAsyncTask tải hình ảnh RecyclerView

đầu tiên ở tất cả i tải tất cả các thông tin cho CardView của tôi từ một cơ sở dữ liệu Tiêu đề của hình ảnh, mô tả và URL từ hình ảnh. Khi tôi đặt tất cả thông tin đó vào RecyclerView, (tiêu đề và mô tả) hiển thị chính xác, nhưng đối với hình ảnh tôi tạo một lớp AsyncTask để tải hình ảnh từ URL và cho phép người dùng không chờ đợi nhiều thời gian chờ ứng dụng để đáp ứng.

Nếu người dùng cuộn chậm hình ảnh được tải chính xác và tất cả đều ổn, nhưng nếu tôi cuộn nhanh đến tôi có một số vấn đề, ví dụ hình ảnh được hiển thị trong mục 3 chẳng hạn được hiển thị trong mục cuối cùng cho đến khi hình ảnh mục cuối cùng được nạp và làm mới ....

Dưới đây một số mã cho bộ chuyển đổi của tôi, nơi tôi tải hình ảnh:

@Override 
public void onBindViewHolder(ViewHolder holder, final int position) { 
    if (holder instanceof EventosViewHolder) { 
     ...... 
     //Load the image (getFoto() get drawable) 
     if (eventoInfoAux.getFoto()==null){ 
      CargarImagen cargarImagen = new CargarImagen(((EventosViewHolder) holder).vRelativeLayout,eventoInfo,position); 
      cargarImagen.execute(); 
     }else{ 
      ((EventosViewHolder) holder).vRelativeLayout.setBackground(eventoInfoAux.getFoto()); 
     } 
    } 
} 

Ở đây mã cho CargarImagen lớp:

//Clase para cargar imagenes con una tarea asíncrona desde un url de la imagen 
public class CargarImagen extends AsyncTask<String, String, Boolean>{ 

//RelativeLayout donde se introduce la imagen de fondo 
RelativeLayout relativeLayout=null; 
//EventoInfo para obtener la url de la imagen 
List<EventoInfo> eventoInfo=null; 
//Posición de la imagen clicada 
int i; 

//Se cargan todos los valores de las variables necesarias desde los datos introducidos 
public CargarImagen(RelativeLayout relativeLayout,List<EventoInfo> eventoInfo,int i) { 
    this.relativeLayout = relativeLayout; 
    this.eventoInfo = eventoInfo; 
    this.i = i; 
} 

//Pintamos el fondo de gris mientras se está cargando la imagen 
@Override 
protected void onPreExecute() { 
    super.onPreExecute(); 
    relativeLayout.setBackgroundResource(R.color.fondo_card_view); 
} 

//Se realiza la carga de la imagen en segundo plano 
@SuppressWarnings("deprecation") 
@Override 
protected Boolean doInBackground(String... params) { 
    //Necesario para hacer la llamada a la red 
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();  
    StrictMode.setThreadPolicy(policy); 

    //obtenemos la imagen con el metodo getBitmapFromURL 
    Bitmap myImage = getBitmapFromURL(eventoInfo.get(i).url); 

    //Si se tiene imagen se pinta, si no no se hace nada 
    if (myImage !=null){ 
     Drawable dr = new BitmapDrawable(myImage); 
     eventoInfo.get(i).setFoto(dr); 
     return true; 
    } 
    return false; 
} 

//Al finalizar la carga de la imagen se pinta el fondo del relative layout 
protected void onPostExecute(Boolean result) { 
    if(result){ 
     relativeLayout.setBackground(eventoInfo.get(i).foto); 
    } 
} 

//Metodo para obtener un bitmap desde una url 
public Bitmap getBitmapFromURL(String imageUrl) { 
    try { 

     URL url = new URL(imageUrl); 
     HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
     connection.setDoInput(true); 
     connection.connect(); 
     InputStream input = connection.getInputStream(); 
     Bitmap myBitmap = BitmapFactory.decodeStream(input); 
     return myBitmap; 

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

} 

Tôi có thể cung cấp cho bạn tệp .apk và bạn có thể thấy sự cố.

Cảm ơn bạn trước. :)

Đây mã đầy đủ của bộ chuyển đổi của tôi

import java.util.List; 

import com.abdevelopers.navarraongoing.R; 
import com.abdevelopers.navarraongoing.detalle.DetalleActivity; 

import android.content.Intent; 
import android.support.v7.widget.CardView; 
import android.support.v7.widget.RecyclerView; 
import android.support.v7.widget.RecyclerView.ViewHolder; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.ViewGroup.LayoutParams; 
import android.widget.Button; 
import android.widget.RelativeLayout; 
import android.widget.TextView; 

public class EventosAdapter extends RecyclerView.Adapter<ViewHolder>{ 

    private static final int TYPE_EVENTO = 0; 
    private static final int TYPE_FOOTER = 1; 

//lista de eventos 
private List<EventoInfo> eventoInfo; 


private String usuario; 
private EventoInfo eventoInfoAux; 
private PaginaInicioActivity paginaInicio; 

//Se pasan los valores necesarios para obtener información de los eventos 
public EventosAdapter(List<EventoInfo> eventoInfo, String usuario, PaginaInicioActivity paginaInicio) { 
    this.eventoInfo = eventoInfo; 
    this.usuario = usuario; 
    this.paginaInicio = paginaInicio; 
} 


//Metodo para obtener el numero de items en la lista que introducimos 
@Override 
public int getItemCount() { 
    return eventoInfo.size(); 
} 

@Override 
public int getItemViewType(int position) { 
    if (position + 1 == getItemCount()) { 
     return TYPE_FOOTER; 
    } else { 
     return TYPE_EVENTO; 
    } 
} 

//Se asignan los datos a cada uno de los elementos de la cardview 
@Override 
public void onBindViewHolder(ViewHolder holder, final int position) { 
    if (holder instanceof EventosViewHolder) { 
     //Obtenemos cada uno de los eventos 
     eventoInfoAux = eventoInfo.get(position); 
     //eventosViewHolder = holder; 

     //Introducimos el título del evento 
     ((EventosViewHolder) holder).vTitle.setText(eventoInfoAux.titulo); 
     //Introdicumos la fecha y el lugar del evento 
     ((EventosViewHolder) holder).vFechaLugar.setText(eventoInfoAux.fecha+", "+eventoInfoAux.lugar); 
     //obtenemos el numero de asistentes al evento 
     String asistentes = Integer.toString(eventoInfoAux.asistentes); 
     ((EventosViewHolder) holder).vLikeButton.setText(asistentes); 

     //Se pinta el boton de like dependiendo de si está o no like 
     if(eventoInfoAux.like){ 
      ((EventosViewHolder) holder).vLikeButton.setBackgroundResource(R.drawable.button_like_liked); 
     }else{ 
      ((EventosViewHolder) holder).vLikeButton.setBackgroundResource(R.drawable.button_like); 
     } 

     //Se pinta la imagen del evento dependiendo de si está en la base de datos o no 
     if (eventoInfoAux.foto==null){ 
      CargarImagen cargarImagen = new CargarImagen(((EventosViewHolder) holder).vRelativeLayout,eventoInfo,position); 
      cargarImagen.execute(); 
     }else{ 
      ((EventosViewHolder) holder).vRelativeLayout.setBackground(eventoInfoAux.foto); 
     } 
    } 
} 



@Override 
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    if (viewType == TYPE_EVENTO) { 
     View view = LayoutInflater. 
       from(parent.getContext()). 
       inflate(R.layout.evento_card_view, parent, false); 
     return new EventosViewHolder(view,eventoInfo,usuario,paginaInicio); 
    } else if (viewType == TYPE_FOOTER) { 
     View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.pie_carga_pagina_inicio, parent, false); 
     view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 
     return new FooterViewHolder(view); 
    } 
    return null; 
} 

//Clase para crear el footerview donde se cargan más eventos 
class FooterViewHolder extends ViewHolder { 

    public FooterViewHolder(View view) { 
     super(view); 
    } 

} 

//Clase para crear los eventos con su cardview 
class EventosViewHolder extends ViewHolder implements View.OnClickListener{ 

    private TextView vTitle; 
    private TextView vFechaLugar; 
    private Button vLikeButton; 
    private RelativeLayout vRelativeLayout; 
    private List<EventoInfo> eventoInfo; 
    private String usuario; 
    private LikesDDBB likesManager; 
    private PaginaInicioActivity paginaInicio; 
    private CardView vCardView; 

    public EventosViewHolder(View itemView,List<EventoInfo> eventoInfo,String usuario, 
      PaginaInicioActivity paginaInicio) { 
     super(itemView); 

     this.paginaInicio = paginaInicio; 
     this.usuario = usuario; 
     vTitle = (TextView)itemView.findViewById(R.id.titulo); 
     vFechaLugar = (TextView) itemView.findViewById(R.id.fecha_lugar); 
     vLikeButton = (Button) itemView.findViewById(R.id.like_button); 
     vRelativeLayout = (RelativeLayout) itemView.findViewById(R.id.layout_cardview); 
     vCardView = (CardView)itemView.findViewById(R.id.card_view); 

     //Valores por defecto de los botones y del fondo en caso de no haber like ni foto 
     vLikeButton.setBackgroundResource(R.drawable.button_like); 
     vRelativeLayout.setBackgroundResource(R.color.fondo_card_view); 
     vLikeButton.setOnClickListener(this); 
     vCardView.setOnClickListener(this); 
     vLikeButton.setTag("boton"); 
     vCardView.setTag("evento"); 

     this.eventoInfo = eventoInfo; 
    } 


    @SuppressWarnings("deprecation") 
    @Override 
    public void onClick(View v) { 
     if(v.getTag().equals("boton")){ 
      likesManager = new LikesDDBB(this.eventoInfo.get(getPosition()).like, usuario, 
        vLikeButton, getPosition(), eventoInfo, paginaInicio); 
      likesManager.execute(); 
     }else if(v.getTag().equals("evento")){ 
      Intent inicion = new Intent(paginaInicio,DetalleActivity.class); 

      paginaInicio.startActivity(inicion); 
     } 

    } 

} 

//Para obtener la lista de eventos desde la clase PaginaInicioActivity 
public List<EventoInfo> getEventoInfo() { 
    return eventoInfo; 
} 

public void setEventoInfo(List<EventoInfo> eventoInfo) { 
    this.eventoInfo = eventoInfo; 
} 

} 
+0

Tôi cho phép bạn ở đây tệp .apk https://mega.co.nz/#!Wc1hlagS!XMOMauYpbdk_UZBIswBgcltbRpwAc7VqaJmlS4JZ9FE trong ứng dụng Người dùng: bruno và Mật khẩu: 1234 – Bruno

+0

Bạn phải hủy AsyncTask ở nơi thích hợp (bất cứ khi nào không cần kết quả). Ví dụ, sử dụng phương thức hủy bỏ của AsyncTask trong phương thức 'onDetachedFromWindow()' của Chế độ xem tùy chỉnh của bạn, nếu bạn có chế độ xem tùy chỉnh của riêng mình. –

+0

[đây là giải pháp vấn đề của bạn] (https://www.youtube.com/watch?v=8MIfSxgsHIs&feature=youtu.be&list=PLWz5rJ2EKKc86y1CjAlexivfvOms6_0NC) –

Trả lời

4

Vì tên "RecyclerView" cho biết, nó sẽ tái chế/sử dụng lại các chế độ xem được tạo để hiển thị các mục/thẻ của bạn.

Vì vậy, hãy giả sử RecyclerView của bạn có 3 CardView mà nó tái chế khi bạn cuộn và chúng tôi có 4 mục để hiển thị nội dung.

Ban đầu nội dung của mục 1 được hiển thị trong CardView 1, mục 2 được hiển thị trong CardView 2 và mục 3 được hiển thị trong CardView 3.

Bây giờ, khi bạn cuộn, CardView 1 biến mất, được tái chế và nội dung của mục 4 được hiển thị trong CardView 1.

Miễn là bạn không đặt lại nội dung đã chèn trước đó, CardView 1 sẽ hiển thị chúng - trong trường hợp của bạn - miễn là AsyncTask cần hoàn thành nội dung của mục được đặt trước đó sẽ được hiển thị.

Để giải quyết vấn đề của bạn, bạn có thể muốn sử dụng một imageloading (và bộ nhớ đệm) thư viện như:

giải pháp của bạn cũng dễ bị đua điều kiện (khi sau công việc hoàn thành trước những cái trước đó)

+0

Xin chào và cảm ơn bạn đã trả lời. Sau khi tìm kiếm giải pháp tôi đã tải xuống thư viện picasso và thay vào đó sử dụng một AsicTask tôi đã sử dụng picasso nhưng vấn đề vẫn còn. – Bruno

+0

Xin chào với nhận xét của bạn, tôi nghĩ rằng vấn đề phải giống như vậy http://stackoverflow.com/questions/26591390/recycler-view-with-volley-image-request-cancel-request – Bruno

+0

Vâng, vấn đề tương tự - picasso và uil xử lý này cho bạn, nếu bạn muốn giải quyết nó trên của riêng bạn, bạn phải theo dõi tải hình ảnh nhắm mục tiêu cùng một (tái chế) xem. –

0

Tôi nghĩ rằng bạn nên sử dụng một thư viện của bên thứ ba như Picasso để không đồng bộ tải hình ảnh từ một url. Thư viện cung cấp nhiều hơn thế, và bạn có thể tập trung nhiều hơn vào chức năng của ứng dụng của bạn thay vì bị rối trong việc thiết lập AsynkTask của riêng bạn.

+0

Hi hơn bạn cho câu trả lời, nhưng tôi đã cố gắng làm điều đó thay vì asynctask và vấn đề vẫn còn đó. – Bruno

+0

Có lẽ bạn nên đăng một số mã để xem vấn đề. – SebastianGreen

+0

đã thêm và tệp .apk cảm ơn bạn Sebastian – Bruno

Các vấn đề liên quan