我有一个包含ImageView和TextView的ListView。我正在继承ArrayAdapter,以便我可以通过子类AsyncTask从Internet加载图像。到目前为止一切都很好。
问题是,如果我尝试使用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;
}
}
非常感谢所有帮助:)
答案 0 :(得分:2)
John,尝试使用raptureinvenice.com的WebImageView。我最近重构了我的代码,使用这个简单轻量级的库,到目前为止,非常好。它可以轻松提供两级缓存,同时更新多个目标,并且设置非常简单。看起来似乎放弃了大约1/20的显示图像的请求。除了可能是图书馆错误的这个潜伏的错误,它是非常好的。
答案 1 :(得分:1)
这是一个令人烦恼的复杂问题。我有两层缓存(内存和磁盘缓存),以便在第二个线程(在您的情况下为AsyncTask)中更智能的更新之上平滑性能。有很多小细节,比如尝试不下载两次相同的图像(如果你有多个列表项的相同公司徽标,这是一个问题)。显示错误图像的主要问题可以通过跟踪与ImageView关联的当前URL来确定,并确保与设置最终图像之前传入AsyncTask的URL相同。您可以将该信息存储在HashMap中。我实际上只是将所有这些内容抽象到一个WebImageView类中,该类扩展了ImageView以使其全部可重用。
答案 2 :(得分:1)
对于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
,设置对集合的引用并通知适配器底层数据已更改。对于cource来说,设计可能更有效,但这只是一个粗略的计划。
答案 3 :(得分:1)
如果您只需下载一些图像,并且不需要显示大图像,则可以使用以下代码。它将位图存储在内存中。效果很好的是图像不是太大。
我将代码更改为您的情况:
导入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;
}
}
import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList;
导入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;
}
}
代码未经过测试但应该有效。