缩略图图像正在重新创建,其位置在滚动ListView时被洗牌

时间:2012-08-15 22:33:40

标签: android listview bitmap android-asynctask imageview

我知道之前已经问过这个问题,而且我已经对此进行了很多搜索,但是在我的问题上找不到合适的答案。

我创建了一个列表,列表中填充了来自JSON的数据。现在在getView()方法内部,我正在使用数据为我的自定义行充气。每行包含Thumbnail,我正在从不同的线程创建每个缩略图。

现在的问题是,一切顺利,直到我不滚动我的列表。当我滚动列表时,我的getView()方法会被连续调用,所有缩略图图像都会被重新创建,并且它的位置会被洗牌。一旦创建了缩略图,我不想重新创建它们,我也希望保持缩略图的顺序。

你能帮助我吗?

非常感谢任何帮助。

我的getView()方法是:

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

            ViewHolder viewHolder = new ViewHolder();
            if (convertView == null) {
                inflater = getLayoutInflater();
                convertView = inflater.inflate(R.layout.list_item_row, parent,
                        false);
                viewHolder.titleText = (TextView) convertView
                        .findViewById(R.id.titleText);
                viewHolder.thumbImage = (ImageView) convertView
                        .findViewById(R.id.thumbnail);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            final String thumbnailURLString = mPostsList.get(position).get(
                    "thumb");
            createBitmapThread = (Thread) getLastNonConfigurationInstance();
            createBitmapThread = new MyThread(thumbnailURLString,
                    viewHolder.thumbImage);
            createBitmapThread.start();
            viewHolder.titleText.setText(title);

            return convertView;
        }

Thread类:

public class MyThread extends Thread {

        String mThumbURLString = null;
        ImageView mImageView = null;

        public MyThread(String thumbnailURLString, ImageView imageView) {
            mThumbURLString = thumbnailURLString;
            mImageView = imageView;
        }

        @Override
        public void run() {

                try {
                    URL newurl = null;
                    try {
                        newurl = new URL(mThumbURLString);
                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                    }
                    try {
                        // Options opts = new Options();
                        /*
                         * opts.inDither = true; opts.inInputShareable = true;
                         * opts.inJustDecodeBounds = true; opts.inPurgeable =
                         * true;
                         */
                        Log.e("", "INSIDE IMAGE DOINBG");
                        mBitmap = BitmapFactory
                                .decodeStream((InputStream) newurl.getContent());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    mHandler.post(new MyRunnable(mImageView));
                } finally {

                }


    }

    public class MyRunnable implements Runnable {

        ImageView mImageView = null;

        public MyRunnable(ImageView imageView) {
            mImageView = imageView;
        }

        public void run() {
            mImageView.setImageBitmap(mBitmap);
        }
    }

2 个答案:

答案 0 :(得分:1)

好的,我在这里做了类似的事情:

对于每个getView,创建一个新的Fetching类并将其放入并发/同步堆栈中。同时,将视图的位图设置为空(或您想要的任何其他内容)。你也可以使用缓存。

该类将包含如何加载数据的信息(例如,位图的url),要更新的视图以及获取的结果(例如,位图本身)。

现在,回到getView,创建并执行一个将在堆栈上使用循环的asyncTask,每次从堆栈中获取一个Fetching类实例(一旦它为空,asyncTask将打破循环并完成),检查需要更新的视图是否仍需要数据(使用其viewHolder)加载位图,将结果设置为Fetching类,并通过publishProgress()函数传递。

在onProgressUpdate方法中,执行与使用Fetching类实例和viewHolder之前相同的检查。如果一切顺利,请更新视图以获取已获取的位图。

可以找到一个很好但复杂的如何处理同一问题的例子here

答案 1 :(得分:1)

我遇到了同样的问题,上面的建议完美无缺,最后 - 谢谢!下面的代码片段:

我的AsyncTask:

protected class LoadImageTask extends AsyncTask<String, Void, String> {
    private View v;

    public LoadImageTask(View v) {
        super();
        this.v = v;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(TAG, "<onPostExecute> load image complete. ");            
    }

    @Override
    protected String doInBackground(String... addresses) {
        String response = "";
        Bitmap bm = null;
        for (String address : addresses) {
            ViewHolder holder = (ViewHolder) v.getTag();
            String name = getNameFromMDN(address);
            if (name != null && name.length() > 0) {
                // get contact ID from name
                long id = getContactID(name);

                if (id != 0) {
                    bm = getThumbnailForId(id);
                    if (bm != null && bm.getHeight() > 0) {
                        bm = resizeBitmap(bm);
                        holder.icon.setImageBitmap(bm);
                        Log.d(TAG, "set thumbnail for " + name + ", id: " + id);

                    }   
                }
            }

            // default icon
            if (bm == null) {
                Log.d(TAG, "using default icon for mdn: " + address + ", name: " + name);
                holder.icon.setImageResource(R.drawable.contact_big);


                /*String s = getContactNameByContactId(person, address);
                s = s.substring(0, 2);
                if (s.length() > 0 && !MDNUtil.isNumber(s)) {
                    Log.d(TAG, "using dynamic icon for person: " + person + ", mdn: " + address + ", name: " + s);

                    icon.setBackgroundColor(Color.BLUE);                    
                    iconText.setText(s);
                    iconText.setTextColor(Color.WHITE);
                    iconText.setVisibility(View.VISIBLE);

                } else {
                    // use generic icon
                    holder.icon.setImageResource(R.drawable.contact_big);
                }*/

            }



        }
        return "";
    }

然后在我的CustomCursorAdapter的bindVew()中:

LoadImageTask load = new LoadImageTask(v);
load.doInBackground(address);

更新:最终使用的是阻止在我的自定义游标适配器中回滚列表视图中的视图:

       @Override
    public int getItemViewType(int position) {
        return position;
    }

    @Override
    public int getViewTypeCount() {
        return 500;
    }