到目前为止,我一直使用一个简单的ArrayAdapter
在ListView
中显示一些项目。现在,我还想在ListView
中的文本旁边显示图像。我有一个名为AsyncTask
的DownloadImageTask
来下载图像。下载工作非常好,但我不知道如何在ListView
中显示图像,也不知道如何使用DownloadImageTask
在ListView
中下载图像。
这是我用来将图像下载到一个DownloadImageTask
中的ImageView
。
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
我还定义了一个ImageView
与ListView
一起下载图像到布局中。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
<ImageView
android:id="@+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView
android:id="@android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
我这样称呼DownloadImageTask
:
new DownloadImageTask((ImageView) findViewById(R.id.image1)).execute(url);
如何使用DownloadImageTask
下载图像并在ListView
中与文本一起显示它们?
发布于 2014-06-26 15:47:33
要实现您想做的事情,您必须创建一个自定义Adapter
。要下载图片,我建议您使用像Picasso这样的库。在下载图片时,毕加索会处理好几乎所有的事情,而且使用起来也不容易,您只需调用它就可以将图像下载到ImageView
中。
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
它已经缓存了图像,并且可以以多种方式转换图像。毕加索是一个非常强大但易于使用的图书馆。
1)实现自定义Adapter
首先,我们需要为ListView
中的每一行创建一个布局,因为您希望显示包含TextView
和ImageView
所需的图像和文本。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageView"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textAlignment="gravity"
android:gravity="center"/>
</RelativeLayout>
现在,我们需要创建一个容器类--称为视图模型--来保存属于ListView
每一行的数据。在您的示例中,此视图模型包含要显示的文本和图像的url:
private class ExampleViewModel {
private String text;
private String imageUrl;
private ExampleViewModel(String text, String imageUrl) {
this.text = text;
this.imageUrl = imageUrl;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
ListViews
使用视图回收。我们可以通过使用称为“视图持有者”的模式来提高ListView
的性能。基本上,我们在每一行中保存对Views
的引用,并将其附加到行本身。这样,我们只需要调用昂贵的findViewById()
一次。这个视图持有者类(我喜欢将它们称为行)还包含一个名为bind()
的方法,用于将视图模型中的数据绑定到每一行中的Views
。我们需要参考TextView
和ImageView
,但也需要毕加索的Context
。我还喜欢将与此行关联的布局定义为该行中的公共常量。
private class ExampleRow {
// This is a reference to the layout we defined above
public static final int LAYOUT = R.layout.list_item;
private final Context context;
private final TextView textView;
private final ImageView imageView;
private ExampleRow(Context context, View convertView) {
this.context = context;
this.imageView = (ImageView) convertView.findViewById(R.id.imageView);
this.textView = (TextView) convertview.findViewById(R.id.textView);
}
public void bind(ExampleViewModel exampleViewModel) {
this.textView.setText(exampleViewModel.getText());
Picasso.with(this.context).load(exampleViewModel.getImageUrl()).into(this.imageView);
}
}
最后,我们需要一个定制的Adapter
来实现这个功能,它实际上没有什么特别之处。唯一有趣的部分是在getView()
中。如有需要,我会评论重要部分:
public class ExampleAdapter extends BaseAdapter {
private final List<ExampleViewModel> viewModels;
private final Context context;
private final LayoutInflater inflater;
public ExampleAdapter(Context context) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.viewModels = new ArrayList<ExampleViewModel>();
}
public ExampleAdapter(Context context, List<ExampleViewModel> viewModels) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.viewModels = viewModels;
}
public List<ExampleViewModel> viewmodels() {
return this.viewModels;
}
@Override
public int getCount() {
return this.viewModels.size();
}
@Override
public ExampleViewModel getItem(int position) {
return this.viewModels.get(position);
}
@Override
public long getItemId(int position) {
// We only need to implement this if we have multiple rows with a different layout. All your rows use the same layout so we can just return 0.
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// We get the view model for this position
final ExampleViewModel viewModel = getItem(position);
ExampleRow row;
// If the convertView is null we need to create it
if(convertView == null) {
convertView = this.inflater.inflate(ExampleRow.LAYOUT, parent, false);
// In that case we also need to create a new row and attach it to the newly created View
row = new ExampleRow(this.context, convertView);
convertView.setTag(row);
}
// After that we get the row associated with this View and bind the view model to it
row = (ExampleRow) convertView.getTag();
row.bind(viewModel);
return convertView;
}
}
这就是你需要的一切。这几乎是Adapter
的最佳实践实现。它使用视图保持模式来获得额外的性能,并与ListView
的视图回收完美地工作。它快速、简洁、简单,几乎没有给开发人员造成错误留下空间,否则ListView
就会慢下来。在您想要显示的数据(全部在ExampleViewModel
中)和如何显示它(在ExampleRow
中)之间有完美的分离。适配器本身也不知道-它应该是这样的!
2)如何使用它
为了使用上面的代码,我们首先需要创建视图模型,这些模型保存我们想要显示的数据:
ExampleViewModel firstRow = new ExampleViewModel("First Row". "http://http://upload.wikimedia.org/wikipedia/commons/6/6f/Freiburger_Alpen.JPG");
ExampleViewModel secondRow = new ExampleViewModel("Second Row". "http://blog.caranddriver.com/wp-content/uploads/2013/05/lamborghini_egoista_three_quarter_front_view.jpg");
ExampleViewModel thirdRow = new ExampleViewModel("Third Row". "http://4.bp.blogspot.com/-vXnf7GjcXmg/UfJZE9rWc2I/AAAAAAAAGRc/x2CIlHM9IAA/s1600/aphoto49721.jpg");
我们需要将所有这些行添加到List
中。
List<ExampleViewModel> viewModels = new ArrayList<ExampleViewModel>();
viewModels.add(firstRow);
viewModels.add(secondRow);
viewModels.add(thirdRow);
在此之后,我们需要创建ExampleAdapter
的一个实例,并在构造函数中传递视图模型的List
。最后,我们只需要将Adapter
设置为ListView
ExampleAdapter adapter = new ExampleAdapter(context, viewModels);
listView.setAdapter(adapter);
您以后可以使用ListView
的viewmodels()
方法修改ExampleAdapter
中显示的项!您只需要记住在修改视图模型之后始终在Adapter
上调用Adapter
:
adapter.viewmodels().remove(0); // Remove first view model
adapter.viewmodels().add(someNewViewModel); // Add some new view model
// Always remember to call this method after modifying the viewmodels.
// This will apply the changes to the ListView.
// If you forget to call this you will get an exception
adapter.notifyDataSetChanged();
我希望我能帮助你,如果你有任何进一步的问题,请随便问!
发布于 2014-06-26 15:09:00
您可以使用外部库,如毕加索或环球图像加载器,他们会给你很多选择。因为它们管理缓存,所以您可以从urls或其他任何地方加载图像,并在几个地方显示它们。
你可以试试:
我不确定,但也许您可以在列表适配器的getView()方法中使用您的getView()方法:
new DownloadImageTask((ImageView) findViewById(R.id.image1)){
@Override
protected void onPostExecute(Bitmap bm) {
//set imageview src with your bitmap }}.execute(url);
}
}.execute(archivo,"investigacion");
https://stackoverflow.com/questions/24433983
复制相似问题