GridView scrollBar:动态添加图像时的不稳定行为

时间:2016-02-17 16:28:39

标签: java android gridview

我正在尝试制作某种图像库,其中图像在后台加载,并在完成加载后动态添加到gridView。图像加载效果很好,但如果gridView中的图像超出屏幕高度,gridView的滚动行为将无法正常工作。

出于测试目的,我正在加载15个虚拟图像,两列中的aligend。加载完所有图像后,根据右侧的scrollBar,gridView的高度似乎符合其内容高度(左侧列中的8个图像或行)。但是,如果我尝试滚动到第4行项目以到达视图的底部(第5/6/7/8行),则scrollBar指示gridView的高度已更改并且已到达视图的底部。滚过第4行是不可能的。如果我再次向上滚动,gridView似乎又包含8行。

same gridView with different content size

左视图 :gridView似乎包含15张图片。 右视图 :gridView突然似乎只包含8张图片

我已经尝试过使用不同的方法,例如提到here的ExpandableHeightViewGrid,但滚动行为是相同的。我会选择在一行中使用一个包含多列图像的gridView(比如使用listView),因为如果我要加载超过15个图像,滚动到底部会非常烦人。

这是我的代码:

  

photo_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

    <!-- This is basically a HorizontalScrollView where i add some buttons -->
    <com.my.HorizontalButtonScrollList
        android:id="@+id/horizontalButtonScrollList"
        android:layout_width="match_parent"
        android:layout_height="50dip">
    </com.my.HorizontalButtonScrollList>

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <GridView
            android:id="@+id/gridView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:columnWidth="100dp"
            android:numColumns="2"
            android:verticalSpacing="0dp"
            android:horizontalSpacing="0dp"
            android:stretchMode="columnWidth"
            android:gravity="center"
            android:scrollbars="vertical">
        </GridView>

    </android.support.v4.widget.SwipeRefreshLayout>

</LinearLayout>
  

PhotoGalleryActivity.java(我简化了代码以提高可读性)

public class PhotoGalleryActivity extends myBaseView {

    private GridView gridView;
    private PhotoGalleryImageAdapter imageAdapter;
    private PhotoGalleryModel[] photoGalleryModels;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.photo_gallery);
        gridView = (GridView) findViewById(R.id.gridView);

        loadImages();
    }

    void loadImages() {

        photoGalleryModels = PhotoGalleryModel.getFakeData();
        imageAdapter = new PhotoGalleryImageAdapter(this, photoGalleryModels);
        gridView.setAdapter(imageAdapter);
    }
}
  

PhotoGalleryImageAdapter(也简化)

public class PhotoGalleryImageAdapter extends BaseAdapter {

    private Context mContext;
    private PhotoGalleryModel[] photoGalleryModels;

    public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
        mContext = c;
        photoGalleryModels = models;
    }

    @Override
    public int getCount() { return photoGalleryModels.length; }

    @Override
    public Object getItem(int position) { return null; }

    @Override
    public long getItemId(int position) { return 0; }

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

        final ImageView imageView = new ImageView(mContext);    
        DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
            @Override
            public void MyHttpCallback_OnSuccess(Object data, String responseString)
            {
                if(data instanceof Bitmap) {
                    imageView.setImageBitmap((Bitmap)data);
                }
            }

            @Override
            public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
            {}
        });

        convertView = imageView;    
        return convertView;
    }
}

如果有人可以帮我解决这个问题并帮助我修复gridView以便能按预期滚动浏览所有已加载的图像,我将非常高兴。

1 个答案:

答案 0 :(得分:0)

好吧,我似乎忽略了自己解决了这个问题。在我跳过修复gridView之后,因为我不知道该怎么做,我实现了使用 LruCache (如Android开发人员training page中所示)缓存图像以节省一些内存。突然,gridView的滚动行为也得到了修复。

以下是我的更改:

PhotoGalleryImageAdapter(现在有缓存)

public class PhotoGalleryImageAdapter extends BaseAdapter {

    private Context mContext;
    private PhotoGalleryModel[] photoGalleryModels;
    private LruCache<String, Bitmap> mMemoryCache;

    public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
        mContext = c;
        photoGalleryModels = models;

        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
        protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    @Override
    public int getCount() { return photoGalleryModels.length; }

    @Override
    public Object getItem(int position) { return null; }

    @Override
    public long getItemId(int position) { return 0; }

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

        final ImageView imageView = new ImageView(mContext);
        final String imageKey = photoGalleryModels[position].thumb_image_url;
        final Bitmap bitmapImage = mMemoryCache.get(imageKey);

        if (bitmapImage != null) {
            imageView.setImageBitmap(bitmapImage);
        }
        else {

            DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
                @Override
                public void MyHttpCallback_OnSuccess(Object data, String responseString) {
                    if (data instanceof Bitmap) {
                        mMemoryCache.put(imageKey, (Bitmap)data);
                        imageView.setImageBitmap((Bitmap)data);
                    }
                }

                @Override
                public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
                {}
            });
        }

        convertView = imageView;
        return convertView;
    }

}

我很高兴gridView终于正常工作了,但是我不满意这样的事实,即如果没有缓存图像它对我不起作用。我应该在加载图像之前在imageAdapter的getView()方法中设置imageView的边界。我将尝试修复gridView而不使用缓存并更新我的答案,如果我找到了解决方案,以防有人必须面对同样的问题。在那之前,我很高兴我设法使它工作:)

UPDATE:

我终于使用和不使用缓存工作。这是我更新的PhotoGalleryImageAdapter

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

    final ImageView imageView;
       // set the imagge's bounds if it is not loaded yet
    if (convertView == null) {
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(imageSize, imageSize));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(0, 0, 0, 0);
    }
    else {
        imageView = (ImageView) convertView;
    }

    final String imageKey = photoGalleryModels[position].thumb_image_url;
    final Bitmap bitmapImage = mMemoryCache.get(imageKey);

    if (bitmapImage != null) {
        imageView.setImageBitmap(bitmapImage);
    }
    else {
        imageView.setImageBitmap(emptyBitmap);
        DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
            @Override
            public void MyHttpCallback_OnSuccess(Object data, String responseString) {
                    if (data instanceof Bitmap) {
                    mMemoryCache.put(imageKey, (Bitmap)data);
                    imageView.setImageBitmap((Bitmap)data);
                }
            }

            @Override
            public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
            {}
        });
    }
    convertView = imageView;
    return convertView;
}

正如所料,我需要在加载之前设置图像边界。

因为我将gridView的numColumns参数更改为'auto_fit',所以图像的宽度/高度(100dp + stretchMode columnWidth)计算如下:

int imagesPerRow = screenSize.x / (int)(100 * mContext.getResources().getDisplayMetrics().density);
imageSize = screenSize.x / imagesPerRow;

在加载imageView的bitmapImage之前,我创建一个空的位图图像并将其分配给imageView(找到代码here):

emptyBitmap = Bitmap.createBitmap(imageSize, imageSize, Bitmap.Config.ARGB_8888);

无论是否使用LruCache,gridView现在都可以正常工作。我不知道一个人自己的问题是否是常见的做法,但这样做我认为它可以帮助那些面临类似问题的人。