Android ListView性能优化,异步加载图片

简介: 版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48184383 ListView性能优...
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48184383

ListView性能优化+异步加载图片

一、绪论

相信大家在Android开发中肯定会经常用到ListView吧,那么怎么优化ListView呢?尤其是每个item里面中还有图片需要加载,数据源比较多,如果处理不好的话,在滑动ListView的过程中肯定会遇到卡顿的现象,做了这么久的开发,自己多少也摸索到了一些规律,接下来就给大家详细的介绍一下ListView的性能优化。

二、思路:

1.利用ViewHolder

我们自己定义一个ViewHolder,存放我们item中的组件,减少不必要的findViewById(),把我们的控件引用存在里面,利用view.setTag()存放在view里面,下次就可以直接取了。说一下setTag()是干什么用的吧,就是给View一个标签,下次getView()的时候我们可以根据标签获取这个View,如果标签存在了,就不需要再创建了,也就不再需要重新初始化那些组件了。

2.异步加载图片

我们在ListView中异步加载图片,可以使用一些第三方API来加载图片,比较好用的是ImageLoader,Xutils里面的BitmapUtils也可以。

3.设置LitView滑动时禁止加载图片

如果我们在滑动ListView的时候也要加载图片,那么滑动时肯定会卡顿

三、详解:

1.定义ListView

我们先看一下布局,item的每一项内容
<span style="font-size:14px;"><span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingBottom="@dimen/middler_space"
              android:background="#fff"
              android:id="@+id/llImage"
        >
        <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <ImageView
                        android:id="@+id/image"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:background="#cccccc"
                        android:layout_marginLeft="15dp"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        android:focusable="false"
                        android:layout_marginTop="@dimen/middler_space"
                        />
                <ImageView
                        android:layout_marginTop="@dimen/middler_space"
                        android:id="@+id/iv_filelist_vedio"
                        android:src="@drawable/luxiangji"
                        android:layout_gravity="left"
                        android:visibility="gone"
                        android:layout_marginLeft="15dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"/>
        </RelativeLayout>

        <LinearLayout
                android:layout_marginTop="@dimen/middler_space"
                android:layout_weight="1"
                android:orientation="vertical"
                android:layout_marginRight="10dp"
                android:layout_width="0dp"
                android:layout_height="wrap_content">
            <TextView
                    android:id="@+id/txtText"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="title"
                    android:textSize="15dp"
                    android:singleLine="true"
                    android:textColor="#000"
                    android:layout_marginLeft="10dp"
                    />
            <LinearLayout
                    android:orientation="horizontal"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="content"
                        android:textSize="11dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="7dp"
                        android:textColor="@color/deep_gray"/>
                
            </LinearLayout>

        </LinearLayout>

</LinearLayout></span></span>

很简单就是一个titile,一个content,一张图片

2.然后我们自定义Adapter

<span style="font-size:14px;"><span style="font-size:14px;">package com.yzx.youneed.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.yzx.youneed.R;
import com.yzx.youneed.model.AppItem_file;

import java.util.List;

/**
 * Created by Hankkin on 2015/1/30.
 * imagelist类型适配器
 */
public class AppImageListAdapter extends BaseAdapter {
    private Context context;
    private List<AppItem_file> data;
    private LayoutInflater inflater;
    public AppImageListAdapter(Context context,List<AppItem_file> data){
        this.data = data;
        this.context = context;
        inflater = LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return data.size();
    }
    /**
     * 修改listview首项
     * by Hankkin at:2015-2-15
     * @param i
     * @return
     */
    @Override
    public AppItem_file getItem(int i) {
        if (i<0){
            return null;
        }
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (view == null){
            holder= new ViewHolder();
            view = inflater.inflate(R.layout.listview_imagelist,null);
            holder.txtTitle = (TextView) view.findViewById(R.id.txtText);
            holder.image = (ImageView) view.findViewById(R.id.image);
            holder.txtContent = (TextView) view.findViewById(R.id.txtSC);
            view.setTag(holder);
        }else {
            holder = (ViewHolder) view.getTag();
            holder.clean();
        }

        AppItem_file af = data.get(i);
        if (i % 2 == 1) {
            view.setBackgroundResource(R.drawable.list_gray_item1);
        } else {
            view.setBackgroundResource(R.drawable.list_gray_item2);
        }
        holder.txtTitle.setText(af.getTitle());
        holder.txtContent.setText(af.getCreate_time());
        ImageLoader.getInstance().displayImage(af.getThumbnail(),holder.image);
        return view;
    }

