Что вызывает мою плохую производительность прокрутки в RecyclerView? - PullRequest
1 голос
/ 17 апреля 2019

У меня проблемы с оптимизацией моего RecyclerView. Когда я запускаю приложение в холодном режиме, первая прокрутка всегда дергается.

Я следил за этим , но это не помогло, так как я не уверен, что вызывает отставание.

Вот содержимое моего RecyclerView (list_item.xml):

<android.support.v7.widget.CardView 
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/card_view"
android:layout_width="match_parent"
android:layout_height="86dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp">

<android.support.constraint.ConstraintLayout
    android:id="@+id/list_item_constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/selectableItemBackground">

    <TextView
        android:id="@+id/list_item_akcija_ime"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:ellipsize="marquee"
        android:fontFamily="sans-serif"
        android:singleLine="true"
        android:text="@string/ime_akcije"
        android:textColor="@color/common_google_signin_btn_text_dark_focused"
        android:textSize="18sp"
        app:layout_constraintEnd_toStartOf="@+id/list_item_eye"
        app:layout_constraintStart_toEndOf="@+id/list_item_slika"
        app:layout_constraintTop_toTopOf="@+id/list_item_slika" />

    <TextView
        android:id="@+id/list_item_akcija_datum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="sans-serif"
        android:text="@string/_1_7_2019"
        android:textSize="12sp"
        app:layout_constraintStart_toStartOf="@+id/list_item_akcija_ime"
        app:layout_constraintTop_toBottomOf="@+id/list_item_akcija_ime" />

    <ImageView
        android:id="@+id/list_item_slika"
        android:layout_width="110dp"
        android:layout_height="70dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:adjustViewBounds="true"
        android:contentDescription="@string/slika_akcije"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/list_item_starosti_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/list_item_slika"
        app:layout_constraintStart_toStartOf="@+id/list_item_akcija_ime" />

    <ImageView
        android:id="@+id/list_item_fire"
        android:layout_width="21dp"
        android:layout_height="22dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:contentDescription="@string/fire"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/list_item_fires"
        app:layout_constraintTop_toBottomOf="@+id/list_item_eye"
        app:srcCompat="@drawable/campfire" />

    <ImageView
        android:id="@+id/list_item_eye"
        android:layout_width="21dp"
        android:layout_height="22dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:contentDescription="@string/eye"
        app:layout_constraintBottom_toTopOf="@+id/list_item_fire"
        app:layout_constraintEnd_toStartOf="@+id/list_item_clicks"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="packed"
        app:srcCompat="@drawable/eye" />

    <TextView
        android:id="@+id/list_item_clicks"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="@+id/list_item_eye"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/list_item_eye"
        tools:text="159" />

    <TextView
        android:id="@+id/list_item_fires"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="60"
        android:textColor="@color/colorAccent"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="@+id/list_item_fire"
        app:layout_constraintStart_toStartOf="@+id/list_item_clicks"
        app:layout_constraintTop_toBottomOf="@+id/list_item_eye" />

</android.support.constraint.ConstraintLayout>

Это то, что я делаю в onBindViewHolder

@Override
public void onBindViewHolder(@NonNull AkcijaViewHolder akcija, int i) {
    akcija.bindData(akcije.get(i), mOnItemClickListener, context); 
}

Мой метод bindData довольно дорогой, но если я прав, это не должно повлиять на производительность?

