当我使用convertView时出现问题,当我没有问题时
我有一个ListView,它包含一个ImageView和一个TextView。我是继承ArrayAdapter,以便我可以通过一个子类AsyncTask从互联网加载图像。迄今为止都很好。当我使用convertView时出现问题,当我没有问题时
的问题是,如果我尝试使用convertView,我有其中图像简单地回收进错行了问题。 (这是一个公司的标志,所以这是...不好。)
如果我不使用convertView,但是,图像丢失的用户滚动时。所以,如果他们向下滚动,备份,图像从互联网(数据使用这显然是不好的,电池寿命等)
有一个简单的办法解决这一问题,以便它不会重新加载每次从互联网加载,或移动图像?
下面是我使用的是什么至今:
public class SupplierAdapter extends ArrayAdapter<Supplier>{
int resource;
String response;
Context context;
public SupplierAdapter(Context context, int resource, List<Supplier> suppliers) {
super(context, resource, suppliers);
this.resource = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
LinearLayout view;
Supplier s = getItem(position);
if(convertView == null){
view = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi;
vi = (LayoutInflater) getContext().getSystemService(inflater);
vi.inflate(resource, view, true);
} else {
view = (LinearLayout) convertView;
}
ImageView iv = (ImageView) view.findViewById(R.id.thumbnail);
// s.getThumbnail returns a URL
new DownloadImageTask(iv).execute(s.getThumbnail());
TextView titleText =(TextView) view.findViewById(R.id.titleText);
titleText.setText(s.getTitle());
titleText.setTag(s.getId());
return view;
}
}
所有帮助非常感谢:)
约翰,尝试使用raptureinvenice.com的WebImageView。我最近重构了我的代码来使用这个简单轻量级的库,到目前为止,这么好。它很容易提供两级缓存,同时更新多个目标,并且非常容易设置。它看起来似乎下降了大约1/20个显示图像的请求。除了这个可能是图书馆过错的潜伏错误之外,它非常好。
不错,这与我所拥有的非常相似,但我无法分享我的代码,因为我为我的雇主写了代码。有趣的是,我认为我在我的实现中似乎也有类似的错误。我相信这与内存使用有关。我唯一的问题是,它使用SoftReferences,它在Android上有些破碎。我使用LruCache,我宁愿反正给我一个一致的最大缓存大小。 – kabuko
谢谢,这很理想! –
这是一个烦人复杂的问题。我甚至有两层缓存(内存和磁盘缓存)来平滑第二个线程中更智能的更新(您的情况为AsyncTask)的性能。有很多小的细节,如尝试不要下载同一图像两次(这是一个问题,如果你有多个列表项相同的公司标志)。通过跟踪与ImageView关联的当前URL是什么,并确保与设置最终图像之前传递给AsyncTask的相同,可以简单地修复显示错误图像的主要问题。也许可以将这些信息存储在HashMap中。实际上,我只是将所有这些东西都抽象成了一个WebImageView类,它扩展了ImageView以使其全部可重用。
对于RAM缓存图像,您可以使用SoftReference
。因此,代码会是这样的:
ImageView iv = (ImageView) view.findViewById(R.id.thumbnail);
// s.getDrawable returns a SoftReference to Drawable
SoftReference<Drawable> thumbRef = s.getDrawable();
Drawable thumb = thumbRef.get();
if (thumb == null) {
new DownloadImageTask(s).execute();
} else {
iv.setDrawable(thumb);
}
DownloadImageTask
将获得的图像,包装成SoftReference
,设置基准以收集并通知适配器垫层数据已经改变。设计可以更高效,但这只是一个粗略的计划。
这看起来相当有希望 - 我会给它一个镜头,让你知道我如何继续。谢谢:) –
如果你只是需要下载一些图片,如果你不需要显示大的图像,你可以使用下面的代码。它将位图存储在内存中。它的效果很好,图像不是太大。
我改变了我的代码,您的情况:
进口android.graphics.Bitmap;
公共类供应商{
// Data
private String mText;
private Bitmap mImage;
private String mImageUrl;
// Flags
private boolean mIsLoading;
public Supplier() {
mText = "test";
mImage = null;
mImageUrl = "image_url";
mIsLoading = false;
}
public Supplier setLoadingStatus(boolean pIsLoading){
mIsLoading = pIsLoading;
return this;
}
public boolean isLoading(){
return mIsLoading;
}
public Supplier setImageUrl(String pImageUrl){
mImageUrl = pImageUrl;
return this;
}
public String getImageUrl(){
return mImageUrl;
}
public Supplier setText(String pText){
mText = pText;
return this;
}
public String getText(){
return mText;
}
public Supplier setImageBitmap(Bitmap bmp){
mImage = bmp;
return this;
}
public Bitmap getImageBitmap(){
return mImage;
}
}
进口产生java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList;
import android.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics。BitmapFactory; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;
公共类TestAdapter延伸BaseAdapter {
protected static final int MSG_IMAGE_DOWNLOADED = 0;
// Constants
private final String TAG = "TestAdapter";
private ArrayList<Supplier> mItems;
private Context mContext;
private LayoutInflater mLf;
private Handler mHandler;
public TestAdapter(Context pContex) {
mContext = pContex;
mLf = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItems = new ArrayList<Supplier>();
mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_IMAGE_DOWNLOADED:
if(null != msg.obj){
mItems.get(msg.arg1).setImageBitmap((Bitmap)msg.obj)
.setLoadingStatus(false);
notifyDataSetChanged();
}
break;
default:
break;
}
};
};
}
public TestAdapter addItem(Supplier pItem){
mItems.add(pItem);
return this;
}
@Override
public int getCount() {
return mItems.size();
}
@Override
public Supplier getItem(int position) {
return mItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if(null == convertView){
convertView = mLf.inflate(R.layout.your_resource, parent, false);
vh = new ViewHolder();
vh.mTextView = (TextView)convertView.findViewById(R.id.your_textview_from_resource);
vh.mImage = (ImageView)convertView.findViewById(R.id.yout_imageview_from_resource);
convertView.setTag(vh);
}else{
vh = (ViewHolder)convertView.getTag();
}
vh.mTextView.setText(mItems.get(position).getText());
if(mItems.get(position).getImageBitmap() == null && !mItems.get(position).isLoading()){
// download image
downloadImage(mItems.get(position).getImageUrl(), position);
// set a flag to know that the image is downloading and it is not need to
// start another download if the getView method is called again.
mItems.get(position).setLoadingStatus(true);
}else{
vh.mImage.setImageBitmap(mItems.get(position).getImageBitmap());
}
return null;
}
private void downloadImage(String pImageUrl, int pItemPosition){
final int cItemPosition = pItemPosition;
final String cImageUrl = pImageUrl;
Thread tGetImage = new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
msg.what = MSG_IMAGE_DOWNLOADED;
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bmImg;
URL myFileUrl = null;
try {
myFileUrl= new URL(cImageUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is, null, options);
is.close();
conn.disconnect();
msg.obj = bmImg;
} catch (IOException e) {
e.printStackTrace();
}
msg.arg1 = cItemPosition;
mHandler.sendMessage(msg);
}
});
tGetImage.start();
}
private class ViewHolder{
public TextView mTextView;
public ImageView mImage;
}
}
的代码没有进行测试,但应该工作。
你有没有考虑过使用SimpleAdapter和缓存? –
@丹,我没有。如何缓存?保存到SD卡?我不确定那将如何工作。 –
如果您要处理的不是字符串数组,而是SimpleAdapter更好。对于缓存,您可以将其保存到SD中,并有一些标准来检查更新。 –