reciclerview GridLayoutManager very slow

2.4k views Asked by At

after thinking a lot about the documentation,I decided to share my code and problem. I have a disposition of view that is my next. Item_grid.xml

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"

android:background="@color/blanco"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="0dp"
card_view:cardUseCompatPadding="true">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"

    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/trlDiaNombre"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/naranjaffb973"
        android:minHeight="30dp"
        android:visibility="visible">

        <TextView
            android:id="@+id/txtADPDiaNombre"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:gravity="center"
            android:singleLine="true"
            android:text="DIA"
            android:textColor="@color/blanco"
            android:textSize="14sp"
            android:textStyle="bold" />


    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rtlDiaNumero"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:minHeight="40dp">

        <TextView
            android:id="@+id/txtADPDiaNumero"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="6"
            android:textColor="@color/morao_moraito_8C008C"
            android:textSize="18sp" />


    </RelativeLayout>

</LinearLayout>

</android.support.v7.widget.CardView> It is simple two Textviews.

it is adapter This is the adapter that inflated view adapter.java

public class CustomAdapterListadoFechasRCV
    extends
    RecyclerView.Adapter<CustomAdapterListadoFechasRCV.ElementosLinea> {

private ArrayList<Cdia> mDataset;

private AfrmProgramaControl afrmGes;


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ElementosLinea extends RecyclerView.ViewHolder {
    // each data item is just a string in this case

    TextView txtNombre;
    TextView txtNumero;
    RelativeLayout rtlNombre;
    RelativeLayout rtlNumero;
    // CardView card;

    public ElementosLinea(View v) {
        super(v);
        ArrayList<CUtilsTipografia.CtipoGraf> lstTipograf = new ArrayList<CUtilsTipografia.CtipoGraf>();
        // card = (CardView) v.findViewById(R.id.card);
        txtNombre = (TextView) v.findViewById(R.id.txtADPDiaNombre);
        txtNumero = (TextView) v.findViewById(R.id.txtADPDiaNumero);
        rtlNombre = (RelativeLayout) v.findViewById(R.id.trlDiaNombre);
        rtlNumero = (RelativeLayout) v.findViewById(R.id.rtlDiaNumero);
        lstTipograf.add(new CUtilsTipografia.CtipoGraf(txtNombre, 0, 1));
        lstTipograf.add(new CUtilsTipografia.CtipoGraf(txtNumero, 0, 0));
        CUtilsTipografia.setTypefaces(afrmGes.getActivity(), lstTipograf);

    }

}

public void add(int position, Cdia item) {
    mDataset.add(position, item);
    notifyItemInserted(position);
}

public void remove(Cdia item) {
    int position = mDataset.indexOf(item);
    mDataset.remove(position);
    notifyItemRemoved(position);


}


// Provide a suitable constructor (depends on the kind of dataset)
public CustomAdapterListadoFechasRCV(
        ArrayList<Cdia> myDataset, AfrmProgramaControl afrm) {
    mDataset = myDataset;
    afrmGes = afrm;
}

// Create new views (invoked by the layout manager)
@Override
public ElementosLinea onCreateViewHolder(
        ViewGroup parent, int viewType) {
    // create a new view
    View v = LayoutInflater.from(parent.getContext()).inflate(
            R.layout.ll_adapter_listado_fechas, parent, false);
    // set the view's size, margins, paddings and layout parameters
    ElementosLinea vh = new ElementosLinea(v);
    return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ElementosLinea holder, final int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    final Cdia datossss = mDataset.get(position);

    if (datossss != null) {


        if (datossss.getDia() == -1) {//s
            holder.rtlNombre.setVisibility(View.VISIBLE);
            holder.rtlNumero.setVisibility(View.GONE);
            holder.txtNombre.setText(datossss.getNombreDia());

        } else {
            holder.rtlNombre.setVisibility(View.GONE);
            holder.rtlNumero.setVisibility(View.VISIBLE);
            if (datossss.getDia() != 0) {

                if (datossss.getMarcado() == 1) {
                    holder.txtNumero.setTextColor(afrmGes.getResources().getColor(R.color.marcacalendarioff4000));
                } else {
                    holder.txtNumero.setTextColor(afrmGes.getResources().getColor(R.color.grisclarod8d8d8));
                }

                holder.txtNumero.setText(String.valueOf(datossss.getDia()));
            } else {
                holder.txtNumero.setText("");
            }


        }


        //


    }


    holder.rtlNumero.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Cdia dia = mDataset.get(position);
            afrmGes.cargarProgramaDia(dia);
        }
    });

}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    return mDataset.size();
}

}

