Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

listView.setAdapter is so sluggish?

I have three swipable tabs. In the first tab, I have a listview with more than 1000 items.

I tried to fill the list using Asynctask and Runnable and I have no problem with that.

The problem is when I am trying to assign the adapter to the listview. I noticed no matter how many items are in the adapter, whether it is 1 or 1000, when it tries to do: listView.setAdapter(adapter), it skips around 30 frames...

Since listView.setAdapter(adapter) is used in the first tab, whenever the user tries to enter that tab, UI freezes for some milliseconds. Although it is not a serious problem, but I don't like it.

The question is: Is this normal that when we invoke listView.setAdapter(adapter) the UI freezes for some milliseconds and skips some frames? Is there not anyway to fix this?

Am I Clear?

    Carpet_handler ch; // my db handler
ListView listview;

public ArrayList<CarpetGen> carpetGens;
CarpetAdapter adapter;
boolean loadingMore=false;
int offset;
Context ctx;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_first_page_customers, container, false);
    ch=new Carpet_handler(getActivity()); // db handler
    listview = (ListView) rootView.findViewById(R.id.listView2);
    ctx=this.getActivity();
    carpetGens = new ArrayList<CarpetGen>();
    offset=0;
    adapter = new CarpetAdapter(getActivity(), R.layout.row, carpetGens);



    listview.setAdapter(adapter); // adapter is empty first time, runnable fills it
    listview.setOnItemClickListener(myClickListener);



    //Here is where the magic happens
    listview.setOnScrollListener(new OnScrollListener(){
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {}
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
            //what is the bottom iten that is visible
            int lastInScreen = firstVisibleItem + visibleItemCount;
            //is the bottom item visible & not loading more already ? Load more !
            if((lastInScreen == totalItemCount) && !(loadingMore)){
                Thread thread =  new Thread(null, loadMoreListItems);
                thread.start();
            }
        }
    });


    return rootView;
}



   //Runnable to load the items
   private Runnable loadMoreListItems = new Runnable() {
    @Override
    public void run() {
        //Set flag so we cant load new items 2 at the same time
        loadingMore = true;
        //Reset the array that holds the new items
        carpetGens= new ArrayList<CarpetGen>();
        carpetGens.addAll(ch.getAllCustomerCarpets1(getActivity().getIntent().getIntExtra("recordid", -1), offset));
        offset+=15;
        //Done! now continue on the UI thread
        if(getActivity()==ctx)
            getActivity().runOnUiThread(returnRes);

    }
};

//Since we cant update our UI from a thread this Runnable takes care of that!
private Runnable returnRes = new Runnable() {
    @Override
    public void run() {
        //Loop thru the new items and add them to the adapter
        if(carpetGens != null && carpetGens.size() > 0){
                    for(int i=0;i < carpetGens.size();i++)
                    adapter.add(carpetGens.get(i));
                 }
                adapter.notifyDataSetChanged();
                loadingMore = false;
        }
   };

Here is my adapter:

public class CarpetAdapter extends ArrayAdapter<CarpetGen> {

private final Context context;
private final int rowResourceId;
//private final String[] Ids;
private final ArrayList<CarpetGen> Objects;

public CarpetAdapter(Context context, int textViewResourceId, ArrayList<CarpetGen> objects){//Arr[] objects) {
    super(context, textViewResourceId, objects);
    // TODO Auto-generated constructor stub
    this.context = context;
    this.rowResourceId = textViewResourceId;
    this.Objects = objects;

}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    View rowView = convertView;
    CarpetGen i = Objects.get(position);
    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        rowView = inflater.inflate(R.layout.row, parent, false);
        //TextView textView = (TextView) rowView.findViewById(R.id.textView);

        //textView.setText(i.Result_String);

        holder = new ViewHolder();
        holder.title = (TextView) rowView
                .findViewById(R.id.textView);

        rowView.setTag(holder);            
    } else {        
        holder = (ViewHolder) rowView.getTag();
    }

    holder.title.setText(i.Result_String);



    return rowView;

}
static class ViewHolder {
TextView title;

} }

like image 789
SMahdiS Avatar asked Nov 10 '22 14:11

SMahdiS


1 Answers

I think it's perfectly normal. Keep in mind that it has to refresh the layout, even if it has zero elements, when you call the setAdapter() method, you're doing some operations which depends on your implementation, but basically it's not a 0-second-miracle. As @laalto suggested, there also might be a bottleneck in the custom adapter implementation, so you might want to consider doing some work in Threads (or basically the AsyncThread). But as I said, I'd not worry about it (overall, if this frame skipping was happening in a virtual device).

like image 111
nKn Avatar answered Nov 14 '22 21:11

nKn