    public final class ViewHolder{
        public TextView txtTitle,txtContent;
        public ImageView image;
        void clean(){
            txtTitle.setText(null);
            txtContent.setText(null);
            image.setImageBitmap(null);
        }
    }

}</span></span>
我们可以看见我们自己定义的ViewHolder,里面存放着item里面的三个属性,在getView的时候如果view为空,我们新建一个view,如果不为空,我们的holder=view.getTag();大家可能注意到还有一个clean()方法,这个方法是为了防止我们每一个item的数据会重复,然后我们每加载一个item之后都把上一个的item的数据源置空。
加载图片我们用的是
 
  
<span style="font-size:14px;"><span style="font-size:18px;">ImageLoader.getInstance().displayImage(af.getThumbnail(),holder.image);</span></span>
这句话也就是ImageLoader的异步加载图片,只需要传进去两个参数,第一个是图片url,第二个是ImageView控件,ImageLoader会自动给我们缓存图片的,如果之前加载过了是不会再次下载图片,直接加载本地缓存好的图片。至于ImageLoader的一些配置信息,包括默认图片,缓存地址等会在下面介绍。

3.接下来我们看一下怎么在我们的Activity中访问服务器获取信息

因为项目里面用的是Xutils的HttpUtils,所以访问服务器我就用它了,只是给大家举个例子
<span style="font-size:14px;"><span style="font-size:14px;">public void asyncQF(boolean url1) {
        RequestParams params = new RequestParams();
        params.addBodyParameter("flag",file_group.getFlag());
        HttpUtils http = new HttpUtils();
        http.send(HttpRequest.HttpMethod.POST, "", new RequestCallBack<String>() {
            @Override
            public void onSuccess(ResponseInfo<String> responseInfo) {
                //ToDo:
                //添加数据源,更新适配器
            }

            @Override
            public void onFailure(HttpException error, String msg) {
                //ToDo:
                //更新UI
            }
        });
    }</span></span>

服务器获取数据之后添加到List中更新我们的适配器就ok了,这时候我们的ListView就已经有数据了。
最后我们还可以设置ListView滑动时不加载图片

4.设置滑动不加载图片

ImageLoader已经给我们封装好了方法,我们只需要设置一下ListView滑动监听就可以了,看一下代码:
<span style="font-size:14px;"><span style="font-size:18px;">        lv_appImageList.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(),false,true));</span>
</span>

只需要简单的这么一句话就搞定,是不是很方便?

四、ImageLoader配置

<span style="font-size:14px;"><span style="font-size:14px;">public static void initImageLoader(Context context) {
        personOptions = new DisplayImageOptions.Builder()
                .showImageOnFail(R.drawable.usericon)
                .showImageForEmptyUri(R.drawable.usericon)
                .resetViewBeforeLoading(false)  // default
                .delayBeforeLoading(0)
                .cacheInMemory(true) // default
                .cacheOnDisk(true) // default
                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
                .bitmapConfig(Bitmap.Config.ARGB_8888) // default
                .displayer(new SimpleBitmapDisplayer()) // default
                .handler(new Handler()) // default
                .build();

        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.download)
//                .showImageOnFail(R.drawable.img_fail)
                .resetViewBeforeLoading(false)  // default
                .delayBeforeLoading(0)
                .cacheInMemory(true) // default
                .cacheOnDisk(true) // default
                .considerExifParams(true) // default
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
                .bitmapConfig(Bitmap.Config.ARGB_8888) // default
                .displayer(new SimpleBitmapDisplayer()) // default
                .handler(new Handler()) // default
                .build();

        // This configuration tuning is custom. You can tune every option, you may tune some of them,
        // or you can create default configuration by
        // ImageLoaderConfiguration.createDefault(this);
        // method.