as you can see, my adapter only needs a list of days Cdia.java

public class Cdia {


private int _iDia;
private String _sNombreDia;
private int _iMarcado;
private int _iMes;


public Cdia() {
    _iDia = 0;
    _sNombreDia = "";
    _iMarcado = 0;
    _iMes =0;
}


public int getDia() {
    return _iDia;
}

public void setDia(int _iDia) {
    this._iDia = _iDia;
}

public String getNombreDia() {
    return _sNombreDia;
}

public void setNombreDia(String _sNombreDia) {
    this._sNombreDia = _sNombreDia;
}


public int getMarcado() {
    return _iMarcado;
}

public void setMarcado(int _iMarcado) {
    this._iMarcado = _iMarcado;
}


public int getMes() {
    return _iMes;
}

public void setMes(int _iMes) {
    this._iMes = _iMes;
}

Once everything is ready, I explain my problem this dispodicion of gridLayoutManages is divided into seven columns, with this I generate two months with corresponding calendar days for each column as follows. enter image description here

Since becoming the adapter to the list of data until it pint in pantalls passes too long, over 4 seconds .this is how full my adapter.

enter image description here

I failed to find a solution to my problem of loading speed someone could give me light in my path of darkness about it? Thanks.

UPDATE for cooment :

public class GridViewReciclerObservable extends ObservableRecyclerView {

//para ponerle el tipo linear
private GridLayoutManagerCustom mLayoutManager;

private int _iColumnas = 7;

public GridViewReciclerObservable(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    mLayoutManager = new GridLayoutManagerCustom(getContext(), _iColumnas);
    setLayoutManager(mLayoutManager);
    LayoutParams par = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    setLayoutParams(par);

}


public GridViewReciclerObservable(Context context, AttributeSet attrs) {
    super(context, attrs);
    mLayoutManager = new GridLayoutManagerCustom(getContext(), _iColumnas);
    setLayoutManager(mLayoutManager);
    LayoutParams par = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    setLayoutParams(par);
    // TODO Auto-generated constructor stub
}

public GridViewReciclerObservable(Context context) {
    super(context);
    mLayoutManager = new GridLayoutManagerCustom(getContext(), _iColumnas);
    setLayoutManager(mLayoutManager);
    LayoutParams par = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    setLayoutParams(par);
    // TODO Auto-generated constructor stub
}

}

VIEWPARENT

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/blanco">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">


        <TextView
            android:id="@+id/txtMesEnCurso"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="New Text"
            android:layout_margin="5dp"
            android:textSize="25sp"
            android:textColor="@color/gris444444">


        </TextView>

        <com.jesusdelarosainfante.herramientas.view.GridViewReciclerObservable
            android:id="@+id/rcvGCalen"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="5dp"
            android:scrollbars="vertical" />


    </LinearLayout>

</RelativeLayout>
2

There are 2 answers

3
ThaiPD On

In your xml file, try to change value of attribute from wrap_content to fixed value or match_parent because of every time the view is init or reuse, if value of heigh/width is wrap_content that means OS always calculates to get the best size and it take a lot of performance. You can put a log in onMeasure() to see it.

1
marmor On

I can see a number of ways to improve the performance of you code, but those won't cut 4 full seconds.

I'm guessing most of the performance issue if from getting myDataset from your Database (or however you're getting your data).

Try measuring specific parts of you code to better understand what exactly is taking so long. you can measure by adding:

long before = System.currentTimeMillis();

before some block of code, and:

long after = System.currentTimeMillis();

after it, and then print how long it took in milliseconds: (after - before)

Anyway, the stuff you could improve in your code (but probably won't make much of a difference):

  1. Get the LayoutInflater only once in the constructor of the adapter, and store it to a member.
  2. re-use the same OnClickListener instead of creating new objects on your bind method, you can then decide which action to take by checking the view passed to the OnClick method.