App freezes when loading large amount of data in Spinner

464 views Asked by At

I am loading countries list in an spinner, They are about 225 items, each with an image.

I am loading this in a fragment. The issue is app freezes for 2-3 seconds when i reach to this Fragment.

I also tried to load this in a thread, but it didn't help.

Following is my code.

Spinner Code in Fragment

var spinnerAdapter : CountriesAdapter?= null
            val runnable= Runnable {
                spinnerAdapter= CountriesAdapter(activity?.applicationContext, R.layout.country_component,
                        CountriesModel.getCountryDataList())

                spinnerNationality?.setAdapter(spinnerAdapter)
            }

        val thread = Thread(runnable)
        thread.start()

Custom Adapter

public class MyAdapter extends ArrayAdapter {

    Context context;
    List<CountriesDTO> objects;
    int textViewResourceId;

    public MyAdapter(Context context,
                            int textViewResourceId,
                            List<CountriesDTO> objects) {
        super(context, textViewResourceId, objects);

        this.objects= objects;
        this.context= context;
        this.textViewResourceId= textViewResourceId;
    }

    public View getCustomView(int position, View convertView,
                              ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflater.inflate(textViewResourceId, parent, false);
        TextView label = (TextView) row.findViewById(R.id.tvCountry);
        ImageView ivFlag =  row.findViewById(R.id.ivCountryFlag);

        label.setText(objects.get(position).getCountryName());

        Glide.with(context)
                .load(objects.get(position).getCompleteFlagURL())
                .into(ivFlag);

        return row;
    }

    @Override
    public View getDropDownView(int position, View convertView,
                                ViewGroup parent) {
        return getCustomView(position, convertView, parent);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getCustomView(position, convertView, parent);
    }
}
1

There are 1 answers

0
Bram Stoker On

Consider a different UX design, a Spinner is not build to display 225 items. You want to use a RecyclerView for that many items.

Easiest option is to navigate to a separate Fragment where a user picks a country. You can also use a DialogFragment. Alternatively you can show a PopupWindow with a custom view.

Edit: I see you don't recycle your spinner views which causes your adapter to inflate 225 views. However from a UX perspective you still might want to consider using a separate fragment to show more items at once.

You want to recycle your adapter views like this:

public View getCustomView(int position, View convertView,
                          ViewGroup parent) {

    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View row;
    if (convertView == null) {
        // only inflate a new view when we don't recycle one
        row = inflater.inflate(textViewResourceId, parent, false);
    } else {
        // recycle convertView
        row = convertView
    }
    
    // these findViewById() calls are also slowing you down
    TextView label = (TextView) row.findViewById(R.id.tvCountry);
    ImageView ivFlag =  row.findViewById(R.id.ivCountryFlag);

    label.setText(objects.get(position).getCountryName());

    Glide.with(context)
            .load(objects.get(position).getCompleteFlagURL())
            .into(ivFlag);

    return row;
}