Lazy Loading no funciona correctamente

Estoy mostrando una lista de contactos en una revista de reciclaje. Estoy mostrando imágenes de perfil de contacto, primero estoy cargando estas imágenes desde el servidor y luego almacenar estas imágenes en una memoria externa.

Luego Carga de las imágenes desde el almacenamiento externo. Puedo ver las imágenes cargadas, pero como me desplazo puedo ver algunas imágenes durante un segundo o dos, entonces desaparecen y puedo ver el icono de la imagen por defecto.

public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactHolder> { private List<Contact> contactList; File myDir1; private Activity mContext; private Boolean fileExists; private File file; private static final int MY_PERMISSIONS_REQUEST_CALL= 20; public ContactAdapter(Activity context, List<Contact> contactList) { this.contactList = contactList; this.mContext = context; } @Override public ContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout,null); ContactHolder mh = new ContactHolder(v); return mh; } @Override public void onBindViewHolder(final ContactHolder contactHolder, int i) { final Contact contact = contactList.get(i); // Log.e("Imagename",""+"http://xesoftwares.co.in/contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg");//+feedItem.getThumbnail()); Target target = new Target() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { // your code here ... bitmap = Bitmap.createScaledBitmap(bitmap,(int)(bitmap.getWidth()*0.8), (int)(bitmap.getHeight()*0.8), true); contactHolder.thumbnail.setImageBitmap(bitmap); Log.e("ProfileImage", contact.getmProfileImage()); SaveImages(bitmap, contact.getmProfileImage()); } @Override public void onBitmapFailed(Drawable errorDrawable) { contactHolder.thumbnail.setImageDrawable(errorDrawable); // do error handling as required } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { contactHolder.thumbnail.setImageDrawable(placeHolderDrawable); } }; contactHolder.thumbnail.setTag(target); String url = ServiceUrl.getBaseUrl() + ServiceUrl.getImageUserUrl() + contact.getmProfileImage(); Log.e("url",url); if(contact.getmProfileImage().equals("")) { file = new File(""); fileExists = file.exists(); contactHolder.thumbnail.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_account_circle_black_48dp)); } else { file = new File(Environment.getExternalStorageDirectory() + "/ContactProfileImages/" + contact.getmProfileImage()); fileExists = file.exists(); } if(fileExists) { Log.e("fileExists",file.getAbsolutePath()); BitmapFactory.Options bmOptions = new BitmapFactory.Options(); Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(), bmOptions); contactHolder.thumbnail.setImageBitmap(bitmap); } else { Log.e("Picasso",file.getAbsolutePath()); Picasso.with(mContext).load(url) .error(R.drawable.ic_account_circle_black_24dp) .placeholder(R.drawable.ic_account_circle_black_24dp) .into(target); } contactHolder.title.setText(contact.getmUserName()); //feedListRowHolder.genre.setText(Html.fromHtml(feedItem.getGenre())); } @Override public int getItemCount() { return (null != contactList ? contactList.size() : 0); } public void SaveImages(Bitmap bitmap,String profileName) { try { String root = Environment.getExternalStorageDirectory().getPath(); File myDir = new File(root +"/ContactProfileImages"); if (!myDir.exists()) { myDir.mkdirs(); } // String name = new Date().toString();= String name = profileName; File myDir1 = new File(myDir, name); if(!myDir1.exists()) { FileOutputStream out = new FileOutputStream(myDir1); bitmap.compress(Bitmap.CompressFormat.PNG,100,out); out.flush(); out.close(); } } catch(Exception e){ // some action } //myDir1= imageFilePath1.getprofile(); } public class ContactHolder extends RecyclerView.ViewHolder implements View.OnClickListener { protected CircleImageView thumbnail; protected TextView title; public ContactHolder(View view) { super(view); this.thumbnail = (CircleImageView) view.findViewById(R.id.thumbnail); this.title = (TextView) view.findViewById(R.id.title); view.setOnClickListener(this); } @Override public void onClick(View v) { final Contact contact = contactList.get(getAdapterPosition()); final Dialog dialog = new Dialog(mContext); dialog.setCanceledOnTouchOutside(true); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.custom); final Window window = dialog.getWindow(); WindowManager.LayoutParams wlp =window.getAttributes(); wlp.gravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP; wlp.y=320; window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); window.setAttributes(wlp); // set the custom dialog components - text, image and button TextView txtusername = (TextView) dialog.findViewById(R.id.txtusername); TextView txtmobile = (TextView) dialog.findViewById(R.id.txtmobile); TextView txtemail = (TextView) dialog.findViewById(R.id.txtemail); txtusername.setText(contact.getmUserName()); txtemail.setText(contact.getmEmailId()); txtmobile.setText(contact.getmMobileNo()); SquareImageView image = (SquareImageView) dialog.findViewById(R.id.image); ImageView image1 = (ImageView) dialog.findViewById(R.id.image1); ImageView image2 = (ImageView) dialog.findViewById(R.id.image2); ImageView image3 = (ImageView) dialog.findViewById(R.id.image3); if(contact.getmProfileImage().equals("")) { image.setImageDrawable(ContextCompat.getDrawable(mContext,R.drawable.profile_icon)); } else { File file = new File(Environment.getExternalStorageDirectory() + "/ContactProfileImages/" + contact.getmProfileImage()); BitmapFactory.Options bmOptions = new BitmapFactory.Options(); Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(), bmOptions); image.setImageBitmap(bitmap); } image1.setImageResource(R.drawable.ic_call_black_24dp); image2.setImageResource(R.drawable.ic_textsms_black_24dp); image3.setImageResource(R.drawable.ic_email_black_24dp); image2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Uri sms_uri = Uri.parse("smsto:" + contact.getmMobileNo()); Intent sms_intent = new Intent(Intent.ACTION_SENDTO, sms_uri); mContext.startActivity(sms_intent); dialog.dismiss(); } }); image1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + contact.getmMobileNo())); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); mContext.startActivity(intent); dialog.dismiss(); } }); image3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent email = new Intent(Intent.ACTION_SEND); email.putExtra(Intent.EXTRA_EMAIL, new String[]{contact.getmEmailId()}); email.setType("message/rfc822"); mContext.startActivity(Intent.createChooser(email, "Choose an Email client :")); } }); Button dialogButton = (Button) dialog.findViewById(R.id.dialogButtonOK); // if button is clicked, view all information custom dialog dialogButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ((MainActivity)mContext).finish(); Intent intent = new Intent(mContext,DetailViewActivity.class); intent.putExtra("contact",contact); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); mContext.startActivity(intent); dialog.dismiss(); } }); dialog.show(); } } } 

EDIT: Busqué el mismo problema con la biblioteca picasso, cuando cargamos imágenes desde el servidor, por esto conseguí la solución de SO como:

  recyclerView.setHasFixedSize(true); recyclerView.setItemViewCacheSize(20); recyclerView.setDrawingCacheEnabled(true); recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); 