//        File cacheDir = StorageUtils.getCacheDirectory(context);
        File picPath=new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"yourneed"+File.separator+"files");
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .memoryCacheExtraOptions(480, 800) // default = device screen dimensions
                .diskCacheExtraOptions(480, 800, null)
                .threadPoolSize(3) // default
                .threadPriority(Thread.NORM_PRIORITY - 1) // default
                .tasksProcessingOrder(QueueProcessingType.FIFO) // default
                .denyCacheImageMultipleSizesInMemory()
                .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
                .memoryCacheSize(2 * 1024 * 1024)
                .memoryCacheSizePercentage(13) // default
                .diskCache(new UnlimitedDiscCache(picPath)) // default
                .diskCacheSize(50 * 1024 * 1024)
                .diskCacheFileCount(1000)
                .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
                .imageDownloader(new BaseImageDownloader(context)) // default
                .imageDecoder(new BaseImageDecoder(true)) // default
                .defaultDisplayImageOptions(options) // default
                .writeDebugLogs()
                .build();
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config);
    }</span></span>

这里面有加载图片失败的设置,默认图片的设置,延迟加载设置,以及缓存陌路设置等等,这里就不详细介绍了,一般这个方法基本的配置都有了,大家可以直接拷到你的项目中直接用,可以在application里面初始化Imageloader。如果大家想要详细的了解Imageloader框架的话可以看看
这两篇博客,还是比较不错的。
至于图片就不给大家贴了,只要按照上面的方法做,你的ListView相信不会卡顿的。


相关文章
|
24天前
|
缓存 监控 Android开发
安卓应用性能优化的实用策略
【4月更文挑战第2天】 在竞争激烈的应用市场中,一款应用的性能直接影响用户体验和市场表现。本文针对安卓平台,深入探讨了性能优化的关键要素,包括内存管理、代码效率、UI渲染和电池使用效率。通过分析常见的性能瓶颈,并提供针对性的解决策略,旨在帮助开发者构建更加流畅、高效的安卓应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
47 0
|
3月前
|
API Android开发 开发者
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
31 2
|
4月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
72 0
|
18天前
|
监控 API Android开发
构建高效安卓应用:探究Android 12中的新特性与性能优化
【4月更文挑战第8天】 在本文中,我们将深入探讨Android 12版本引入的几项关键技术及其对安卓应用性能提升的影响。不同于通常的功能介绍,我们专注于实际应用场景下的性能调优实践,以及开发者如何利用这些新特性来提高应用的响应速度和用户体验。文章将通过分析内存管理、应用启动时间、以及新的API等方面,为读者提供具体的技术实现路径和代码示例。
|
24天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
22 1
|
1月前
|
缓存 前端开发 Android开发
构建高效Android应用:从设计原则到性能优化
随着移动设备成为我们日常生活不可或缺的一部分,开发一个流畅且响应迅速的Android应用变得至关重要。本文将探讨如何通过遵循Android设计原则和实施细致的性能优化策略来构建高效的Android应用程序。我们将深入分析应用架构的选择、内存管理的要点以及UI设计的优化,旨在为开发人员提供一套实用的指导方针,帮助他们提升应用的整体性能和用户体验。
|
1月前
|
监控 Java Android开发
构建高效Android应用:从内存管理到性能优化
【2月更文挑战第30天】 在移动开发领域,打造一个流畅且响应迅速的Android应用是每个开发者追求的目标。本文将深入探讨如何通过有效的内存管理和细致的性能调优来提升应用效率。我们将从分析内存泄露的根本原因出发,讨论垃圾回收机制,并探索多种内存优化策略。接着,文中将介绍多线程编程的最佳实践和UI渲染的关键技巧。最后,我们将通过一系列实用的性能测试工具和方法,帮助开发者监控、定位并解决性能瓶颈。这些技术的综合运用,将指导读者构建出更快速、更稳定、用户体验更佳的Android应用。
|
1月前
|
Java 定位技术 Android开发
安卓应用性能优化实践
【2月更文挑战第26天】在竞争激烈的应用市场中,一个高效流畅的安卓应用是吸引和留住用户的关键。本文将深入探讨安卓应用性能优化的多个方面,包括内存管理、多线程处理、UI渲染效率以及电池使用优化。通过实例分析和最佳实践的分享,旨在帮助开发者构建更快、更稳定、更节能的安卓应用。
|
1月前
|
设计模式 缓存 Android开发
深入理解Android应用性能优化
【2月更文挑战第18天】在移动开发领域,应用性能是用户体验的关键因素之一。特别是对于安卓设备而言,由于硬件配置的多样性,确保应用在不同设备上都能流畅运行是一项挑战。本文将探讨Android应用的性能优化策略,包括内存管理、UI渲染、多线程处理以及电池效率等方面。通过实例和最佳实践,我们将展示如何诊断性能瓶颈,并提供解决方案来改善应用响应速度和稳定性。