android----------ListView的优化

ListView 如何提高其效率?简单的说,就是如何优化ListView。

可以从以下方面考虑一下:

① 复用ConvertView

② 自定义静态类ViewHolder
③ 使用分页加载

④ 使用WeakRefrence 、SoftReference引用ImageView 对象


一般,我们用ListView时都会用到适配器(Adapter),一般的Adapter都是以下的这种形式的:

public class MyAdapter extends BaseAdapter {
	private Context mContext;
	private List<SongInfo> songlists;
	private SongInfo songInfo;

	private ImageView albumImage; // 专辑图片
	private TextView musicTitle; // 音乐标题
	private TextView musicDuration; // 音乐时长
	private TextView musicArtist; // 音乐艺术家

	@Override
	public int getCount() {
		return songlists.size();
	}

	@Override
	public Object getItem(int position) {
		return songlists.get(position);
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view = LayoutInflater.from(mContext).inflate(
				R.layout.audio_list_item_layout, null);
		albumImage = (ImageView) view.findViewById(R.id.albumImage);
		musicTitle = (TextView) view.findViewById(R.id.music_title);
		musicArtist = (TextView) view.findViewById(R.id.music_Artist);
		musicDuration = (TextView) view.findViewById(R.id.music_duration);
		songInfo = songlists.get(position);
		// 设置默认图片
		albumImage.setImageResource(R.drawable.album);
		musicTitle.setText(songInfo.getSongName()); // 显示标题
		musicArtist.setText(songInfo.getSinger()); // 显示艺术家
		musicDuration.setText(Utils.formatTime(songInfo.getDuration()));// 显示时长
		return view;
	}

}

① 复用ConvertView

将getView的方法改成下面的这种形式

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		songInfo = songlists.get(position);
		View view;
		if (convertView == null) {
			view = LayoutInflater.from(mContext).inflate(
					R.layout.audio_list_item_layout, null);
		}else{
			view=convertView;
		}
		albumImage = (ImageView) view.findViewById(R.id.albumImage);
		musicTitle = (TextView) view.findViewById(R.id.music_title);
		musicArtist = (TextView) view.findViewById(R.id.music_Artist);
		musicDuration = (TextView) view.findViewById(R.id.music_duration);
		// 设置默认图片
		albumImage.setImageResource(R.drawable.album);
		musicTitle.setText(songInfo.getSongName()); // 显示标题
		musicArtist.setText(songInfo.getSinger()); // 显示艺术家
		musicDuration.setText(Utils.formatTime(songInfo.getDuration()));// 显示时长
		return view;
	}
convertView是历史View对象的缓存,也就是在拖动ListView时,最顶部的Item对象拖出了手机界面后变成的被回收掉的iew对象。
当ListView最底部的Item对象进入界面时,就可以使用刚才最顶部被回收掉的iew对象,这样就达到了复用convertView的效果了。


② 自定义静态类ViewHolder

在上面的① 复用ConvertView方法内,我们还看到findViewById的方法,由于每一次显示一个Item对象时都会调用getView方法,若在ListView

中有成千上万个Item对象,在拖动ListView显示Item时就会多次调用getView方法,也就是会多次调用findViewById方法,这也会导致ListView可能还是

会有一点点的卡顿现象,这时就可以使用② 自定义静态类ViewHolder来优化ListView了。

步骤:

将Item中需要用到的对象放在一个容器中,并将这个容器定义成静态的,这样在类创建的时候就创建了容器,并且只创建一次,后面要使用时就可以直接使用

而不用再创建了。如:

public static class ViewHolder {
		// 所有控件对象引用
		public ImageView albumImage; // 专辑图片
		public TextView musicTitle; // 音乐标题
		public TextView musicDuration; // 音乐时长
		public TextView musicArtist; // 音乐艺术家
}
这里设置ViewHolder为static,也就是静态的,静态类只会在第一次加载时会耗费比较长时间,但是后面就可以很好帮助加载,同时保证了内存中只有一个ViewHolder,节省了内存的开销。

getView的方法改成下面:

