android给每个应用程序分配的内存是16MB,从网上下了个图片
高清大图,大小是500多kb,加载在listview的imageview里,layout_width和layout_height设置为60p。启动程序直接omm错误退出。
要想在listview里加载这样的图片,只能进行图片压缩了。但是怎么压缩呢?
andriod提供了一些方法如下:
压缩图片质量:
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fos);
其中的quality为0~100, 可以压缩图片质量, 不过对于大图必须对图片resize
这个是等比例缩放:
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
这个是截取图片某部分:
bitmap = Bitmap.createBitmap(bitmap, x, y, width, height);
但是这些方法在压缩图片之前先要把图片加载到内存中,所以不符合要求。
网上的常用的方法如下:
options为产生图片的编码设置
options.inJustDecodeBounds = true时,调用BitmapFactory.decodeResource()方法,将不会将图片加载到内存里去,却可以得到图片的信息(保存在options里)
这时我们如果我们希望图片宽100,高100,图片实际宽1000,实际高1000,那么我们设置options.inSampleSize = 1000/100(图片的缩放比例),设置options.inJustDecodeBounds = false();(下次调用BitmapFactory.decodeResource()将占用内存)
再次调用BitmapFactory.decodeResource(),将会产生按你设置的比例进行压缩的bitmap
*/
public class BitmapCompressTools {
public static Bitmap decodeSampleBitmapFromResource(Resources res,int resId,int reqWidth,int reqHeight){
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res,resId,options);
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res,resId,options);
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if(height > reqHeight|| width > reqWidth){
final int halfheight = height /2;
final int halfwidth = width / 2;
while(halfheight/inSampleSize >reqHeight && halfwidth/inSampleSize > reqWidth){
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
滑动时不加载图片:
在网上看的一段程序,看不懂,却运行的通。
在adapter的getview()(第一次显示,页面刷新,或者当adapter对应的数据源变化时候会主动调用,notifyDataSetChanged等方法主动刷新界面时被调用,也就是当listview需要显示item的时候就会调用getview())里的代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v;
if (convertView == null) {
v = getLayoutInflater().inflate(R.layout.list_item, null);
v.setTag(v);
} else {
v = (View) convertView.getTag();
ImageView iv = (ImageView) v.findViewById(R.id.img);
iv.setImageResource(R.drawable.ic_launcher);
}
ImageView iv = (ImageView) v.findViewById(R.id.img);
// 给图片控件设置上对应的位置编号
iv.setTag(position);
if (!isInit) {
iv.setImageResource(R.drawable.lable);
}
return v;
}
刚进来时它会调用if(convertView == null)初始化v,但v.setTag(v)有什么用? 下面isinit初始值是false,所以imageview会初始化为R.drawable.lable
当滑动listview时: 在下面滑动监听器中改变isInit的值,以上getView()将运行covertview!=null的分支,设置iv为R.drawable.ic_launcher,由于isInit为true,不会运行iv.setImageResource(R.drawable.lable)
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
isInit = true;
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:// 滑动停止
for (; start_index < end_index; start_index++) {
ImageView img = (ImageView) list.findViewWithTag(start_index);
bitmap = BitmapCompressTools.decodeSampleBitmapFromResource(getResources(),R.drawable.da,60,60);
img.setImageBitmap(bitmap);
}
break;
default:
break;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
// 设置当前屏幕显示的起始index和结束index
start_index = firstVisibleItem;
end_index = firstVisibleItem + visibleItemCount;
}
});
当滑动停止时,会运行以上代码加载压缩后的图片
我的两个问题是:convertView没给它赋过值,为什么会进入convertview!=null的语句,以及v.setTag(v)有什么用?