How To Improve Android ListView Performance

ListView is widely used in android applications. It is used to show a list of data in rows. And the row data is retrieved from the data adapter’s getView() method. You can read the article Android ListView Example to learn how to use ListView.

1. Android ListView Performance Issues.

  1. When there are so many list data that need to be displayed in the ListView, the getView() method will be called so many times and very frequently. So you may find the ListView performance decreased very fast if the list data is so huge.
  2. So the key to improving ListView performance is to make the getView() method run as quickly as possible. Make it less cost memory and CPU resources. Below picture is the diagram of how the ListView behaves.
    listview-execution-diagram
  3. From the above picture, we can see that ListView will cache scraped view objects which can be used later, this will decrease view creation times and reduce view creation consumed resources.
  4. So there are below methods that can be used to improve ListView performance.

2. Only Inflate The View When It Is Null In getView() Method.

  1. Each time ListView shows a row, it will call the data adapter’s getView(int itemIndex, View itemView, ViewGroup viewGroup) method.
  2. This method will inflate a View object and return it. But the inflate layout XML file process is resource consumed. So we should reduce such inflate layout XML code.
  3. This method has three input parameters. The first parameter is the current row index. The second parameter is the scrapped view object if the user has already scrolled to that row data before.
  4. So we should only create the return view when the itemView is null, otherwise, return the itemView instead.
  5. The below code is an example.
    public View getView(int itemIndex, View itemView, ViewGroup viewGroup) {
    
        if(itemView == null)
        {   // First inflate the RelativeView object.
            itemView = LayoutInflater.from(ListViewActivity.this).inflate(R.layout.activity_list_view_base_adapter, null);
        }
    
        // Find related view object inside the itemView.
        ImageView imageView = (ImageView)itemView.findViewById(R.id.baseUserImage);
        TextView titleView = (TextView)itemView.findViewById(R.id.baseUserTitle);
        TextView descView = (TextView)itemView.findViewById(R.id.baseUserDesc);
    
        // Set background color by row number.
        int colorPos = itemIndex % 2;
        if(colorPos==0) {
            itemView.setBackgroundColor(Color.YELLOW);
        }else
        {
            itemView.setBackgroundColor(Color.GREEN);
        }
        // Set resources.
        imageView.setImageResource(R.mipmap.ic_launcher);
    
        final String title = titleArr[itemIndex];
        final String desc = descArr[itemIndex];
        titleView.setText(title);
        descView.setText(desc);
    
        return itemView;
    }

3. Use ViewHolder Inner Class To Decrease Find View Times.

  1. From the example code in section 1, we can see that the code will find 3 view objects ( 1 ImageView and 2 TextView ) in each row’s getView() method. This action is also resource consumption because the find view object action will go through the layout XML tree for each time.
  2. So we should reduce such find view object actions. We can find the view object just for the first time and store them in a View Holder class, which can be used for later processes.
    public View getView(int itemIndex, View itemView, ViewGroup viewGroup) {
    
            if(itemView == null)
            {   // First inflate the RelativeView object.
                itemView = LayoutInflater.from(ListViewActivity.this).inflate(R.layout.activity_list_view_base_adapter, null);
    
                // Find related view object inside the itemView.
                ImageView imageView = (ImageView)itemView.findViewById(R.id.baseUserImage);
                TextView titleView = (TextView)itemView.findViewById(R.id.baseUserTitle);
                TextView descView = (TextView)itemView.findViewById(R.id.baseUserDesc);
    
                // Only create the view holder to hold the child view if the itemView is null.
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.setImageView(imageView);
                viewHolder.setTitleView(titleView);
                viewHolder.setDescView(descView);
    
                // Save the ViewHolder object in cached view.
                itemView.setTag(viewHolder);
            }
    
            // Set background color by row number.
            int colorPos = itemIndex % 2;
            if(colorPos==0) {
                itemView.setBackgroundColor(Color.YELLOW);
            }else
            {
                itemView.setBackgroundColor(Color.GREEN);
            }
    
            // Get the ViewHolder class from the cached view. 
            ViewHolder viewHolder = (ViewHolder)itemView.getTag();
            // Set resources.
            viewHolder.getImageView().setImageResource(R.mipmap.ic_launcher);
    
            final String title = titleArr[itemIndex];
            final String desc = descArr[itemIndex];
            viewHolder.getTitleView().setText(title);
            viewHolder.getDescView().setText(desc);
    
            return itemView;
        }
    
        // This class is used to hold ListView row view's child view object.
        class ViewHolder{
            // Store image view.
            private ImageView imageView;
            // Store title text view.
            private TextView titleView;
            // Store desc text view.
            private TextView descView;
    
            public ImageView getImageView() {
                return imageView;
            }
    
            public void setImageView(ImageView imageView) {
                this.imageView = imageView;
            }
    
            public TextView getTitleView() {
                return titleView;
            }
    
            public void setTitleView(TextView titleView) {
                this.titleView = titleView;
            }
    
            public TextView getDescView() {
                return descView;
            }
    
            public void setDescView(TextView descView) {
                this.descView = descView;
            }
        }
    };

4. Reduce Network Or IO Interaction In getView() Method.

  1. Network interaction is time-consuming. And IO operation is resource consumption also. But commonly ListView‘s row data is retrieved from the network or local files by IO.
  2. So we should use a thread to interact with the network server, and let’s that thread update the added view row data in memory.
  3. And the getView() method will get row data from the memory variable.
  4. The IO operation should be placed in the method when the activity is initialized such as the activity’s onStart() method. And the retrieved data from the local file will be cached in memory also.
  5. With all the above actions, your ListView performance can be improved as much as you need.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.