ANDROID:加载中的ListView异步图片加载中、图片、ANDROID、ListView

2023-09-06 13:26:19 作者:八度余温

我想用一个自定义的适配器(图文)显示一个ListView。

I 'd like to display a ListView with a customized adapter (with picture and text).

图像从远程服务器加载的,所以我决定用AsyncTask的。

Images are loaded from distant servers, so I have decided to use AsyncTask.

其实,图像显示良好,但如果我赶紧向下滚动,在1/2 secondes会显示一个错误的画面(加载后,正确的图片显示)

Actually, pictures are well displayed but if I scroll down quickly, a wrong picture is displayed during 1/2 secondes (after loading, correct picture appears)

下面是我的适配器的code:

Here is my adapter's code:

public class GiAdapter extends BaseAdapter {

    private Context mContext;

    private List<SiteStaff> mListAppInfo;
    private HashMap<Integer, ImageView> views;
    private HashMap<String,Bitmap> oldPicts = new  HashMap<String,Bitmap>();
    private LayoutInflater mInflater;
    private boolean auto;

    private final String BUNDLE_URL = "url";
    private final String BUNDLE_BM = "bm";
    private final String BUNDLE_POS = "pos";
    private final String BUNDLE_ID = "id";

    public GiAdapter(Context context, List<SiteStaff> list) {
        mContext = context;
        mListAppInfo = list;
        views = new HashMap<Integer, ImageView>();
        mInflater = LayoutInflater.from(mContext);

    }

    @Override
    public int getCount() {
        return mListAppInfo.size();
    }

    @Override
    public Object getItem(int position) {
        return mListAppInfo.get(position).getId();
    }

    @Override
    public long getItemId(int position) {
        return mListAppInfo.get(position).getId();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LinearLayout layoutItem;

        // reuse of convertView
        if (convertView == null) {
            layoutItem = (LinearLayout) mInflater.inflate(R.layout.auto_gi, parent, false);
        } else {
            layoutItem = (LinearLayout) convertView;
        }

        // infos for the current element
        SiteStaff entry = mListAppInfo.get(position);

        //set some text fields
        TextView name = (TextView) layoutItem.findViewById(R.id.name);
        TextView size = (TextView) layoutItem.findViewById(R.id.size); 

        name.setText(entry.getName());
        size.setText(entry.getSize());

        // get the imageView for the current object
        ImageView v = (ImageView) layoutItem.findViewById(R.id.gi_image);

        // put infos in bundle and send to the LoadImage class
        Bundle b = new Bundle();

        //url of the pict
        b.putString(BUNDLE_URL, entry.getUrl());

        //position in the listView
        b.putInt(BUNDLE_POS, position);

        //id of the current object
        b.putInt(BUNDLE_ID, entry.getId());

        //put info in the map in order to display in the onPostExecute
        views.put(position, v);

        // thread
        new LoadImage().execute(b);

        return layoutItem;

    }

    //asyncTackClass for loadingpictures
    private class LoadImage extends AsyncTask<Bundle, Void, Bundle> {

        @Override
        protected Bundle doInBackground(Bundle... b) {

            Bitmap bm =null;

            //cache: for better performance, check if url alredy exists
            if(oldPicts.get(b[0].getString(BUNDLE_URL))==null){
                bm = Utils.getBitMapFromUrl(b[0].getString(BUNDLE_URL));
                oldPicts.put(b[0].getString(BUNDLE_URL),bm);
            }else{
                bm = oldPicts.get(b[0].getString(BUNDLE_URL));
            }

            // get info from bundle
            Bundle bundle = new Bundle();
            bundle.putParcelable(BUNDLE_BM, bm);
            bundle.putInt(BUNDLE_POS, b[0].getInt(BUNDLE_POS));

            return bundle;

        }

        @Override
        protected void onPostExecute(Bundle result) {
            super.onPostExecute(result);

            //get picture saved in the map + set
            ImageView view = views.get(result.getInt(BUNDLE_POS));
            Bitmap bm = (Bitmap) result.getParcelable(BUNDLE_BM);

            if (bm != null){ //if bitmap exists...
                view.setImageBitmap(bm);
            }else{ //if not picture, display the default ressource
                view.setImageResource(R.drawable.unknow);
            }

        }

    }

}

感谢您!

推荐答案

这发生在我身上了。我想通了,是新的图像得到绑定的ImageView之前,已显示了,而旧的。在你的情况下,正在发生的事情是,你的正确的信息是显示onPostExecute(),这需要一段时间,而在这之前的任何数据集在convertview正在显示。有2种方式ü可以多为解决这一问题,

This happened to me too. What I figured out was that before the new image was getting bound to the imageview, the old one was displayed for a while. In your case, what is happening is that your correct info is showing onPostExecute(), which takes sometime, and before that whatever data was set in the convertview is being shown. There are 2 ways u could mostly fix this,

在你的getView(),改如果{} ...其他{}块只是

In your getView(), change the if{}... else{} block to just

layoutItem = (LinearLayout) mInflater.inflate(R.layout.auto_gi, parent, false);

设置ImageView的在getView(),直到onPostExecute()被调用一些图像占位符。

set the imageview with some placeholder image in getView() till onPostExecute() is called.

希望这有助于。