关于RecyclerView的一点小事
最近用RecyclerView做了一个图片列表,遇到了好几个OOM的坑,特别记录一下,首先是RecyclerView的使用上,原谅我是从listview转过来的一时没适应过来,listview的BaseAdapter里面有getPostion和getItem的方法重写,我们随便就能获得postion或者对应的item,到了RecyclerView我没找到getPostion方法,RecyclerView.ViewHolder里面的getAdapterPosition方法不能在初始化时获取postion,所以一时抽风重写了getItemViewType()方法返回postion,然后事情大条了,RecyclerView里是根据ItemViewType判断类型是否相同然后回收重用,所以一旦getItemViewType()方法返回postion,就表示着你的每个item不会回收复用,会一直填充新的itemView然后就oom了,虽然我知道大多数程序员没我这么傻,可是还是写给某些偶尔会脑抽的人参考一下。
我现在主要使用的还是getAdapterPosition()方法,只要不是需要在初始化时获取相对应的postion都可以用(要在初始化里面获取postion的建议放到onBindViewHolder方法里面,自带postion参数),具体的例子可以看看下面的给view加上点击事件的代码:
public ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
View view = mInflater.inflate(R.layout.recy_item_second_case,parent,false);
final ViewHolder holder = new ViewHolder(view);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Intent intent2 = new Intent(mContext, CaseActivity.class);
intent2.putExtra("id",mDatas.get(position).getId()+"");
mContext.startActivity(intent2);
}
});
return holder;
}
接下来是Picasso的使用上遇到的问题
以前一开始用的时候问题还不大,直到最近后台把开始把几M的缩略图传给我,3000多的宽高分辨率几张就把内存爆到100多了,不过这也怪我当初考虑不周,设计图要求图片宽度匹配屏幕,然后高度按比例自适应,图片的分辨率早就超出屏幕宽度了,所以加载这么大的图片是浪费内存资源,我就想着把bitmap缩小,一开始用的下面这个方法,在Picasso.transform(transformation)里面做处理当图片宽度大于屏幕时根据屏幕的width重新createScaledBitmap一个缩放的bitmap。
Transformation transformation = new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
int targetWidth = width;
if (source.getWidth()<=width){
return source;
}
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
if (targetHeight != 0 && targetWidth != 0) {
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
source.recycle();
}
return result;
} else {
return source;
}
}
@Override
public String key() {
return "transformation" + " desiredByWidth";
}
};
可是程序一跑起来内存占用并不能马上降下来,虽然我调用了source.recycle(),可是内存还是会涨到一个超过100m的峰值后面才下降,我试了用Picasso自身的resize方法的话就不会产生这么高的峰值,所以就想着不生成新的bitmap而是直接把根据屏幕宽度压缩后的宽高传给Picasso.resize(width,height)。
public static void displayCorpByResize(final ImageView img, String url, final int width){
final double[] scaled = {0};
Transformation transformation = new Transformation() {
@Override
public Bitmap transform(Bitmap source) {
scaled[0] = (double) source.getHeight() / (double) source.getWidth();
return source;
}
@Override
public String key() {
return "transformation" + " desiredByResize";
}
};
if (!TextUtils.isEmpty(url)) {
Picasso.with(mContext)
.load(url)
.config(Bitmap.Config.RGB_565)
.transform(transformation)
.resize(width, (int) (width*scaled[0]))
.placeholder(R.drawable.load_photo_big)
.into(img);
}
}
这样虽然是解决了内存暴涨的问题,可是这代码的写法看起来连我都觉得有点别扭,各位大牛如果知道有什么好的写法请务必告诉我,网上都没找到对应的方法,所以才用这种别扭的方法。当然网络上许多朋友说Picasso内存占用大是老问题了,想要内存占用问题少点最好试试看glide和fresco框架,最后再谢谢这位老兄提供的自适应高度的ImageView。