Picasso loading of image spawned inside AsyncTask

匿名 (未验证) 提交于 2019-12-03 02:38:01

问题:

So I am trying to use the Picasso Library for image downloading and caching. In order to get the contactUri to pass to Picasso I need to make a query to the Contacts Content Provider. Since I don't want to block the main UI thread to get the contactId, I have put this in an AsyncTask. And once I get that contactId, I make the call to Picasso in the onPostExecute() method of the AsyncTask.

However, I am noticing a flickering that shows up when I scroll through my ListView quickly. It seems to me that there is an issue with the ViewHolder since the recycled views are displaying the previous image before setting the appropriate image. Is there anyway to avoid this?

public class ConversationThreadsCursorAdapter extends SimpleCursorAdapter {      // region Constants     private static final int RECIPIENT_IDS_COLUMN_INDEX = 3;     private static final int ID2_COLUMN_INDEX = 0;     private static final int ADDRESS_COLUMN_INDEX = 1;     // endregion      // region Variables     private final String DEBUG_TAG = getClass().getSimpleName().toString();      private Context mContext;     protected Drawable mDefaultPicDrawable;     protected ContentResolver mContentResolver;     protected LinearLayout.LayoutParams mContactPicLayoutParams;     // endregion      // region Constructors     public ConversationThreadsCursorAdapter(Context context, int layout,     Cursor c, String[] from, int[] to, int flags) {         super(context, layout, c, from, to, flags);         mContext = context;         mDefaultPicDrawable = mContext.getResources().getDrawable(         R.drawable.ic_contact_picture);         mContactPicLayoutParams = new LinearLayout.LayoutParams(         mDefaultPicDrawable.getIntrinsicWidth(),         mDefaultPicDrawable.getIntrinsicHeight());      }     // endregion      public View getView(final int position, View convertView, ViewGroup parent) {         ViewHolder viewHolder = null;          if (convertView == null) {             convertView = mLayoutInflater.inflate(R.layout.simple_message, null);              // Creates a ViewHolder and store references to the children             // views we want to bind data to.             viewHolder = setupViewHolder(convertView);              convertView.setTag(viewHolder);          } else {             // Get the ViewHolder back to get fast access to the TextView             // and the ImageView.             viewHolder = (ViewHolder) convertView.getTag();             viewHolder.task.cancel(true);           }          mCursor = getCursor();          mCursor.moveToPosition(position);          viewHolder.position = position;          String recipient_ids = mCursor.getString(RECIPIENT_IDS_COLUMN_INDEX);          String[] recipients = recipient_ids.split(" ");          viewHolder.task = new AddressFetcherTask(viewHolder, position);         viewHolder.task.execute(recipients);           return convertView;      }      // region Helper Methods     private ViewHolder bindUIElements(View convertView) {         ViewHolder viewHolder = new ViewHolder();          viewHolder.contactBadge = (QuickContactBadge) convertView.findViewById(R.id.contact_pic);         return viewHolder;     }      private ViewHolder setupViewHolder(View convertView) {         ViewHolder viewHolder = bindUIElements(convertView);          viewHolder.contactBadge.setLayoutParams(mContactPicLayoutParams);         return viewHolder;     }     // endregion      // region Inner Classes      private class ViewHolder {         QuickContactBadge contactBadge;         int position;     }      private class AddressFetcherTask extends AsyncTask  {         private ViewHolder mViewHolder;         private int mPosition;          public AddressFetcherTask(ViewHolder viewHolder, int position) {             mViewHolder = viewHolder;             mPosition = position;         }          @Override         protected Integer doInBackground(String[]...recipients) {             String recipient = recipients[0][0];             Log.d(DEBUG_TAG, "recipient is " + recipient);             Cursor c = mContentResolver.query(             Uri.parse("content://mms-sms/canonical-addresses"), null, "_id = " + recipient, null, null);              String _id = "";             String address = "";             while (c.moveToNext()) {                 _id = c.getString(ID2_COLUMN_INDEX);                 address = c.getString(ADDRESS_COLUMN_INDEX);             }             c.close();              int contactId;             if (address != null) {                 contactId = ContactsUtils.getContactId(mContext, address, "address");             } else {                 contactId = Integer.valueOf(address);             }             return contactId;         }          @Override         protected void onPostExecute(Integer contactId) {              if (mViewHolder.position == mPosition) {                 Picasso.with(mContext)                     .load(getContactUri(contactId))                     .placeholder(R.drawable.ic_contact_picture)                     .into(mViewHolder.contactBadge);              }         }     }     // endregion  } 

回答1:

Just set the imageview to null in within getView and it should remove what you are experiencing for the most part you'll be right.

The other tiny tiny corner case aspect is that when your asynctask arrives at postExecute, the view might still exist, but it might have already been assigned a different contact to load up (it's been recycled).

You need to put some kind of tag in the viewholder, and then check that it is still the same when you go to set it in postexecute.

To remove the fade in, you need to remove the asynctask from the getview. You need to be able to call picasso within getview, which means having your data ready before arriving at getview.

The below, not quite sure if it will compile, I've done it in a text editor.

But bassically I'm caching results in mCachedContactIds and just reloading the whole table if I need a new one. I've typically found this to be robust. But you can also call the picasso code which I've commented out

public class ConversationThreadsCursorAdapter extends SimpleCursorAdapter {  // region Constants private static final int RECIPIENT_IDS_COLUMN_INDEX = 3; private static final int ID2_COLUMN_INDEX = 0; private static final int ADDRESS_COLUMN_INDEX = 1; private HashMap mCachedContactIds = new HashMap(); // endregion  // region Variables private final String DEBUG_TAG = getClass().getSimpleName().toString();  private Context mContext; protected Drawable mDefaultPicDrawable; protected ContentResolver mContentResolver; protected LinearLayout.LayoutParams mContactPicLayoutParams; // endregion  // region Constructors public ConversationThreadsCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {     super(context, layout, c, from, to, flags);     mContext = context;     mDefaultPicDrawable = mContext.getResources().getDrawable(     R.drawable.ic_contact_picture);     mContactPicLayoutParams = new LinearLayout.LayoutParams(     mDefaultPicDrawable.getIntrinsicWidth(),     mDefaultPicDrawable.getIntrinsicHeight());  } // endregion  public View getView(final int position, View convertView, ViewGroup parent) {     ViewHolder viewHolder = null;      if (convertView == null) {         convertView = mLayoutInflater.inflate(R.layout.simple_message, null);             // Creates a ViewHolder and store references to the children         // views we want to bind data to.         viewHolder = setupViewHolder(convertView);           convertView.setTag(viewHolder);      } else {         // Get the ViewHolder back to get fast access to the TextView         // and the ImageView.         viewHolder = (ViewHolder) convertView.getTag();         viewHolder.task.cancel(true);         viewHolder.contactBadge.setImageDrawable(mDefaultPicDrawable);     }      mCursor = getCursor();      mCursor.moveToPosition(position);      viewHolder.position = position;      String recipient_ids = mCursor.getString(RECIPIENT_IDS_COLUMN_INDEX);      String[] recipients = recipient_ids.split(" ");     String recipient = recipients[0];      if(mCachedContactIds.get(recipient) != null){         Picasso.with(mContext)             .load(getContactUri(mCachedContactIds.get(recipient)))             .placeholder(R.drawable.ic_contact_picture)             .into(mViewHolder.contactBadge);                      } else {         viewHolder.task = new AddressFetcherTask(viewHolder, position);         viewHolder.task.execute(recipients);      }      return convertView;     }  // region Helper Methods private ViewHolder bindUIElements(View convertView) {     ViewHolder viewHolder = new ViewHolder();         viewHolder.contactBadge = (QuickContactBadge) convertView.findViewById(R.id.contact_pic);     return viewHolder; }  private ViewHolder setupViewHolder(View convertView) {     ViewHolder viewHolder = bindUIElements(convertView);         viewHolder.contactBadge.setLayoutParams(mContactPicLayoutParams);     return viewHolder; } // endregion  // region Inner Classes  private class ViewHolder {     QuickContactBadge contactBadge;     int position;     AddressFetcherTask task; }  private class AddressFetcherTask extends AsyncTask  {     private ViewHolder mViewHolder;     private int mPosition;     private String mRecipient;      public AddressFetcherTask(ViewHolder viewHolder, int position) {         mViewHolder = viewHolder;         mPosition = position;     }      @Override     protected Integer doInBackground(String[]...recipients) {         mRecipient = recipients[0][0];         Log.d(DEBUG_TAG, "recipient is " + recipient);         Cursor c = mContentResolver.query(         Uri.parse("content://mms-sms/canonical-addresses"), null, "_id = " + mRecipient, null, null);          String _id = "";         String address = "";         while (c.moveToNext()) {             _id = c.getString(ID2_COLUMN_INDEX);             address = c.getString(ADDRESS_COLUMN_INDEX);         }         c.close();          int contactId;         if (address != null) {             contactId = ContactsUtils.getContactId(mContext, address, "address");         } else {             contactId = Integer.valueOf(address);         }         return contactId;     }      @Override     protected void onPostExecute(Integer contactId) {                                    if (mViewHolder.position == mPosition) {             mCachedContactIds.put(mRecipient, contactId);              Picasso.with(mContext)                 .load(getContactUri(mCachedContactIds.get(recipient)))                 .placeholder(R.drawable.ic_contact_picture)                 .into(mViewHolder.contactBadge);         }                    } }   // endregion  } 

Or if all that's bugging you left is the fade from picasso, then add noFade() to the request.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!