public void bindData(final Akcija akcija, final AkcijaAdapter.OnItemClickListener onItemClickListener, Context context) {

    /* Set Akcija's ime to the TextView */
    imeTextView.setText(akcija.getIme());
    imeTextView.setSelected(true);

    /* Set date and show it */
    Date date = new Date(akcija.getDatum() * 1000);
    DateFormat dateFormat = new SimpleDateFormat("d. M. yyyy", Locale.getDefault()); // Format for 13. 4. 2019
    String strDate = dateFormat.format(date);
    datumTextView.setText(strDate);

    /* Set clicks */
    klikTextView.setText(String.valueOf(akcija.getClicks()));

    /* Draw starosti circle_mc images */
    String starosti = akcija.getStarost(); // get starosti...
    String[] starostiArr = starosti.split(" "); // and split them into strings

    linearLayout.removeAllViews();
    for (String starost : starostiArr) { // loop through all starosti. For each starost draw it by calling drawStarostSlika and pass in the drawable of circle
        switch (starost) {
            case "M":
                drawStarostSlika(R.drawable.circle_mu);
                break;
            case "MČ":
                drawStarostSlika(R.drawable.circle_mc);
                break;
            case "GG":
                drawStarostSlika(R.drawable.circle_gg);
                break;
            case "PP":
                drawStarostSlika(R.drawable.circle_pp);
                break;
            case "RR":
                drawStarostSlika(R.drawable.circle_rr);
                break;
            case "G":
                drawStarostSlika(R.drawable.circle_gr);
                break;
            default:
                break;
        }
    }

    /* Load image into slikaImageView from Firebase Storage */
    GlideApp.with(context)
            .load(storageReference.child(akcija.getIme() + ".jpg"))
            .thumbnail(0.5f)
            .transition(DrawableTransitionOptions.withCrossFade())
            .diskCacheStrategy(DiskCacheStrategy.DATA)
            .into(slikaImageView);


    /* Make each item clickable. On click, run the method passed in to adapter from anywhere. */
    listItemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onItemClickListener.onItemClick(akcija, v);
        }
    });
}

Так я заполняю RecyclerView

private DatabaseReference mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("akcije"); 
private StorageReference storageReference = FirebaseStorage.getInstance().getReference();

List<Akcija> akcije = new ArrayList<>();
AkcijaAdapter adapter;
RecyclerView recyclerView;

Context context; 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    context = MainActivity.this;



    mDatabaseReference.addValueEventListener(valueEventListener); // set listener for the method defined below

    adapter = new AkcijaAdapter(context, akcije, onItemClickListener); // for now, add empty akcija's so the list is not skipped
    recyclerView = findViewById(R.id.list);
    recyclerView.setHasFixedSize(true); 
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(context)); 
}

/* When Firebase's databases changes update the recycler view */
ValueEventListener valueEventListener = new ValueEventListener() {

    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot ds : dataSnapshot.getChildren()) {
            akcije.add(new Akcija(
                    ds.getKey(), // the key is the same as Akcija's name
                    ds.child("datum").getValue(Long.class), // milliseconds since 1970
                    ds.child("starost").getValue().toString(),
                    ds.child("link").getValue().toString(),
                    ds.child("klik").getValue(Integer.class)
            ));
        }

        /* Sort akcija's by date */
        Collections.sort(akcije, new Comparator<Akcija>() {
            @Override
            public int compare(Akcija o1, Akcija o2) {
                return o2.getDatum().compareTo(o1.getDatum());
            }
        });

        adapter = new AkcijaAdapter(context, akcije, onItemClickListener); // update the list and
        recyclerView.setAdapter(adapter); // set the adapter
        mDatabaseReference.removeEventListener(this); // only update the app when it's ran
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
};


AkcijaAdapter.OnItemClickListener onItemClickListener = new AkcijaAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(Akcija akcija, View listItemView) {
    // do stuff here
    }
};

}

Я также думал, что использование ConstraintLayout было оптимальным, но я не знаю, слишком ли дорог мой list_item?

1 Ответ

0 голосов
/ 17 апреля 2019

Наиболее вероятная причина, по которой вы получаете эти лаги, заключается в том, что каждый раз, когда вы получаете новые данные из вашей базы данных, вы устанавливаете новый адаптер для RecyclerView.

Попробуйте использовать ListAdapter вместо RecyclerView.Adapter, поскольку он также более функциональный, реагируя на изменения. С этим адаптером вы установите его в свой RecyclerView только один раз, а затем каждый раз, когда вы получаете новые данные, вы должны вызывать что-то вроде adapter.submitList(myNewData);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...