Y esto funcionó cuando estoy cargando las imágenes desde el servidor, pero cuando estoy cargando las imágenes desde el almacenamiento externo todavía el problema existe.

¿Puede alguien ayudar con esto, por favor? Gracias..

Luego Carga de las imágenes desde el almacenamiento externo. Puedo ver las imágenes cargadas, pero como me desplazo puedo ver algunas imágenes durante un segundo o dos, entonces desaparecen y puedo ver el icono de la imagen por defecto.

Esto es porque usted está utilizando Callback de destino en picasso. Y las devoluciones de llamada se llaman poco tarde cuando se desplaza la lista. Sólo tienes que quitar el objetivo y utilizar la imagen en Picasso, debe funcionar bien. Además, no es necesario almacenar en caché los mapas de bits por su cuenta, ya que Picasso lo hace por usted.

 @Override public void onBindViewHolder(final ContactHolder contactHolder, int i) { final Contact contact = contactList.get(i); // Log.e("Imagename",""+"http://xesoftwares.co.in/contactsapi/profile_images/85368a5bbd6cffba8a3aa202a80563a2.jpg");//+feedItem.getThumbnail()); String url = ServiceUrl.getBaseUrl() + ServiceUrl.getImageUserUrl() + contact.getmProfileImage(); Log.e("url",url); if(contact.getmProfileImage().equals("")) { file = new File(""); fileExists = file.exists(); contactHolder.thumbnail.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_account_circle_black_48dp)); } else { file = new File(Environment.getExternalStorageDirectory() + "/ContactProfileImages/" + contact.getmProfileImage()); fileExists = file.exists(); } Log.e("Picasso",file.getAbsolutePath()); Picasso.with(mContext).load(url) .error(R.drawable.ic_account_circle_black_24dp) .placeholder(R.drawable.ic_account_circle_black_24dp) .into(contactHolder.thumbnail); contactHolder.title.setText(contact.getmUserName()); //feedListRowHolder.genre.setText(Html.fromHtml(feedItem.getGenre())); } 

Utilice este código en su clase de aplicación para aplicar la configuración en la aplicación completa.

  final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // Use 1/8th of the available memory for this memory cache. final int cacheSize = maxMemory / 8; Picasso.Builder builder = new Picasso.Builder(getApplicationContext()); builder.memoryCache(new LruCache(cacheSize)); Picasso built = builder.build(); built.setIndicatorsEnabled(true);// it will show indicator where it downloaded from built.setLoggingEnabled(false); Picasso.setSingletonInstance(built); 

Ahora pasar la url a Picasso para cargarlo para ver. Si se trata de gran imagen que puede cambiar el tamaño de la imagen también para una carga más rápida.

  Picasso.with(mContext).load(url) .error(R.drawable.on_error) .placeholder(R.drawable.place_holder) //.resize(custom_width,custom_height) put custom_height to 0 if you want to maintain aspect ratio .into(your_view); 

Puedo confundir, pero su problema podría ser causado por que usted utiliza el Contact que usted consiguió de su conjunto de datos por la posición de la disposición , pero puesto que usted lo utiliza asincrónicamente en la onBitmapLoaded llamada de onBitmapLoaded , la posición podría ya ser cambiado en ese momento. Así que todo lo que necesitas es usar la posición del adaptador de la siguiente manera:

 @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { // your code here ... Contact c = contactList.get(contactHolder.getAdapterPosition()); bitmap = Bitmap.createScaledBitmap(bitmap,(int)(bitmap.getWidth()*0.8), (int)(bitmap.getHeight()*0.8), true); contactHolder.thumbnail.setImageBitmap(bitmap); Log.e("ProfileImage", c.getmProfileImage()); SaveImages(bitmap, c.getmProfileImage()); } 

No estoy seguro de que sería útil, pero vamos a intentar, y espero que sea 🙂

Si desea simplemente cargar la imagen, entonces por qué necesita almacenar en el almacenamiento externo. Si tiene que almacenar para cualquier otro propósito, luego almacenarlo, pero cuando se muestra en el ImageView, por favor, utilice cualquier api de terceros como Picasso o Universal Image Loader hace carga perezosa y también hace todo tipo de gestión de memoria caché también provies muchas fasality de visualización.

Espero que esto te ayudará

Operaciones como cargar imágenes deben realizarse utilizando AsyncTask en un subproceso de fondo.

  • Compruebe cada imagen cuánto MB es. Por ejemplo: Si la imagen es de 1 MB o 500 KB, tardará más tiempo en descargar imágenes en segundo plano y después de descargarlo se guardará en catche. Eso significa que por primera vez sólo tomará algún tiempo para descargar la imagen.

  • En la segunda vez, esas imágenes de catche.It mostrará todas las imágenes en la fracción de segundos.

  • Utilice Volley – para más rápido y Glide – para la gestión de memoria.

     Glide.with(context).load(rowItem.getPosteduserpostimage()).asBitmap().diskCacheStrategy(DiskCacheStrategy.SOURCE).fitCenter() .placeholder(R.drawable.load_image).error(R.drawable.cancel_image).into(holder.ivPostedImageNew); 
  • Consulte aquí cómo cargar un mapa de bits de gran tamaño. Necesita reducir la imagen.

  • De lo contrario, Cuando estoy subiendo todas las imágenes, hice recorte utilizando library.It se encargará de reducir el mapa de bits de gran tamaño. Por ejemplo: las imágenes de 5mb serán reducidas a 180 kb.

  • Compruebe este CropImage lib para escalar abajo de las imágenes más grandes del tamaño. Incluso si el usuario no recorta la imagen, apenas selecciona la porción entera al cosechar, él bajará 5 mb a la calidad 180kb.Image también bueno.

Creo que sin recorte también se puede utilizar el código a continuación para reducir la imagen. Puede ver este código en que:

  private void startCropImage() { Intent intent = new Intent(this, CropImage.class); intent.putExtra(CropImage.IMAGE_PATH, mFileTemp.getPath()); intent.putExtra(CropImage.SCALE, true); intent.putExtra(CropImage.ASPECT_X, 0); //3 for aspect ratio intent.putExtra(CropImage.ASPECT_Y, 0); //2 for aspect ratio startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE); } 
  • Y también no utilice la vista de desplazamiento anidada dentro de recyclerview.
  • Cómo hacer la primera imagen más grande en Gridlayout?
  • Android Recyclerview GridLayoutManager espaciamiento de columnas
  • El más correctamente para guardar el estado de RecyclerView?
  • Problema de desplazamiento Infinito Infinito de RecyclerView
  • La forma más sencilla de mostrar Cuerdas con iconos en un RecyclerView
  • RecyclerView con CollapsingToolbarLayout se desplaza mal cuando se lanza
  • Cómo utilizar RecyclerView.scrollToPosition () para mover la posición a la parte superior de la vista actual?
  • Pantalla Android Parpadea en mostrar / ocultar barras del sistema
  • La creación de clase Pojo desde el cursor Sqlite está tomando demasiado tiempo
  • Android studio: gradle error de dependencia
  • ¿Cómo agregar un simple encabezado 8dp / pie de página a RecyclerView de Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.