使用回调异步加载列表视图中的图像
Posted
技术标签:
【中文标题】使用回调异步加载列表视图中的图像【英文标题】:Loading images in listview asynchronously with callback 【发布时间】:2014-02-12 12:01:39 【问题描述】:我在我的应用程序中使用 Parse,为了加载我的“个人资料”图像,我需要检索一个所谓的 Parsefile。当 Parsefile 下载完成时,它使用回调来通知它何时完成。现在这通常是一种不错的处理方式,但我在使用 Listview 并使用 Asynctask 下载图像时遇到了问题。
问题如下:
在 getView
方法中的 ListView 适配器中,我创建了一个 AsyncTask 并执行它,这个 AsyncTask 启动了 retrieveProfileImage(callBack)
函数。在我的回调中,我只需在 UI 线程上启动一个 Runnable 以使用新的(检索到的图像)更新视图中的 ImageView。然而,问题似乎是,一旦我启动我的 AsyncTask,视图就会返回。所以我无法将其他图像设置为正确的行。我希望我的代码能更清楚地说明我的问题。
ListAdapter:
public class FriendListAdapter extends ArrayAdapter<Profile>
private int resource;
private Context context;
private List<Profile> friends;
private Profile fProfile;
private Bitmap profileImageBitmap;
private ProgressBar friendImageProgressBar;
//ui
private ImageView friendImage;
public FriendListAdapter(Context context, int resource,
List<Profile> objects)
super(context, resource, objects);
this.context = context;
this.resource = resource;
this.friends = objects;
@Override
public View getView(int position, View convertView, ViewGroup parent)
TextView friendName = null;
friendImage = null;
View rowView = convertView;
if (rowView == null)
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
rowView = inflater.inflate(R.layout.friendslist_row, null);
friendName = (TextView) rowView.findViewById(R.id.fName);
friendImage = (ImageView) rowView
.findViewById(R.id.fImage);
friendImageProgressBar = (ProgressBar) rowView.findViewById(R.id.friendImageProgressBar);
else
friendName = (TextView) convertView.findViewById(R.id.fName);
friendImage = (ImageView) convertView.findViewById(R.id.fImage);
friendImageProgressBar = (ProgressBar) convertView.findViewById(R.id.friendImageProgressBar);
fProfile = friends.get(position);
DownloadProfileImage dImg = new DownloadProfileImage();
dImg.execute();
friendName.setText(fProfile.getName());
return rowView;
private class DownloadProfileImage extends AsyncTask<Void, Integer, String>
@Override
protected String doInBackground(Void... arg0)
Log.d("logpp", "Starting download image for " + fProfile.getName());
fProfile.retrieveProfileImage(new ProfileImageCallback());
return null;
private class ProfileImageCallback extends GetDataCallback
@Override
public void done(byte[] bytearray, ParseException e)
if (e == null)
Log.d("logpp", "Done downloading image for " + fProfile.getName() + ". Setting bitmap to:" +
" " + friendImage.getId());
profileImageBitmap = BitmapManager
.getBitmapFromByteArray(bytearray);
((Activity) context).runOnUiThread(new UpdateUi());
private class UpdateUi implements Runnable
@Override
public void run()
friendImage.setImageBitmap(profileImageBitmap);
friendImage.setVisibility(View.VISIBLE);
friendImageProgressBar.setVisibility(View.INVISIBLE);
retrieveProfileImage 方法:
public void retrieveProfileImage(GetDataCallback callBack)
this.image.getDataInBackground(callBack);
我希望有人能帮我解决这个问题。
问候,
提姆
【问题讨论】:
对 Universal Image Loader 和 picasso 等库使用延迟加载。使用 UIL ***.com/questions/16789676/… @Raghunandan 问题是,我不能使用 URL。我没有图像 url,我可以检索图像(位图)的唯一方法是使用回调。解析库将我限制在那里。 【参考方案1】:我通过以下代码解决了这个问题
public View getView(int position, View convertView, ViewGroup parent)
try
if (inflater == null)
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null)
convertView = inflater.inflate(R.layout.answer_item, null);
TextView name = (TextView) convertView.findViewById(R.id.textView_ans_user_name);
TextView body = (TextView) convertView.findViewById(R.id.textView_ans_user_body);
TextView timestamp = (TextView) convertView.findViewById(R.id.textView_ans_user_timestamp);
final CircularImageView thumbnail = (CircularImageView) convertView.findViewById(R.id.imageView_ans_user);
Parse_answer_model ans = answers.get(position);
name.setText(ans.getAns_by());
body.setText(ans.getAns_body());
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
sdfAmerica.setTimeZone(TimeZone.getDefault());
String sDateInAmerica = sdfAmerica.format(ans.getCreatedAt());
timestamp.setText(sDateInAmerica);
ParseQuery<User> query = ParseQuery.getQuery("_User");
query.whereEqualTo("username", ans.getAns_by());
query.getFirstInBackground(new GetCallback<User>()
public void done(User user, ParseException e)
// TODO Auto-generated method stub
if (e == null)
img.DisplayImage(user.getprofile_pic_url(), thumbnail, false);
else
);
catch (Exception e)
e.printStackTrace();
把你的图像视图作为最终的,不要让它全局化,你从 geturl() 方法获取图像 url,它是由 parse 定义的,你可以在下面的例子中使用
ParseFile fileObject = (ParseFile) object.get("image_file");
User user = new User();
user = (User) ParseUser.getCurrentUser();
user.setProfile_pic_url(fileObject.getUrl().toString());
user.saveInBackground();
更新
昨天我找到了新的解决方案,您可以通过以下代码获取与解析对象相关的用户数据,并对模型类进行一些更改。
void getchats()
pd.show();
ParseQuery<Parse_chat_dialogs> query = ParseQuery.getQuery("chat_dialogs");
query.addDescendingOrder("updatedAt");
query.whereContains("users", ParseUser.getCurrentUser().getUsername());
query.findInBackground(new FindCallback<Parse_chat_dialogs>()
public void done(List<Parse_chat_dialogs> dilogs, ParseException e)
if (e == null)
pd.hide();
dialoglist = (ArrayList<Parse_chat_dialogs>) dilogs;
adp = new ChatDialogAdapter(Chat_list.this, dialoglist);
list.setAdapter(adp);
for (int i = 0; i < dialoglist.size(); i++)
ParseQuery<User> query = ParseQuery.getQuery("_User");
query.whereEqualTo("username", dialoglist.get(i).getUsers().trim()
.replace(ParseUser.getCurrentUser().getUsername(), "").replace(",", ""));
User user = new User();
try
user = query.getFirst();
dialoglist.get(i).setFirstname(user.getFirstname());
dialoglist.get(i).setLastname(user.getLastname());
dialoglist.get(i).setProfileurl(user.getprofile_pic_url());
adp.notifyDataSetChanged();
catch (ParseException e1)
// TODO Auto-generated catch block
e1.printStackTrace();
else
Toast.makeText(Chat_list.this, e.getMessage(), Toast.LENGTH_SHORT).show();
);
如上例所示,我在 parseobejct 模型类中添加了三个新参数,用于存储用户的名字、姓氏和个人资料 url 的值。 我也在分享模型类以获得更多想法
@ParseClassName("chat_dialogs")
public class Parse_chat_dialogs extends ParseObject
private String firstname;
private String lastname;
private String profileurl;
public String getFirstname()
return firstname;
public void setFirstname(String firstname)
this.firstname = firstname;
public String getLastname()
return lastname;
public void setLastname(String lastname)
this.lastname = lastname;
public String getProfileurl()
return profileurl;
public void setProfileurl(String profileurl)
this.profileurl = profileurl;
/////////////////////////////////////////////////////////////////////////////
public String getLast_message()
return getString("last_message");
public void setLast_message(String value)
put("last_message", value);
public String getUsers()
return getString("users");
public void setUsers(String value)
put("users", value);
【讨论】:
【参考方案2】:这个怎么样!
不要在适配器类中使用 AsyncTask,而是在为列表视图设置适配器的 MainActivity 中使用它。并在 Callback 或 postExecute 中的 done 方法中更新对象/对象并调用 notifyDataSetChanged()。
所以,基本上你可以在你的适配器类中有一个更新方法,比如说,像这样,
public void updateObject(int pos, byte[] byteArray)
//Assuming your Profile Object has some member to store this image data
friends.get(pos).setImageData(byteArray); //friends is the list in adapter class and setImageData may be the setter in your Profile object class
notifyDataSetChanged();
在 getView() 中,你可以做这样的事情
profileImageBitmap = BitmapManager
.getBitmapFromByteArray(friends.get(pos).getImageData);
friendImage.setImageBitmap(profileImageBitmap);
【讨论】:
以上是关于使用回调异步加载列表视图中的图像的主要内容,如果未能解决你的问题,请参考以下文章