Android - 通过 getView 函数在自定义 listView 适配器内设置 ImageView 的源无法正常工作
Posted
技术标签:
【中文标题】Android - 通过 getView 函数在自定义 listView 适配器内设置 ImageView 的源无法正常工作【英文标题】:Android - Set the Source of an ImageView inside a custom listView adapter from the getView function does not work properly 【发布时间】:2015-06-11 22:54:56 【问题描述】:为长标题道歉。
我正在构建一个 android 应用程序,其中一个 Activity 包含一个自定义 listView。在我的自定义列表视图的布局中,我有一个图像视图和三个文本视图。我正在从数据库中获取数据,并且行数据没有问题,因为它们是准确的。但是,我在显示 ImageViews 时遇到问题。
我填充 imageView 的方法是从数据库中获取存储的 imagePath,解析该 URL(仅限本地服务器),然后使用它设置 ImageViews 位图。
在我的 customListView 类的getView
函数中,我创建了一个线程来处理来自数据库的 url,然后我对其进行解析,然后将其设置为 ImageView 的位图。
这是我的getView
函数:
public View getView(int position, View convertView, ViewGroup parent)
if (convertView == null)
convertView = layoutInflater.inflate(R.layout.nominees_list_layout, null);
holder = new ViewHolder();
holder.firstName = (TextView) convertView.findViewById(R.id.nomineesListFirstName);
holder.middleName = (TextView) convertView.findViewById(R.id.nomineesListMiddleName);
holder.lastName = (TextView) convertView.findViewById(R.id.nomineesListLastName);
holder.photo = (ImageView) convertView.findViewById(R.id.nomineesListCandidatePhoto);
convertView.setTag(holder);
else
holder = (ViewHolder) convertView.getTag();
holder.firstName.setText(listData.get(position).getFirst_name());
holder.middleName.setText(listData.get(position).getMiddle_name());
holder.lastName.setText(listData.get(position).getLast_name());
new setDisplayPhoto().execute(listData.get(position).getPicture_path());
return convertView;
如您所见,我正在初始化视图组件,然后根据从数据库中获取的 listData 设置它们的值。显示的数据都是正确的。然后,我对 imageView 所做的是创建一个 AsyncTask 并在那里提供数据。
这是我的异步任务:
private class setDisplayPhoto extends AsyncTask<String, Void, String>
String toastMessage = "Downloading nominees photo finished.";
Bitmap mIcon_val;
@Override
protected void onPreExecute()
super.onPreExecute();
@Override
protected String doInBackground(String... params)
Log.d("","doInBackGround Started");
String photo_url_str = "http://192.168.0.10:8888/server/path/here/"
+ params[0];
try
Log.d("","photo_url_str = " + photo_url_str);
newurl = new URL(photo_url_str);
catch (MalformedURLException e)
e.printStackTrace();
try
mIcon_val = BitmapFactory.decodeStream(newurl.openConnection().getInputStream());
holder.photo.setImageBitmap(mIcon_val);
catch (IOException e)
e.printStackTrace();
return "Executed!";
@Override
protected void onPostExecute(String result)
super.onPostExecute(result);
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show();
但是,照片不会出现,如果出现,有时照片会混乱。
当源是从本地服务器获取时,有人可以帮助我在 customListView 适配器的 getView 功能期间如何正确设置 imageView 的图像源吗?感谢您的任何帮助。
【问题讨论】:
网络操作总是在辅助线程中运行....所以如果你给出一个url路径并尝试下载它会在其他线程中下载它,所以最好有你自己的asynctask尝试下载图像下载后会回电给您的适配器。根据位置的可见性显示图像。 我正试图取消实际下载文件,因为我希望系统能够灵活地从服务器获取文件而无需下载它。 在您的情况下,维护列表项的位置非常重要...因为列表视图基于回收概念。因此,如果您传递 imageview 对象,无论哪个位置可见,您的线程都会尝试将图像设置为该图像视图 您正在下载它,如果不下载它就无法显示服务器图像..只是您没有将其保存在辅助存储中..它将在您的主内存中.. 我不推荐这种图像下载,因为在 android 中保留了这么多图像在主内存中,要么最终导致内存不足异常,要么每次当用户滚动时,你最终都会下载许多相同的副本图片.. 【参考方案1】:它不起作用的原因是处理图像下载、缓存和视图回收比您的代码处理的要复杂得多。
我可以指出一些我可以从您的代码中看到的错误,但肯定还有更多:
没有 RAM 缓存,这意味着当用户将视图滚动出视图然后返回视图时,图像将再次从服务器下载。 没有磁盘缓存,这意味着如果用户在列表中滚动太远,或者如果他/她离开应用程序几分钟后回来,图像将再次从服务器下载 在这一行holder.photo.setImageBitmap
上,您正尝试在后台线程中更改 View
。
AsyncTask(从某些 API 开始)是一个单线程类,这意味着您的所有下载都将一个接一个地排队,因此用户可能会在看到任何内容之前盯着空白屏幕一段时间。
您没有取消任务,因此在回收过程中,调用 setImageBitmap
可能发生在错误的项目上。
换行:
new setDisplayPhoto().execute(listData.get(position).getPicture_path());
与:
Picasso.with(convertView.getContext())
.load("http://192.168.0.10:8888/server/path/here/" +
listData.get(position).getPicture_path())
.into(holder.photo);
为此,您需要一个额外的库,您可以通过在清单中添加以下行来添加它:
compile 'com.squareup.picasso:picasso:2.5.2'
有关图书馆的更多信息,请查看:http://square.github.io/picasso/
【讨论】:
我必须在 AsyncTask 中执行此操作吗? 不!直接替换getView
里面的代码就可以扔掉AsyncTask的代码了。 Picasso 库处理有关线程的所有问题。
哦,我的天哪,听起来真的非常非常非常好。我会尽快检查并尽快反馈。
您,好心的先生,是救生员。非常感谢!
救生员是那些创建图书馆的人。我很高兴传播这个词【参考方案2】:
package com.example.jojo.gridview;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
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 java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
public class GirdViewAdapter extends BaseAdapter
private Activity activity;
private ArrayList<String> ar;
private LayoutInflater inflater;
public GirdViewAdapter(ArrayList<String> ar, Activity con)
activity = con;
this.ar=ar;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
private class ViewHolder
public TextView textView;
public ImageView imageView;
@Override
public int getCount()
// TODO Auto-generated method stub
return ar.size();
@Override
public Object getItem(int arg0)
// TODO Auto-generated method stub
return null;
@Override
public long getItemId(int arg0)
// TODO Auto-generated method stub
return 0;
@Override
public View getView(int position, View arg1, ViewGroup arg2)
// TODO Auto-generated method stub
View rowView = arg1;
ViewHolder viewHolder;
if (arg1 == null)
rowView = inflater.inflate(R.layout.style_view, null);
viewHolder = new ViewHolder();
viewHolder.textView = (TextView) rowView.findViewById(R.id.textView);
viewHolder.imageView = (ImageView) rowView.findViewById(R.id.imageView);
rowView.setTag(viewHolder);
else
viewHolder = (ViewHolder) rowView.getTag();
String rowData[] = this.ar.get(position).split("\\|");
viewHolder.textView.setText(rowData[0] );
setImageView(viewHolder.imageView, rowData[1] );
return rowView;
private void setImageView(ImageView imageView, String url)
class ImageDownloadHelper extends AsyncTask<String, String, Bitmap>
@Override
protected Bitmap doInBackground(String... params)
// TODO Auto-generated method stub
URL url;
String _url = params[0];
Log.e("url",_url );
BufferedOutputStream out;
InputStream in;
BufferedInputStream buf;
try
url = new URL(_url);
in = url.openStream();
buf = new BufferedInputStream(in);
Bitmap bMap = BitmapFactory.decodeStream(buf);
if (in != null)
in.close();
if (buf != null)
buf.close();
return bMap;
catch (Exception e)
Log.e("Error reading file", e.toString());
return null;
ImageDownloadHelper downloadHelper = new ImageDownloadHelper();
downloadHelper.execute(url);
try
imageView.setImageBitmap(downloadHelper.get());
catch (Exception e)
e.printStackTrace();
【讨论】:
以上是关于Android - 通过 getView 函数在自定义 listView 适配器内设置 ImageView 的源无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章
Android ListView 不调用适配器的类 getView() 函数
适用于Android ListView的适配器类getView()函数