RecyclerView onCreateViewHolder llamado excesivamente cuando se desplaza rápidamente con DPAD

Estoy desarrollando en Amazon Fire TV.

Debido a que es una aplicación de TV (sin toque), necesito focusables dentro de la disposición de la fila para poder navegar alrededor.

Tengo un Recyclerview muy simple con la imagen, el texto, y un focusable. Cuando presiono hacia arriba o hacia abajo, todo se desplaza y las cosas correctamente, pero me di cuenta de que cuando navego más rápido de desplazamiento puede mantener, crea nuevos espectadores (fuera de pantalla) y retrasa la interfaz de usuario.

He creado una actividad con números de Creación en él. Cuando me desplazo lentamente, la mayor creación # es 10. Pero cuando me desplazo rápido, consigo tarjetas con la creación número 60 en un segundo. Esto causa un retraso enorme y la aplicación deja caer una gran cantidad de marcos. ¿Es mi enfoque totalmente equivocado?

Utilice el siguiente código para probar esto.

 /** * Created by sylversphere on 15-04-15. */ public class LandfillActivity extends Activity{ private Context context; private static int ticketNumber; private static int getTicket(){ ticketNumber ++; return ticketNumber; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); context = this; setContentView(R.layout.landfill_activity); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); GridLayoutManager glm = new GridLayoutManager(context, 2); recyclerView.setLayoutManager(glm); SickAdapter sickAdapter = new SickAdapter(); recyclerView.setAdapter(sickAdapter); } public class SickViewHolder extends RecyclerView.ViewHolder{ TextView ticketDisplayer; public ImageView imageView; public SickViewHolder(View itemView) { super(itemView); ticketDisplayer = (TextView) itemView.findViewById(R.id.ticketDisplayer); imageView = (ImageView) itemView.findViewById(R.id.imageView); itemView.findViewById(R.id.focus_glass).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { context.startActivity(new Intent(context, LouisVuittonActivity.class)); } }); } public void setTicket(int value){ ticketDisplayer.setText(""+value); } } public class SickAdapter extends RecyclerView.Adapter<SickViewHolder>{ @Override public SickViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { SickViewHolder svh = new SickViewHolder(getLayoutInflater().inflate(R.layout.one_row_element, null)); svh.setTicket(getTicket()); return svh; } @Override public void onBindViewHolder(SickViewHolder holder, int position) { String[] image_url_array = getResources().getStringArray(R.array.test_image_urls); Picasso.with(context).load(image_url_array[position % image_url_array.length] ).fit().centerCrop().into(holder.imageView); } @Override public int getItemCount() { return 100000; } } } 

One_row_element.xml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <FrameLayout android:layout_width="match_parent" android:layout_height="200dp" android:orientation="horizontal"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:scaleType="centerCrop" android:src="@mipmap/sick_view_row_bg" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|center_vertical" android:layout_marginLeft="15dp" android:orientation="horizontal"> <TextView android:id="@+id/virusTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Creation #" android:textColor="#fff" android:textSize="40sp" /> <TextView android:id="@+id/ticketDisplayer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1" android:textColor="#fff" android:textSize="40sp" /> </LinearLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/focus_glass" android:background="@drawable/subtle_focus_glass" android:focusable="true" android:focusableInTouchMode="true"/> </FrameLayout> </FrameLayout> 

