TPG
TPG

Reputation: 3211

Suggestion for ListView performance improvement

I am using custom list view to show an image and text. The below is the layout file for my list view item and the code behind. I will explain my problem at the bottom of the post.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="5dp"
    tools:context=".MainActivity" >

    <ImageView
        android:id="@+id/imgTitleImage"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:scaleType="fitXY" />

    <TextView
        android:id="@+id/tvNewsTitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/imgTitleImage"
        android:layout_alignStart="@+id/imgTitleImage"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:paddingLeft="10dp"
        android:paddingStart="10dp"
        android:paddingRight="10dp"
        android:paddingEnd="10dp"
        android:paddingTop="2dp"
        android:paddingBottom="2dp"
        android:gravity="top|start"
        android:textColor="#FFFFFF"         
        android:background="#80000000" />
</RelativeLayout>

Below is the backend code to load necessary info into the list view.

public View getView(final int position, View convertView, ViewGroup parent) 
    {
        SessionManagement sessionmanagement = new SessionManagement(context);
        ViewHolder holder = null;

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.news_item, null);
            holder = new ViewHolder();
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder)convertView.getTag();
        }

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Touch on view handle                              
                ObjNews objNews = objNewss[position];

                Intent intent = new Intent(activity, NewsViewActivity.class);       

                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

                intent.putExtra("newsId", String.valueOf(objNews.newsId));
                intent.putExtra("type", String.valueOf(Config.NEWS_BRANCH));

                context.startActivity(intent);
            }

        });

        holder.imageView = (ImageView)convertView.findViewById(R.id.imgTitleImage);

        //calculate the screen size and image ratio
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        int width = size.x;
        float screenRatio = width / 320f;

        holder.imageView.getLayoutParams().height = (int)(75f * screenRatio);
        holder.imageView.getLayoutParams().width = (int)(320f * screenRatio);

        Bitmap titleImage = Global.GetBitmapFromURL("http://www.domain.com/" + objNewss[position].titleImage);

        if(titleImage != null)
        {
            holder.imageView.setImageBitmap(titleImage);
        }   
        else
        {
            holder.imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.news_title_default));    
        }

        //customizing view
        holder.textView = (TextView)convertView.findViewById(R.id.tvNewsTitle);
        holder.textView.setText(objNewss[position].title);                     

        return convertView;
    }

These pieces of code works perfectly, the image and text loaded nicely. However, when the item count increase, the loading time too increased. The screen will be blank waiting for the view to get loaded. Below is the logcat obtain.

12-21 03:54:20.827: D/OpenGLRenderer(1248): Enabling debug mode 0

12-21 03:54:20.955: I/Choreographer(1248): Skipped 36 frames! The application may be doing too much work on its main thread.

12-21 03:54:24.991: D/dalvikvm(1248): GC_FOR_ALLOC freed 467K, 14% free 4447K/5116K, paused 8ms, total 17ms

12-21 03:54:35.587: D/dalvikvm(1248): GC_FOR_ALLOC freed 263K, 16% free 4416K/5220K, paused 7ms, total 9ms

12-21 03:54:35.591: I/dalvikvm-heap(1248): Grow heap (frag case) to 4.647MB for 148492-byte allocation

12-21 03:54:35.607: D/dalvikvm(1248): GC_FOR_ALLOC freed <1K, 16% free 4560K/5368K, paused 14ms, total 15ms

12-21 03:54:43.363: D/dalvikvm(1248): GC_FOR_ALLOC freed 322K, 18% free 4415K/5368K, paused 8ms, total 8ms

12-21 03:54:44.611: D/dalvikvm(1248): GC_FOR_ALLOC freed 281K, 18% free 4415K/5368K, paused 8ms, total 9ms

12-21 03:54:46.531: W/EGL_genymotion(1248): eglSurfaceAttrib not implemented

12-21 03:54:48.115: D/dalvikvm(1248): GC_FOR_ALLOC freed 284K, 18% free 4420K/5368K, paused 8ms, total 10ms

