【发布时间】:2018-05-22 12:09:42
【问题描述】:
我的自定义适配器有以下代码,其中每一行由一个名称和一张图片组成,图片取自 firebase 存储:
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageException;
import com.google.firebase.storage.StorageReference;
import com.squareup.picasso.Picasso;
import java.util.List;
public class CustomAdapter extends BaseAdapter {
Context context;
List<RowItem> rowItems;
CustomAdapter(Context context, List<RowItem> rowItems) {
this.context = context;
this.rowItems = rowItems;
}
@Override
public int getCount() {
return rowItems.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
/* private view holder class */
private class ViewHolder {
ImageView profile_pic;
TextView member_name;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
final RowItem row_pos = rowItems.get(position);
final StorageReference storageReference = FirebaseStorage.getInstance().getReference().child(row_pos.getFirebaseUserUid()+".jpg");
//if (convertView == null) {
LayoutInflater mInflater = LayoutInflater.from(context);
convertView = mInflater.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.member_name = convertView
.findViewById(R.id.member_name);
holder.profile_pic = convertView
.findViewById(R.id.profile_pic);
//convertView.setTag(holder);
/*} else {
holder = (ViewHolder) convertView.getTag();
}*/
holder.member_name.setText(row_pos.getName());
storageReference.getDownloadUrl().addOnSuccessListener(new
OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
Glide.with(context).load(uri).apply(RequestOptions.circleCropTransform()).into(holder.profile_pic);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
int errorCode = ((StorageException) exception).getErrorCode();
if (errorCode == StorageException.ERROR_OBJECT_NOT_FOUND) {
Picasso.get()
.load(R.drawable.user)
.resize(70,70)
.into(holder.profile_pic);
}
}
});
return convertView;
}
}
现在,如果我这样运行它,它会加载每个新行,因此滚动不会像我希望的那样平滑。 为了克服这个问题,许多帖子建议添加以下内容(基本上是上面代码中标记为 cmets 的内容):
if (convertView == null){
/.../
convertView.setTag(holder);
}
} else {
holder = (ViewHolder) convertView.getTag();
}
但是当我这样做时,在列表项的 profilePic 视图中,它会以非常快的速度一个接一个地显示许多图像。
任何人都可以帮助检测问题并提出任何解决方案吗?
这是该错误的视频:https://vimeo.com/271555362
【问题讨论】:
-
使用 RecyclerView 代替 Listview
-
还有其他选择吗?我不想重写很多代码
-
在Adapter中请求URL的问题是,当视图(行)被复用时,需要手动停止对Firebase的请求。这取决于您拥有多少项目以及检索 url 需要多长时间,但您可以在检索 url 时显示一个带有进度条的空列表,然后在您拥有所有元素时显示该列表。
-
在实现任何东西之前,您需要了解 ListView 的工作原理(特别是它的适配器)。 Adapter 有一定数量的视图,当你滚动时复用它们来显示数据。例如,如果您的列表中有 100 个项目,但您只能同时看到其中的 10 个,则列表视图将尝试仅管理 10 个视图。如果您没有正确编写适配器并在每次调用
getView时创建一个新视图,则对未使用的视图或内容发生更改时执行操作,您将以泄漏和缓慢的 UI 告终。 -
这就是@firegloves 在谈到“回收过程”时的意思。所以我建议你阅读一些关于实现 ListView 的最佳实践的文档。如上所述,最好还是使用 RecyclerView
标签: android firebase firebase-storage custom-adapter