1
votes

RecyclerView défilement laggy sur les nouvelles versions d'Android

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 commentaires

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?


3 Réponses :


2
votes

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


0 commentaires

3
votes

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.

  • Puisque vous n'avez qu'un seul itme à l'intérieur, vous pouvez simplement vous débarrasser du wrapper et ne conserver qu'un seul TextView comme élément racine
  • Si vous souhaitez toujours obtenir un wrapper pour la vue - essayez d'éviter wrap_content pour RelativeLayout et / ou ConstrainLayout , utilisez une taille de correction ou des mises en page simples telles que Frame / Linear .

0 commentaires

1
votes

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.


0 commentaires