【问题标题】:Android - ListView with images scrolls not smoothAndroid - 带有图像的 ListView 滚动不流畅
【发布时间】:2015-04-22 10:10:35
【问题描述】:

我正在尝试显示带有商品的 ListView。 Goods 是一个带有标题、计数和图像 (BLOB) 的 SQLite 表。所以我的 ListView 不流畅。

我尝试了什么:

  1. 打开相机意图、捕获、获取附加内容并插入到 SQLite。所以我只使用了一个位图。在商品数量少于 50 之前,此方法运行良好。

我走了另一条路:

  1. 打开相机意图,捕捉并保存到文件。
  2. 检查ExifInterface 并在需要时旋转图像。
  3. 使用http://developer.android.com/training/displaying-bitmaps/load-bitmap.html 缩放到300x300 的大小并移动到我的文件夹。此图像文件适用于全屏。
  4. 现在我需要一个缩略图,以便以后将其放入 ListView。所以我使用http://developer.android.com/training/camera/photobasics.html中的setPic()方法将文件(3)缩放到缩略图大小(例如60x60) 并将这个小拇指保存到 SQLite 数据库 Goods 表中。

现在当商品数量超过 100 时,ListView 变得难以滚动。这不是问题的解决方案。

所以我需要一些不同的方法来用图像填充 ListView。

请以正确的方式指导我)))

谢谢!

附:我正在使用自定义 SimpleCursorAdapter 来显示数据:

public class GoodsCursorAdapter extends SimpleCursorAdapter {
    public GoodsCursorAdapter(Context context) {
        super(context, R.layout.cell_goods, null,
                new String[] { "title", "countAvail" },
                new int[] { R.id.lbTitle, R.id.lbCount }, 0);

    }

    private class ViewHolder {
        ImageView imageView;
        TextView lbTitle, lbCount;
    }

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

        ViewHolder viewHolder;

        if (convertView == null){
            LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.cell_goods, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.ivThumb);
            viewHolder.lbTitle = (TextView) convertView.findViewById(R.id.lbTitle);
            viewHolder.lbCount = (TextView) convertView.findViewById(R.id.lbCount);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        mainCursor.moveToPosition(position);
        byte[] byteArray = mainCursor.getBlob(mainCursor.getColumnIndex("photo"));
        if (byteArray != null) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
            Log.d("INFO", mainCursor.getString(mainCursor.getColumnIndex("title"))+": "+String.valueOf(bitmap.getWidth())+"x"+String.valueOf(bitmap.getHeight())+"("+String.valueOf(bitmap.getByteCount()/1024)+"Kb)");
            viewHolder.imageView.setImageBitmap(bitmap);
        } else {
            viewHolder.imageView.setImageResource(R.drawable.ic_action_picture);
        }
        viewHolder.lbTitle.setText(mainCursor.getString(mainCursor.getColumnIndex("title")));
        viewHolder.lbCount.setText(String.format(getString(R.string.lbCount), mainCursor.getString(mainCursor.getColumnIndex("countAvail"))));

        return convertView;
    }

【问题讨论】:

  • @HareshChhelana:我已经使用这种方法进行缩放,请参阅我的问题 :) 我可以在我的getView() 中使用它吗?
  • 是的,尝试在getView()中使用。
  • 再尝试在构造函数或适配器外部加载 getview() 之外的所有位图,然后将其分配给适配器。创建视图时每次从数据库加载图像可能会减慢滚动速度。
  • @user4153589,如果最初加载所有位图,则可能会出现内存不足异常。

标签: android image listview


【解决方案1】:

尝试从 UI 线程加载图像 - 使用 AsyncTask。

类似这样的东西(取自here)

class BitmapWorkerTask extends AsyncTask<Cursor, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Cursor mCursor;;

public BitmapWorkerTask(ImageView imageView) {
    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference<ImageView>(imageView);
}

// Decode image in background.
@Override
protected Bitmap doInBackground(Cursor... params) {
    mCursor = params[0];
    byte[] byteArray = mCursor.getBlob(mCursor.getColumnIndex("photo"));
    if (byteArray != null) {
     Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
    return bitmap;
  }
}

// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
  }
}

所以修改

 if (byteArray != null) {     
  BitmapWorkerTask task = new BitmapWorkerTask(imageView);
  task.execute(mainCursor);
 }else{......}

【讨论】:

  • mm.. 不明白如何将onPostExecute 适配到LitView item.. 能不能给出更详细的解释?
  • @Zain 您还想增加线程池的大小(否则图像解码会出现延迟,因为默认情况下 Executor 在 Android 4 或 3 之后只有一个线程。另外需要进行检查以防止因视图回收而出现问题。
  • 我已将上面的代码修改为您现在可以使用的代码。 @Amit True 在这两个帐户上,但目前,如果 Romowski 可以让它工作,并且更流畅,他可以查看线程池大小和单元重用。
【解决方案2】:

使用惰性列表在列表视图中下载图像。 参考链接:http://www.prandroid.com/2014/07/how-to-lazy-load-of-images-in-listview.html

【讨论】:

  • ooh.. 并将 download from web 函数替换为我的 download from SD and scale 函数。对吗?
  • 是的。惰性列表下载不过是基于优先级处理繁重工作的异步任务。
  • 好的,谢谢,我会尽力回复)
【解决方案3】:

使用分页..获取 5/10 行并加载位图使用 Picasso 或者你可以异步加载位图

编辑

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == 1) {
                    isUserScroll = true;
                } else {
                    isUserScroll = false;
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                if (isUserScroll) {

                    int lastInScreen = firstVisibleItem + visibleItemCount;
                    if (!isDataLoading && (lastInScreen == totalItemCount)) {
                       //load data

                        isDataLoading = true;
                    }
                }
            }
        });

【讨论】:

  • 我想过分页,但没有找到一些关于..以及如何在ListView中可视化分页的文章?
  • 您可以添加逻辑以在列表视图的滚动条上加载下一批
  • 谢谢,我试试这个
【解决方案4】:

在构造函数或适配器外部加载 getview() 外部的所有位图,然后将其分配给适配器。创建视图时每次从数据库加载图像可能会减慢滚动速度。

如果您遇到任何内存问题在预加载图像时尝试将它们缓存在内存中 而不是保存到数据库

【讨论】:

  • 感谢您的回复,但图片数量可能在 1-2 千左右 ))
  • 然后不要保存在数据库中缓存它们,只保存 url 到数据库
【解决方案5】:

好的,我已经尝试了几乎所有你建议的方法。这是我的报告:

  1. @HareshChhelana 的方法是使用inSampleSize 选项(来自BitmapFactory.Options)。方法更好然后在 SQLite 中存储小缩略图(就像我首先做的那样),但是对于超过 200 个带有图像的列表项变得不平滑

  2. @Zain 建议使用 Google 解决方案 (http://developer.android.com/training/displaying-bitmaps/process-bitmap.html)。 这也很好用。

  3. 来自@Prachi 的分页。 工作正常。但我没有添加任何逻辑来加载列表视图的滚动条上的下一批。我的解决方案是:获取前 30 行并使用“下一个 30 行”和“上一个 30 行”按钮。因为如果没有分页的任何方法都不起作用,这种方法对我来说是最后的解决方案,所以我跳过它。 :)

  4. @Pankaj 的建议。我浏览了这门课,它看起来像是可行的解决方案,但我没有尝试过。反正答案很有用。

我找到了一个库,我在我的项目中使用了它: https://github.com/nostra13/Android-Universal-Image-Loader 真的很棒,还有很多有用的设置!

附:对不起我的英语:)

【讨论】:

    猜你喜欢
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多