Mon RecyclerView
est assez lent chaque fois que je commence à faire défiler les premiers éléments dans un démarrage à froid de l'application. Ce comportement se produit pour les dernières versions d'Android (testées sur les niveaux API 27 et 28) mais pas pour les plus anciennes (testées sur les niveaux API 22).
J'ai essayé les deux versions, le normal com.android.support:appcompat- v7: 28.0.0
et androidx com.google.android.material:material:1.1.0-alpha03
.
Le projet de test est assez simple: p>
MainActivity.java
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:tools="http://schemas.android.com/tools"> <TextView android:id="@+id/item_tv" android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
activity_main.xml
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { List<String> mData; Context context; LayoutInflater mInflater; public MyAdapter(Context context, List<String> data) { this.mData = data; this.context = context; this.mInflater = LayoutInflater.from(context); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View view = mInflater.inflate(R.layout.recycler_item, viewGroup, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { viewHolder.tv.setText(String.valueOf(i)); } @Override public int getItemCount() { return mData.size(); } public String getItem(int id) { return mData.get(id); } public class ViewHolder extends RecyclerView.ViewHolder { TextView tv; public ViewHolder(@NonNull View itemView) { super(itemView); tv = itemView.findViewById(R.id.item_tv); } } }
MyAdapter.java
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
recycler_item.xml
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recyclerview); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setHasFixedSize(true); recyclerView.setItemViewCacheSize(20); ArrayList<String> list = new ArrayList<>(); for (int i = 0; i < 200; i++) { list.add(String.valueOf(i)); } MyAdapter adapter = new MyAdapter(MainActivity.this, list); recyclerView.setAdapter(adapter); } }
Des idées pour résoudre le problème ou s'agit-il d'un problème de bibliothèque qui ne peut pas être résolu par moi-même (en attendant nouvelle version officielle)?
3 Réponses :
obtenir layoutInflater
à partir du contexte parent donc au lieu de
LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, viewGroup, false);
utilisez ceci
mInflater.inflate(R.layout.recycler_item, viewGroup, false);
J'espère que cela vous aidera
Dans la mise en page de vos éléments, la classe wrapper est ConstraintLayout
avec wrap_content_height
- cela pourrait poser des problèmes lors de la mesure.
RelativeLayout
et / ou ConstrainLayout
, utilisez une taille de correction ou des mises en page simples telles que Frame / Linear . J'ai résolu le problème en définissant la variante de construction sur release après avoir trouvé ce commentaire: Performance de ConstraintLayout dans RecyclerView ViewHolder .
L'exemple partagé ici est alors fluide et mon application avec Glide fonctionne également plus facilement, même sans définir layout_width sur ConstraintLayout.
Mais je ne vois pas pourquoi ce décalage apparaît en mode débogage et uniquement sur les dernières versions d'Android.
Avez-vous essayé de supprimer setItemViewCacheSize et remarqué une différence?
Oui, je l'ai fait (également setHasFixedSize (true)) mais aucune différence. Dans le GPU Profiler, les barres atteignent le haut de l'écran (presque vert), plus tard, quand il est "chargé", il reste dans une zone de 16 ms.
des changements lorsque pas d’utiliser ConstraintLayout?