public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder viewHolder = null;
		if (convertView == null) {
			viewHolder = new ViewHolder();
			convertView = LayoutInflater.from(mContext).inflate(
					R.layout.audio_list_item_layout, null);
			viewHolder.albumImage = (ImageView) convertView
					.findViewById(R.id.albumImage);
			viewHolder.musicTitle = (TextView) convertView
					.findViewById(R.id.music_title);
			viewHolder.musicArtist = (TextView) convertView
					.findViewById(R.id.music_Artist);
			viewHolder.musicDuration = (TextView) convertView
					.findViewById(R.id.music_duration);
			convertView.setTag(viewHolder); // 表示给View添加一个格外的数据,

		} else {
			viewHolder = (ViewHolder) convertView.getTag();// 通过getTag的方法将数据取出来
		}
		songInfo = songlists.get(position);
		// 设置默认图片
		viewHolder.albumImage.setImageResource(R.drawable.album);
		viewHolder.musicTitle.setText(songInfo.getSongName()); // 显示标题
		viewHolder.musicArtist.setText(songInfo.getSinger()); // 显示艺术家
		viewHolder.musicDuration.setText(Utils.formatTime(songInfo
				.getDuration()));// 显示时长

		return convertView;
}


前面的两种方法是针对android的 内部机制对ListView作出的优化策略,后面的两种方法是视项目的情况而使用的。

③ 使用分页加载

当我们需要显示很多数据条目时,若一下子就显示过多的数据就会造成界面很卡,甚至会卡死。因此在数据很多的时候采用分页加载是一个不错的选择,

采用分页加载可以是界面更加顺畅。

下面通过一个例子说明一下分页加载的用法:

界面代码

list_page.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/lv_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

list_page_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    
    
    <TextView
        android:id="@+id/title_id"
        android:text="title"
        android:layout_width="wrap_content"
        android:layout_height="30dp"/>
    
    <TextView
        android:id="@+id/tv_id"
        android:layout_marginLeft="50dp"
        android:text="contenttext"
        android:layout_width="wrap_content"
        android:layout_height="30dp"/>

</LinearLayout>

list_page_load.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="13dp"
    android:paddingTop="13dp" >

    <Button
        android:id="@+id/more_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="查看更多..."
        android:textSize="20sp" />

    <LinearLayout
        android:id="@+id/load_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone" >

        <ProgressBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:text="正在加载..."
            android:textSize="20dp" />
    </LinearLayout>

</LinearLayout>

java代码部分

MainActivity.java

public class MainActivity extends Activity {
    private ListView listView;
    private List<Map<String,Object>> data;
    private listViewAdapter adapter;
    //分页加载的数据的数量
    private int pageSize=10;
    private final int pageType=1;
    //查看更多
    private TextView moreTextView;
    //正在加载进度条
    private LinearLayout loadProgressBar;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_page);
        
        listView=(ListView)findViewById(R.id.lv_id);
        
        //第一个参数:1起始数  第二个参数:显示的数目
        data=InitValue.initValue(1,15);
        
        //在ListView中添加"加载更多"
        addPageMore();
        //添加"加载更多"一定要在设置Adapter之前
        adapter=new listViewAdapter();
        listView.setAdapter(adapter);
    }
    
    private class listViewAdapter extends BaseAdapter{
    	
        int count=data.size();
        @Override
        public int getCount() {
            return count;
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
        	
            View view=LayoutInflater.from(MainActivity.this).inflate(R.layout.list_page_item, null);
            TextView title=(TextView)view.findViewById(R.id.tv_id);
            TextView text=(TextView)view.findViewById(R.id.title_id);
            title.setText(data.get(position).get("title").toString());
            text.setText(data.get(position).get("text").toString());
            return view;
        }
        
    }
    
    /**
     * 加载下一页的数据
     * @param pageStart
     * @param pageSize
     */
    private void chageListView(int pageStart,int pageSize){
        List<Map<String,Object>> data=InitValue.initValue(pageStart,pageSize);
        for (Map<String, Object> map : data) {
            this.data.add(map);
        }
        data=null;
    }
    
    /**
     * 在ListView中添加"加载更多"
     */
    private void addPageMore(){
        View view=LayoutInflater.from(this).inflate(R.layout.list_page_load, null);
        moreTextView=(TextView)view.findViewById(R.id.more_id);
        loadProgressBar=(LinearLayout)view.findViewById(R.id.load_id);
        moreTextView.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                //隐藏"加载更多"
                moreTextView.setVisibility(View.GONE);
                //显示进度条
                loadProgressBar.setVisibility(View.VISIBLE);
                
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //休眠3秒,用于模拟网络操作时间
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                        //加载模拟数据:下一页数据, 在正常情况下,上面的休眠是不需要,直接使用下面这句代码加载相关数据
                        chageListView(data.size(),pageSize);
                        
                        Message mes=handler.obtainMessage(pageType);
                        handler.sendMessage(mes);
                    }
                }).start();
            }
        });
        listView.addFooterView(view);
    }
    
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case pageType:
                //改变适配器的数目
                adapter.count += pageSize;
                //通知适配器,发现改变操作
                adapter.notifyDataSetChanged();
                
                //再次显示"加载更多"
                moreTextView.setVisibility(View.VISIBLE);
                //再次隐藏“进度条”
                loadProgressBar.setVisibility(View.GONE);
                break;

            default:
                break;
            }
            
            super.handleMessage(msg);
        }
    };
}

