I have a ListView in which every row has some text and two ImageView: one is the same for every row, the other depends on the current item.
This is my adapter:
mArrayAdapter(Context context, int layoutResourceId, ArrayList<Exhibition>  data) {
    super(context, layoutResourceId, data);
    this.context = context;
    this.layoutResourceId = layoutResourceId;
    this.list = data;
    this.originalList = data;
    viewHolder = new ViewHolder();
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getByteCount() / 1024;
        }
    };
}
@Override
@NonNull
public View getView(final int position, View convertView, @NonNull final ViewGroup parent) {
    View row;
    final Exhibition ex;
    if(convertView==null){
        row = LayoutInflater.from(getContext()).inflate(R.layout.row,parent,false);
        viewHolder.expand = (ImageView)row.findViewById(R.id.expand);
        row.setTag(viewHolder);
    }
    else {
        row = convertView;
        viewHolder = (ViewHolder)row.getTag();
    }
    ex = list.get(position);
    descr = (TextView)row.findViewById(R.id.descr);
    ttl = (TextView)row.findViewById(R.id.title);
    city = (TextView)row.findViewById(R.id.city);
    dates = (TextView)row.findViewById(R.id.dates);
    museum = (TextView)row.findViewById(R.id.location);
    header = (ImageView)row.findViewById(R.id.hd);
    ttl.setText(ex.name);
    descr.setText(ex.longdescr);
    museum.setText(ex.museum);
    city.setText(ex.city);
    final Bitmap bitmap = getBitmapFromMemCache(ex.key);
    if (bitmap != null) {
        header.setImageBitmap(bitmap);
    } else {
        header.setImageBitmap(ex.getHeader());
        addBitmapToMemoryCache(ex.key,ex.header);
    }
    SimpleDateFormat myFormat = new SimpleDateFormat("dd/MM/yyyy", Locale.ITALY);
    Date start = new Date(ex.getStart()), end = new Date(ex.getEnd());
    String startEx = myFormat.format(start);
    String endEx = myFormat.format(end);
    String finalDate = getContext().getResources().getString(R.string.ex_date, startEx, endEx);
    dates.setText(finalDate);
    viewHolder.expand.setId(position);
    if(position == selectedId){
        descr.setVisibility(View.VISIBLE);
        ttl.setMaxLines(Integer.MAX_VALUE);
        dates.setMaxLines(Integer.MAX_VALUE);
        museum.setMaxLines(Integer.MAX_VALUE);
        city.setMaxLines(Integer.MAX_VALUE);
    }else{
        descr.setVisibility(View.GONE);
        ttl.setMaxLines(1);
        dates.setMaxLines(1);
        museum.setMaxLines(1);
        city.setMaxLines(1);
    }
    viewHolder.expand.setOnClickListener(this.onCustomClickListener);
    return row;
}
public void setDescr(int p){
    selectedId = p;
}
public void setOnCustomClickListener(final View.OnClickListener onClickListener) {
    this.onCustomClickListener = onClickListener;
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}
public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}
@Override
public int getCount()
{
    return list.size();
}
@Override
public boolean isEnabled(int position)
{
    return true;
}
@Override
public Exhibition getItem (int pos){
    return list.get(pos);
}
void resetData() {
    list = originalList;
}
private class ViewHolder {
    ImageView expand,header;
}
@Override
@NonNull
public Filter getFilter() {
    if (valueFilter == null) {
        Log.d("SEARCH1","New filter");
        valueFilter = new ValueFilter();
    }
    return valueFilter;
}
private class ValueFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        if(constraint == null || constraint.length() == 0){
            results.values = originalList;
            results.count = originalList.size();
        }
        else {
            List<Exhibition> nExhList = new ArrayList<>();
            for(Exhibition e : list){
                Log.d("NAMEE",e.name + " " + constraint.toString());
                if (e.getName().toUpperCase().contains(constraint.toString().toUpperCase()) || e.getCity().toUpperCase().contains(constraint.toString().toUpperCase())
                        ||e.getMuseum().toUpperCase().contains(constraint.toString().toUpperCase()) || e.getLongDescription().toUpperCase().contains(constraint.toString().toUpperCase())
                        || e.getDescription().toUpperCase().contains(constraint.toString().toUpperCase()) || e.getCategory().toUpperCase().contains(constraint.toString().toUpperCase())){
                    nExhList.add(e);
                }
            }
            results.values= nExhList;
            results.count=nExhList.size();
        }
        return results;
    }
    @Override
    protected void publishResults(CharSequence constraint,
                                  FilterResults results) {
        if(results.count==0){
            notifyDataSetInvalidated();
        }
        else{
            list = (ArrayList<Exhibition>)results.values;
            notifyDataSetChanged();
        }
    }
}
The first ImageView is a Bitmap stored in a Exhibition variable.
The second one changes the visibility of a text to get a expandable-like effect (because for now I can't convert the ListView to a ExpandableListView).
I tried different things like the cache, an AsyncTask, removing the custom click listener, put everything in ViewHolder but the scrolling is full of microlags. Is there something wrong in the adapter that I don't get it?
 
     
    