Android - 通过 getView 函数在自定义 listView 适配器中设置 ImageView 的源无法正常工作
Android - Set the Source of an ImageView inside a custom listView adapter from the getView function does not work properly
抱歉标题太长。
我正在构建一个 Android 应用程序,其中 activity 包含自定义 listView。在我的自定义 listView 的布局中,我有一个图像视图和三个文本视图。我正在从数据库中获取数据,我对行数据没有任何问题,因为它们是准确的。但是,我在显示 ImageView 时遇到问题。
我填充 imageView 的方法是从数据库中获取存储的 imagePath,解析 URL(仅限本地服务器),然后用它设置 ImageViews 位图。
在我的 customListView class 的 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 并在那里提供数据。
这是我的 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 的图像源吗?感谢您的任何帮助。
它不起作用的原因是处理图像下载、缓存和视图回收比您的代码处理的要复杂得多。
我可以指出一些我可以从您的代码中看出错误的地方,但肯定还有更多:
- 没有 RAM 缓存,这意味着当用户将视图滚动出视图然后返回视图时,将从服务器再次下载图像。
- 没有磁盘缓存,这意味着如果用户在列表中滚动太远,或者如果 he/she 离开应用程序几分钟后再回来,图像将从服务器
- 在这一行
holder.photo.setImageBitmap
您正试图在后台线程中更改 View
。
- AsyncTask(从某些 API 开始)是单线程 class,这意味着您的所有下载都将一个接一个地排队,因此用户可能会盯着黑屏一段时间后才看到任何东西。
- 您没有取消任务,因此在回收期间,调用
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/
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 应用程序,其中 activity 包含自定义 listView。在我的自定义 listView 的布局中,我有一个图像视图和三个文本视图。我正在从数据库中获取数据,我对行数据没有任何问题,因为它们是准确的。但是,我在显示 ImageView 时遇到问题。
我填充 imageView 的方法是从数据库中获取存储的 imagePath,解析 URL(仅限本地服务器),然后用它设置 ImageViews 位图。
在我的 customListView class 的 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 并在那里提供数据。
这是我的 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 的图像源吗?感谢您的任何帮助。
它不起作用的原因是处理图像下载、缓存和视图回收比您的代码处理的要复杂得多。
我可以指出一些我可以从您的代码中看出错误的地方,但肯定还有更多:
- 没有 RAM 缓存,这意味着当用户将视图滚动出视图然后返回视图时,将从服务器再次下载图像。
- 没有磁盘缓存,这意味着如果用户在列表中滚动太远,或者如果 he/she 离开应用程序几分钟后再回来,图像将从服务器
- 在这一行
holder.photo.setImageBitmap
您正试图在后台线程中更改View
。 - AsyncTask(从某些 API 开始)是单线程 class,这意味着您的所有下载都将一个接一个地排队,因此用户可能会盯着黑屏一段时间后才看到任何东西。
- 您没有取消任务,因此在回收期间,调用
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/
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();
}
}
}