InitValue.java

public class InitValue {
    public static int page=1;
    
    /**
     * 模拟数据分页加载,
     * @param pageStart  起始数
     * @param pageSize   每页显示数目
     * @return
     */
    public static List<Map<String,Object>> initValue(int pageStart,int pageSize){
        Map<String,Object> map;
        List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
        for(int i=0;i<pageSize;i++){
            map=new HashMap<String,Object>();
            map.put("text", "       context...");
            map.put("title", "       "+page+"_ListView分页显示");
            ++page;
            list.add(map);
        }
        return list;
    }
}


实现效果


④ 使用WeakRefrence 、SoftReference引用ImageView 对象

在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。比如可以使用WeakReference mContextRef)、SoftReference、WeakHashMap等的来存储图片信息。

例子:

package com.lvguo.scanstreet.activity;  
import java.io.File;  
import java.lang.ref.SoftReference;  
import java.util.ArrayList;  
import java.util.HashMap;  
import java.util.List;  
import android.app.Activity;  
import android.app.AlertDialog;  
import android.content.Context;  
import android.content.DialogInterface;  
import android.content.Intent;  
import android.content.res.TypedArray;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.graphics.BitmapFactory.Options;  
import android.os.Bundle;  
import android.view.View;  
import android.view.ViewGroup;  
import android.view.WindowManager;  
import android.widget.AdapterView;  
import android.widget.AdapterView.OnItemLongClickListener;  
import android.widget.BaseAdapter;  
import android.widget.Gallery;  
import android.widget.ImageView;  
import android.widget.Toast;  
import com.lvguo.scanstreet.R;  
import com.lvguo.scanstreet.data.ApplicationData;  
/** 
* @Title: PhotoScanActivity.java 
* @Description: 照片预览控制类 
* @author XiaoMa 
*/  
public class PhotoScanActivity extends Activity {  
private Gallery gallery ;  
private List<String> ImageList;  
private List<String> it ;  
private ImageAdapter adapter ;  
private String path ;  
private String shopType;  
private HashMap<String, SoftReference<Bitmap>> imageCache = null;  
private Bitmap bitmap = null;  
private SoftReference<Bitmap> srf = null;  
@Override  
public void onCreate(Bundle savedInstanceState) {  
super.onCreate(savedInstanceState);  
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
WindowManager.LayoutParams.FLAG_FULLSCREEN);  
setContentView(R.layout.photoscan);  
Intent intent = this.getIntent();  
if(intent != null){  
if(intent.getBundleExtra(“bundle”) != null){  
Bundle bundle = intent.getBundleExtra(“bundle”);  
path = bundle.getString(“path”);  
shopType = bundle.getString(“shopType”);  
}  
}  
init();  
}  
private void init(){  
imageCache = new HashMap<String, SoftReference<Bitmap>>();  
gallery = (Gallery)findViewById(R.id.gallery);  
ImageList = getSD();  
if(ImageList.size() == 0){  
Toast.makeText(getApplicationContext(), “无照片,请返回拍照后再使用预览”, Toast.LENGTH_SHORT).show();  
return ;  
}  
adapter = new ImageAdapter(this, ImageList);  
gallery.setAdapter(adapter);  
gallery.setOnItemLongClickListener(longlistener);  
}  
/** 
* Gallery长按事件操作实现 
*/  
private OnItemLongClickListener longlistener = new OnItemLongClickListener() {  
@Override  
public boolean onItemLongClick(AdapterView<?> parent, View view,  
final int position, long id) {  
//此处添加长按事件删除照片实现www.2cto.com  
AlertDialog.Builder dialog = new AlertDialog.Builder(PhotoScanActivity.this);  
dialog.setIcon(R.drawable.warn);  
dialog.setTitle(“删除提示”);  
dialog.setMessage(“你确定要删除这张照片吗?”);  
dialog.setPositiveButton(“确定”, new DialogInterface.OnClickListener() {  
@Override  
public void onClick(DialogInterface dialog, int which) {  
File file = new File(it.get(position));  
boolean isSuccess;  
if(file.exists()){  
isSuccess = file.delete();  
if(isSuccess){  
ImageList.remove(position);  
adapter.notifyDataSetChanged();  
//gallery.setAdapter(adapter);  
if(ImageList.size() == 0){  
Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoSizeZero), Toast.LENGTH_SHORT).show();  
}  
Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoDelSuccess), Toast.LENGTH_SHORT).show();  
}  
}  
}  
});  
dialog.setNegativeButton(“取消”,new DialogInterface.OnClickListener() {  
@Override  
public void onClick(DialogInterface dialog, int which) {  
dialog.dismiss();  
}  
});  
dialog.create().show();  
return false;  
}  
};  
/** 
* 获取SD卡上的所有图片文件 
* @return 
*/  
private List<String> getSD() {  
/* 设定目前所在路径 */  
File fileK ;  
it = new ArrayList<String>();  
if(“newadd”.equals(shopType)){  
//如果是从查看本人新增列表项或商户列表项进来时  
fileK = new File(ApplicationData.TEMP);  
}else{  
//此时为纯粹新增  
fileK = new File(path);  
}  
File[] files = fileK.listFiles();  
if(files != null && files.length>0){  
for(File f : files ){  
if(getImageFile(f.getName())){  
it.add(f.getPath());  
Options bitmapFactoryOptions = new BitmapFactory.Options();  
//下面这个设置是将图片边界不可调节变为可调节  
bitmapFactoryOptions.inJustDecodeBounds = true;  
bitmapFactoryOptions.inSampleSize = 5;  
int outWidth  = bitmapFactoryOptions.outWidth;  
int outHeight = bitmapFactoryOptions.outHeight;  
float imagew = 150;  
float imageh = 150;  
int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight  
/ imageh);  
int xRatio = (int) Math  
.ceil(bitmapFactoryOptions.outWidth / imagew);  
if (yRatio > 1 || xRatio > 1) {  
if (yRatio > xRatio) {  
bitmapFactoryOptions.inSampleSize = yRatio;  
} else {  
bitmapFactoryOptions.inSampleSize = xRatio;  
}  
}  
bitmapFactoryOptions.inJustDecodeBounds = false;  
bitmap = BitmapFactory.decodeFile(f.getPath(),  
bitmapFactoryOptions);  
//bitmap = BitmapFactory.decodeFile(f.getPath());  
srf = new SoftReference<Bitmap>(bitmap);  
imageCache.put(f.getName(), srf);  
}  
}  
}  
return it;  
}  
/** 
* 获取图片文件方法的具体实现 
* @param fName 
* @return 
*/  
private boolean getImageFile(String fName) {  
boolean re;  
/* 取得扩展名 */  
String end = fName  
.substring(fName.lastIndexOf(“.”) + 1, fName.length())  
.toLowerCase();  
/* 按扩展名的类型决定MimeType */  
if (end.equals(“jpg”) || end.equals(“gif”) || end.equals(“png”)  
|| end.equals(“jpeg”) || end.equals(“bmp”)) {  
re = true;  
} else {  
re = false;  
}  
return re;  
}  
public class ImageAdapter extends BaseAdapter{  
/* 声明变量 */  
int mGalleryItemBackground;  
private Context mContext;  
private List<String> lis;  
/* ImageAdapter的构造符 */  
public ImageAdapter(Context c, List<String> li) {  
mContext = c;  
lis = li;  
TypedArray a = obtainStyledAttributes(R.styleable.Gallery);  
mGalleryItemBackground = a.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0);  
a.recycle();  
}  
/* 几定要重写的方法getCount,传回图片数目 */  
public int getCount() {  
return lis.size();  
}  
/* 一定要重写的方法getItem,传回position */  
public Object getItem(int position) {  
return lis.get(position);  
}  
/* 一定要重写的方法getItemId,传并position */  
public long getItemId(int position) {  
return position;  
}  
/* 几定要重写的方法getView,传并几View对象 */  
public View getView(int position, View convertView, ViewGroup parent) {  
System.out.println(“lis:”+lis);  
File file = new File(it.get(position));  
SoftReference<Bitmap> srf = imageCache.get(file.getName());  
Bitmap bit = srf.get();  
ImageView i = new ImageView(mContext);  
i.setImageBitmap(bit);  
i.setScaleType(ImageView.ScaleType.FIT_XY);  
i.setLayoutParams( new Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,  
WindowManager.LayoutParams.WRAP_CONTENT));  
return i;  
}  
}  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值