【问题标题】:android: showing 156 images using gridview inside viewpagerandroid:在viewpager中使用gridview显示156张图片
【发布时间】:2014-04-13 11:49:31
【问题描述】:

我想使用 18 页的 Viewpager 显示 156 个缩略图,每个页面有 9 个缩略图。我已经实现如下:

Index_gridview 类:

public void init() 
{  
    PageCount = (int) Math.ceil(mThumbIds.length / PAGE_SIZE);  
    mLists = new ArrayList<GridView>();  

    for (int i = 0; i < PageCount; i++) 
    {  
        GridView gv = new GridView(this);  
        gv.setAdapter(new MyGridViewAdapter(this, mStrs, mThumbIds, i, icon_dimension));  
        gv.setGravity(Gravity.CENTER);  
        gv.setClickable(true);  
        gv.setFocusable(true);  
        gv.setNumColumns(NUMOFCOLUMN);  
        gv.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
        gv.setHorizontalSpacing(gridview_horizontal_padding);
        gv.setVerticalSpacing(gridview_vertical_padding);
        mLists.add(gv);  
    }         
    page_number.setText("1/"+PageCount);
}  

GridViewAdapter 类:

public class MyGridViewAdapter extends BaseAdapter 
{   
    private Animation zoom     = null;
    // view
    int icon_width, icon_height;
    Typeface tf;
    private Context mContext;  
    private List<String> mLists;  
    public static final int PAGE_SIZE = 9; // showing how many items in 1 page  

    public MyGridViewAdapter(Context pContext, String[] pStrs, Integer[] image_ref, int page, int width) 
    {  
        this.mContext = pContext;  
        mLists = new ArrayList<String>();  
        int i = page * PAGE_SIZE;  
        int end = i + PAGE_SIZE;  
        while ((i < image_ref.length) && (i < end)) 
        {  
            mLists.add(pStrs[i]); 
            i++;  
        }  

        icon_width = width;
        icon_height = icon_width;

        tf = Typeface.createFromAsset(mContext.getAssets(),"fonts/HomegirlKiddo.ttf");   
    }  

    @Override  
    public int getCount() 
    {           
        return mLists.size();  
    }  
    @Override  
    public Object getItem(int position) 
    {           
        return mLists.get(position);  
    }  
    @Override  
    public long getItemId(int position) 
    {     
        return position;  
    }  

    @Override  
    public View getView(int position, View convertView, ViewGroup parent) 
    {
        ViewHolder holder;
        if (convertView == null)
        {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.menugrid, parent, false);
            holder = new ViewHolder();

            holder.img = (ImageView) convertView.findViewById(R.id.imageicon);
            convertView.setTag(holder);
        } 
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }


        final int myNum = Integer.parseInt(mLists.get(position)) -1;
        ImageView imageView = holder.img;

        try
        {
            imageView.setImageBitmap(decodeSampledBitmapFromResource(mContext.getResources(), mThumbIds[myNum], icon_width, icon_width));   
        }
        catch (OutOfMemoryError e)
        {
            ((Index_Gridview)mContext).custom_toast("System Out-of-Error! Restarting...");
            ((Index_Gridview)mContext).restart_app();  
        }


        imageView.setOnClickListener(new OnImageClickListener(myNum));       
        return convertView;
    }

private Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) 
{
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

private int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight) 
{
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) 
    {   
        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }   
    return inSampleSize;
} 

class ViewHolder 
{
    ImageView img;
}

// References to our images in res > drawable
public Integer[] mThumbIds =  new Integer[] 
    {
        R.drawable.t_aaa, 
        R.drawable.t_bbb, 
                    ....listing of 156 image references here
    }

问题:

我已经尝试通过“decodeSampledBitmapFromResource”导入缩略图。每个原始缩略图大约 75KB。

它很容易陷入OOM。如何增强代码以减轻 OOM 错误?

谢谢!!

【问题讨论】:

  • 你在你的imageView.setImageBitmap(decodeSampledBitmapFromResource(mContext.getResources(), mThumbIds[myNum], icon_width, icon_width)); 中通过了Image Height 哪里?
  • 感谢您的回复...由于缩略图是方形的,我只是简单地使用 icon_width, icon_width 代替
  • 现在请发布您的decodeSampledBitmapFromResource(.....) 方法。
  • 补充了,谢谢~~确实是标准解码方法
  • t_aaa,t_bbb,t_ccc,etc.......resolution的每张图片的尺寸是多少?

标签: android gridview android-viewpager out-of-memory


【解决方案1】:

您可以尝试使用 RAM 和磁盘缓存来重用您的位图。

这里是 android support v4 中 LRUCache 的链接:

http://developer.android.com/reference/android/support/v4/util/LruCache.html

这是 Jake Wharton 的 DiskLRUCache 项目的链接

https://github.com/JakeWharton/DiskLruCache

【讨论】:

    【解决方案2】:

    您必须自己进行一些内存管理 - 毫无疑问。您可以回收屏幕外页面并在必要时重新加载它们。 LRUCache 很不错,但是它会占用你所有的内存来存储图片。

    您的画廊并不大,您可以考虑将其保存在原生内存中。 hdpi 800x480 屏幕需要 30MB,高清屏幕需要 150MB。使用 JNI 和 C 调用,您可以向 android 询问安装在硬件中的整个内存(512 - 1GB)。这样的内存不是 Java 堆的一部分,因此您不必担心应用程序中的其他内容内存不足。

    当然这不是完美的解决方案,因为占用的内存超出系统所能提供的容量会导致分配失败。你必须照顾它。

    链接:http://code.google.com/p/native-buffer/

    NativeBuffer 是一种缓存,它使用 C 分配的内存来存储图像数据。这比重新加载图像或将它们缓存到 sdcard 上要快得多。

    【讨论】:

      【解决方案3】:

      https://code.google.com/p/android-query/wiki/AsyncAPI?tm=6 用在一个例子中,我知道https://play.google.com/store/apps/details?id=com.app.ive 它可以处理任意数量的图像......

      我认为重新发明轮子不好,希望它能帮助你实现你想要的。

      谢谢

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-15
        • 1970-01-01
        相关资源
        最近更新 更多