12-21 03:54:49.983: D/dalvikvm(1248): GC_FOR_ALLOC freed 323K, 18% free 4429K/5368K, paused 6ms, total 6ms

12-21 03:54:50.339: D/dalvikvm(1248): GC_FOR_ALLOC freed 280K, 18% free 4439K/5368K, paused 11ms, total 11ms

12-21 03:54:50.551: I/Choreographer(1248): Skipped 1523 frames! The application may be doing too much work on its main thread.

12-21 03:54:51.263: D/dalvikvm(1248): GC_FOR_ALLOC freed 288K, 17% free 4500K/5368K, paused 8ms, total 9ms

12-21 03:54:54.115: D/dalvikvm(1248): GC_FOR_ALLOC freed 326K, 17% free 4497K/5368K, paused 7ms, total 9ms

12-21 03:54:54.531: D/dalvikvm(1248): GC_FOR_ALLOC freed 281K, 17% free 4496K/5368K, paused 10ms, total 10ms

12-21 03:54:55.871: D/dalvikvm(1248): GC_FOR_ALLOC freed 287K, 17% free 4506K/5368K, paused 8ms, total 9ms

12-21 03:54:56.591: D/dalvikvm(1248): GC_FOR_ALLOC freed 324K, 17% free 4506K/5368K, paused 7ms, total 8ms

12-21 03:54:57.339: D/dalvikvm(1248): GC_FOR_ALLOC freed 281K, 17% free 4506K/5368K, paused 7ms, total 8ms

It could be due to "Bitmap titleImage = Global.GetBitmapFromURL("http://www.domain.com/" + objNewss[position].titleImage);" this line of code. If commented the load significantly faster.

May I know if any experts out there has a better suggestion for me? Better still if can implement an asynchronous loading like groupon etc where it loads and show line by line which will not interfere the user-experience.

Many thanks.

Upvotes: 0

Views: 128

Answers (2)

mrres1
mrres1

Reputation: 1155

Your not utilizing the structure. This is a copy of the EfficientAdapter class written by the Android Development Team.

During the evaluation of convertView you should be assigning your holder values.

By assign the value after the conditions it will be called each time.

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();

Point size;

float ratio = -1;

//calculate the screen size and image ratio
void float getRatio()
{
    if(ratio == -1)
    {
        size = new Point();

        display.getSize(size);

        int width = size.x;

        ratio = width / 320f;
    }

    return ratio;
}

Bitmap titleImage;

Drawable news_title_default = context.getResources().getDrawable(R.drawable.news_title_default);

public View getView(final int position, View convertView, ViewGroup parent) 
{
    ViewHolder holder = null;

    if (convertView == null) {
        convertView = inflater.inflate(R.layout.news_item, null);
        holder = new ViewHolder();

        // assign the holder values
        holder.imageView = (ImageView)convertView.findViewById(R.id.imgTitleImage);
        holder.textView = (TextView)convertView.findViewById(R.id.tvNewsTitle);

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

    convertView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Touch on view handle                              
            ObjNews objNews = objNewss[position];

            Intent intent = new Intent(activity, NewsViewActivity.class);       

            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            intent.putExtra("newsId", String.valueOf(objNews.newsId));
            intent.putExtra("type", String.valueOf(Config.NEWS_BRANCH));

            context.startActivity(intent);
        }

    });

    holder.imageView.getLayoutParams().height = (int)(75f * getRatio());
    holder.imageView.getLayoutParams().width = (int)(320f * getRatio());

    titleImage = Global.GetBitmapFromURL("http://www.domain.com/" + objNewss[position].titleImage);

    if(titleImage != null)
    {
        holder.imageView.setImageBitmap(titleImage);
    }   
    else
    {
        holder.imageView.setImageDrawable(news_title_default);    
    }

    //customizing view

    holder.textView.setText(objNewss[position].title);                     

    return convertView;
}

Upvotes: 1

Dara
Dara

Reputation: 107

It seems like Global.GetBitmapFromURL is running on the main thread. Any network request should be done on separate thread, so you should move it into AsyncTask or Loader that would solve your problem.

Upvotes: 1

Related Questions