Test_image_urls.xml (Urls no es propiedad de mí)

 <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="test_image_urls" formatted="false"> <item>http://farm4.static.flickr.com/3175/2737866473_7958dc8760.jpg</item> <item>http://farm4.static.flickr.com/3276/2875184020_9944005d0d.jpg</item> <item>http://farm3.static.flickr.com/2531/4094333885_e8462a8338.jpg</item> <item>http://farm4.static.flickr.com/3289/2809605169_8efe2b8f27.jpg</item> <item>http://2.bp.blogspot.com/_SrRTF97Kbfo/SUqT9y-qTVI/AAAAAAAABmg/saRXhruwS6M/s400/bARADEI.jpg</item> <item>http://fortunaweb.com.ar/wp-content/uploads/2009/10/Caroline-Atkinson-FMI.jpg</item> <item>http://farm4.static.flickr.com/3488/4051378654_238ca94313.jpg</item> <item>http://farm4.static.flickr.com/3368/3198142470_6eb0be5f32.jpg</item> <item>http://www.powercai.net/Photo/UploadPhotos/200503/20050307172201492.jpg</item> <item>http://www.web07.cn/uploads/Photo/c101122/12Z3Y54RZ-22027.jpg</item> <item>http://www.mitravel.com.tw/html/asia/2011/Palau-4/index_clip_image002_0000.jpg</item> <item>http://news.xinhuanet.com/mil/2007-05/19/xinsrc_36205041914150623191153.jpg</item> <item>http://ib.berkeley.edu/labs/koehl/images/hannah.jpg</item> <item>http://down.tutu001.com/d/file/20110307/ef7937c2b70bfc2da539eea9df_560.jpg</item> <item>http://farm3.static.flickr.com/2278/2300491905_5272f77e56.jpg</item> <item>http://www.pic35.com/uploads/allimg/100526/1-100526224U1.jpg</item> <item>http://img.99118.com/Big2/1024768/20101211/1700013.jpg</item> <item>http://farm1.static.flickr.com/45/139488995_bd06578562.jpg</item> </string-array> </resources> 

Enfoque sutil

  <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:drawable="@color/glass_focus"/> <item android:drawable="@color/glass_normal"/> </selector> 

glass_normal es #9000

glass_focus es #0000

Intente aumentar el número máximo de vistas recicladas en la agrupación:

 recyclerView.getRecycledViewPool().setMaxRecycledViews(50); 

50 es un número arbitrario, puedes probar más o menos y ver qué pasa.

RecyclerView intenta evitar volver a usar las vistas que tienen un estado transitorio , por lo que si las vistas se invalidan rápidamente o se animan, es posible que no se vuelvan a utilizar de inmediato.

Del mismo modo, si tiene muchas vistas más pequeñas, puede terminar con más en la pantalla que el tamaño de grupo predeterminado puede manejar (más común con la cuadrícula como diseños).

Picasso es la celebración de usted, pero la solución sugerida para construir su propio mecanismo no es el camino a seguir.

Picasso se ha quedado atrás en el último año y hoy hay alternativas mucho mejores en forma de Google Glide y Facebook Fresco que específicamente lanzó actualizaciones para trabajar mejor con RecyclerView y han demostrado ser más rápido y más eficiente en la carga, almacenamiento en memoria caché y almacenamiento en muchos Pruebas disponibles en línea tales como:

Espero que ayudó. Buena suerte.

Como los comentaristas señalaron las respuestas pendientes de Picasso podría ser la celebración de usted. Si ese es el caso, puede solucionarlo extendiendo ImageView y reemplazando el siguiente método. Creo que vale la pena intentarlo.

 @Override protected void onDetachedFromWindow() { Picasso.with(context).cancelRequest(this); super.onDetachedFromWindow(); } 

Actualizar:

Resulta que esta no es la forma correcta, cualquier persona que desee cancelar las solicitudes debe hacerlo en la devolución de llamada onViewRecycled() como se señala en los comentarios a continuación.

Para cualquiera que esté buscando un hack rápido, haz esto. Esto retrasará la selección hasta que se haya inflado y seleccionado. No sé cómo, pero funciona. Solo devuelve null en onFocusSearchFailed.

  /** * Created by sylversphere on 15-04-22. */ public class SomeGridLayoutManager extends GridLayoutManager{ private final Context context; public SomeGridLayoutManager(Context context, int spanCount) { super(context, spanCount); this.context = context; } public SomeGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); this.context = context; } @Override public View onFocusSearchFailed(View focused, int focusDirection, RecyclerView.Recycler recycler, RecyclerView.State state) { return null; } } 
  • Android: cómo manejar el botón de clic
  • Problema al analizar JSON
  • Android: CountDownTimer salta el último onTick ()!
  • ¿Deshacer / rehacer rápidamente con el patrón del memento / comando?
  • Java MTP biblioteca que funciona en Windows
  • Andengine FPS bajo en ciertos teléfonos
  • LibGDX Actriz
  • API de calendario de Android insertar evento recurrente
  • Java.net.ConnectException: no se conectó a localhost / 127.0.0.1 (puerto 9090): falló conexión: ECONNREFUSED (Connection refused)
  • "Aapt" IOException error = 2, No hay tal archivo o directorio "¿por qué no puedo construir mi gradle en jenkins?
  • Separar horas de minutos en un valor de tiempo dado
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.