Picasso 加载在 AsyncTask 中生成的图像 [英] Picasso loading of image spawned inside AsyncTask

查看:24
本文介绍了Picasso 加载在 AsyncTask 中生成的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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 < 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, 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,它应该会删除您正在经历的大部分内容,您会是对的.

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.

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

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).

你需要在viewholder里面放一些标签,然后再去postexecute里面设置的时候检查一下还是一样的.

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.

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

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.

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

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<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 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 < String[], Void, 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"), 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

}

或者,如果让您烦恼的只是毕加索的淡入淡出,那么将 noFade() 添加到请求中.

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

这篇关于Picasso 加载在 AsyncTask 中生成的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