android - 如何实现图片库(本 map 片)

标签 android android-viewpager out-of-memory gallery android-gallery

目前我正在制作一个应用程序来显示来自 SD 卡的图像。基本上你制作一个相册并向其中添加图片,无论是来自 MediaStore 选择器的相机。

我尝试实现 2 种方法:

  1. 带有自定义 BaseAdapter 以返回 View 的标准图库应用
  2. 带有自定义 PagerAdapter 的 viewpager

我不想显示 GridView ,所以它应该立即全屏显示。之后我想禁用左右滑动,只听点击。

Atm 这两种方法都适用于纵向模式。当我切换到横向时,一些图像就会掉落

03-20 12:20:56.515: W/OpenGLRenderer(17398): Bitmap too large to be uploaded into a texture

后跟内存不足错误。如果满满的 OOM 和画廊问题导致堆栈溢出,您应该回收 View 以使其正常工作,因为 convertView 在 BaseAdapter 的 getView 中始终为 null。

所以我为 View 使用了一个回收器,我将它限制为 2 个 View ,纵向模式适用于方法 1(使用画廊)。景观仍然给我同样的问题。

对于方法 2(viewflipper),它通过

处理 View
@Override
public void destroyItem(ViewGroup container, int position, Object object) {

Wich 从来没有被称为 btw... 但是纵向模式在这里有效。景观仍然崩溃。

我获取位图的方法:

public static Bitmap getBitmap(Context ctx, int imageId, ImageView target) {

    String file = getPath(ctx, imageId);

    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(file, bmOptions);
    WindowManager mgr = (WindowManager)         ctx.getSystemService(Context.WINDOW_SERVICE);

    int scaleFactor = 1;

    if (mgr != null) {
        // Get the dimensions of the View
        int targetW = mgr.getDefaultDisplay().getWidth();
        int targetH = mgr.getDefaultDisplay().getHeight();
        Log.d(TAG, "Image width + height=" + targetW + "," + targetH);


        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;
        // Determine how much to scale down the image
        scaleFactor = Math.min(photoW / targetW, photoH / targetH);

    } else {
        Log.d(TAG, "Target is null");
    }

    // Get the dimensions of the bitmap
    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;
    logHeap(ImageHelper.class);

    Bitmap bm = BitmapFactory.decodeFile(file, bmOptions);

    if (target != null) {
        target.setImageBitmap(bm);
    }
    return bm;
}

工作正常,我知道我使用窗口管理器来获取屏幕尺寸,但那是因为我的 ImageView 在我膨胀它时仍然是 size(0,0)。之后我调用

imgView.setLayoutParams(new Gallery.LayoutParams(
            Gallery.LayoutParams.FILL_PARENT,
            Gallery.LayoutParams.FILL_PARENT));
    imgView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

似乎没有任何效果......

请注意,我不使用可绘制对象或 APK 中包含的任何其他资源。 这个画廊应该能够从 SD 卡或相机中加载任何质量的图片。显然,画廊应该能够处理与目录中一样多的图像。

有人可以帮我解决以下问题吗?

  1. 有没有办法让默认图库立即全屏显示并屏蔽 GridView ?这样我只需要一个适配器来提供图像而不是制作我自己的 View 。 (也许这可以解决 OOM 崩溃问题)
  2. 我的Bitmap解码功能可以吗?我是否需要内置一些技巧来捕捉景观变化?
  3. 制作我需要的那种画廊的最佳方法是什么,是使用 viewpager 还是画廊?
  4. 有没有人有一些不会崩溃的全屏画廊示例代码?

最佳答案

这是我过去遇到过几次的问题。 Google 实际上发布了一篇关于此的文章。

问题出在你用来解码图像的 inSampleSize 中。由于不同的设备具有不同的屏幕和内存大小(VM 堆大小可能从 12 到 64 或更多 Mb),您无法在所有设备中以相同的方式解码图像。例如,具有 12Mb 堆内存的 320x240 设备中的图像应该使用给定的 inSampleSize,而 1280x720 64Mb 堆内存设备应该使用另一个 inSampleSize(更大的)。

我攻击的文章展示了一种针对给定高度和宽度渲染图像的有效方法。特别注意最后一个代码段,他们“预打开”文件并计算 inSampleSize 以便稍后“完全解码”。

我还想添加此建议。

  1. 以异步方式使用“getBitmap”函数,调用一个新线程或一个 asyncTask(这样做是因为使用 SD 需要时间,这会导致您的应用程序挂起,变慢并产生错误在中低端设备上的印象。

  2. 尝试始终使用相同的位图对象。避免创建多个“Bitmap bitmap = new Bitmap()”。您必须意识到加载的位图存储在 ram 中,一旦分配给 View ,垃圾收集器就“更难”获取它们。

  3. 当您使用完位图后,将其设为空。为此,假设您有 12Mb 的最大堆 RAM。您的应用现在使用 8Mb。垃圾收集器启动,无法再获取任何未使用的 RAM。在将数据分配给 ImageView 之后,您 10 个快速位图永远不会使它们为空,并且您会以某种方式保留它们的引用。考虑到每个位图占用 500Kb 的 Ram,您的应用程序将崩溃。使用后始终使位图为空。

  4. 最后使用 google platform-tools 中提供的 DDMS(您可以通过 eclipse 访问它来调试和查看您的内存使用情况,您还可以强制垃圾收集以查看您的应用程序的行为)。

关于android - 如何实现图片库(本 map 片),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9786638/

相关文章:

java - 不同 Activity 中的 AdMob 广告单元 ID 不同?提高匹配率?

android - 从数据库加载数据时 RecyclerView 闪烁

android - appengine 连接的 android 项目在到达时死机

android - 缩放图标以适应 Imageview Android

android - 异步任务崩溃 ViewPager RecyclerView (Android)

android - java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java :91)? 处的 java.lang.OutOfMemoryError

android - WebView 内存不足异常

android - 处理 PagerTitleStrip click in compatibiliy Fragment-based ViewPager

android - FragmentPagerAdapter 不适用于 fragment 的娱乐

java - 如何将所有数据分块插入数据库