android – 毕加索在AsyncTask中生成的图像加载

所以我试图使用 Picasso Library进行图像下载和缓存.为了让contactUri传递给Picasso,我需要向Contacts Content Provider提出查询.因为我不想阻止主UI线程获取contactId,所以我把它放在AsyncTask中.一旦我得到那个contactId,我就会在AsyncTask的onPostExecute()方法中调用Picasso.

但是,我注意到当我快速滚动ListView时出现的闪烁.在我看来,ViewHolder存在问题,因为回收视图在设置适当的图像之前显示上一个图像.反正有没有避免这个?

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 < String[],Void,Integer > {
        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);

            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

}

解决方法

只需在getView中将imageview设置为null,它就应该删除你正在经历的大部分内容.

另一个微小的小角落情况是,当你的asynctask到达postExecute时,视图可能仍然存在,但它可能已被分配了一个不同的联系人来加载(它已被回收).

您需要在视图中放置某种标记,然后在postexecute中设置它时检查它是否仍然相同.

要删除淡入,您需要从getview中删除asynctask.您需要能够在getview中调用picasso,这意味着在到达getview之前准备好数据.

下面,不太确定它是否会编译,我已经在文本编辑器中完成了.

但是低音我正在缓存mCachedContactIds中的结果,如果需要一个新表,只需重新加载整个表.我通常发现这很强大.但你也可以调用我已经注释掉的毕加索代码

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<String,Integer> mCachedContactIds = new HashMap<String,Integer>();
// 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 flags) {
    super(context,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,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 < String[],Integer > {
    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"),"_id = " + mRecipient,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");
        } 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

}

或者,如果所有这些让你感到困扰的是毕加索的淡出,那么在请求中添加noFade().

相关文章

Android 如何解决dialog弹出时无法捕捉Activity的back事件 在...
Android实现自定义带文字和图片的Button 在Android开发中经常...
Android 关于长按back键退出应用程序的实现最近在做一个Andr...
android自带的时间选择器只能精确到分,但是对于某些应用要求...