将图像从SD卡加载到gridview抛出内存异常?

时间:2016-05-10 12:08:08

标签: android image gridview bitmap

从2天开始我很挣扎,请有人帮我解决这个问题。

我想将外部存储器中所有图像的列表加载到gridview中。

我能够使用这种方法从系统中获取图像列表。

  public static ArrayList<String> getFilePaths(Activity context)
    {


        Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {MediaStore.Images.ImageColumns.DATA};
        Cursor c = null;
        SortedSet<String> dirList = new TreeSet<String>();
        ArrayList<String> resultIAV = new ArrayList<String>();

        String[] directories = null;
        if (u != null)
        {
            c = context.managedQuery(u, projection, null, null, null);
        }

        if ((c != null) && (c.moveToFirst()))
        {
            do
            {
                String tempDir = c.getString(0);
                tempDir = tempDir.substring(0, tempDir.lastIndexOf("/"));
                try{
                    dirList.add(tempDir);
                }
                catch(Exception e)
                {

                }
            }
            while (c.moveToNext());
            directories = new String[dirList.size()];
            dirList.toArray(directories);

        }

        for(int i=0;i<dirList.size();i++)
        {
            File imageDir = new File(directories[i]);
            File[] imageList = imageDir.listFiles();
            if(imageList == null)
                continue;
            for (File imagePath : imageList) {
                try {

                    if(imagePath.isDirectory())
                    {
                        imageList = imagePath.listFiles();

                    }
                    if ( imagePath.getName().contains(".jpg")|| imagePath.getName().contains(".JPG")
                            || imagePath.getName().contains(".jpeg")|| imagePath.getName().contains(".JPEG")
                            || imagePath.getName().contains(".png") || imagePath.getName().contains(".PNG")
                            || imagePath.getName().contains(".gif") || imagePath.getName().contains(".GIF")
                            || imagePath.getName().contains(".bmp") || imagePath.getName().contains(".BMP")
                            )
                    {



                        String path= imagePath.getAbsolutePath();
                        resultIAV.add(path);

                    }
                }
                //  }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        return resultIAV;


    }

现在最棘手的部分来了,我知道我无法加载实际图像,因为它占用了大量内存并最终得到bitmap Outofmemory exception因此我有图像加载器与执行器执行单独的图像加载这里异步的线程和加载图像是图像加载器。

public class AbstractImageLoader {
    private static ExecutorService executorService;
    private static AbstractImageLoader loader;
    public static int maxWidth;
    Handler handler;;
    private Map<ImageView,String> imageViews;

    static {
        AbstractImageLoader.executorService = Executors.newFixedThreadPool(5);
    }

    public AbstractImageLoader(final Context context) {
        this.imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
        this.handler = new Handler();
        AbstractImageLoader.maxWidth = context.getResources().getDisplayMetrics().widthPixels / 3;
    }

    public static AbstractImageLoader getInstance(final Context context) {
        if (AbstractImageLoader.loader == null) {
            AbstractImageLoader.loader = new AbstractImageLoader(context);
        }
        return AbstractImageLoader.loader;
    }

    private void queuePhoto(final String s, final ImageView imageView, final int n) {
        AbstractImageLoader.executorService.submit(new PhotosLoader(new PhotoToLoad(s, imageView, n)));
    }

    public void DisplayImage(final String s, final ImageView imageView) {
        this.DisplayImage(s, imageView, -1);
    }

    public void DisplayImage(final String s, final ImageView imageView, final int imageResource) {
        this.imageViews.put(imageView, s);
        final Bitmap value = MemCache.get(s);
        if (value != null) {
            imageView.setImageBitmap(value);
            return;
        }
        this.queuePhoto(s, imageView, imageResource);
        if (imageResource > -1) {
            imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
            imageView.setImageResource(imageResource);
            return;
        }
        imageView.setImageDrawable((Drawable)null);
    }

    public void DisplayImage(final String s, final ImageView imageView, final Drawable imageDrawable) {
        this.imageViews.put(imageView, s);
        final Bitmap value = MemCache.get(s);
        if (value != null) {
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setImageBitmap(value);
        }
        else {
            this.queuePhoto(s, imageView, -1);
            if (imageDrawable != null) {
                imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
                imageView.setImageDrawable(imageDrawable);
            }
        }
    }

    public void clearCache() {
        MemCache.clear();
    }

    public void delete(final String s) {
        MemCache.remove(s);
    }

    protected Bitmap getBitmap(final String ex) {
        final Bitmap bitmap = null;


        final File file = new File((String)ex);
        if (!file.exists()) {
            final String[] list = file.getParentFile().list(new FileUtils$Filters$6());
            Object o = bitmap;
            if (list != null) {
                if (list.length != 0) {
                    o = new File(file.getParent(), list[0]);
                    final String absolutePath = ((File)o).getAbsolutePath();
                    o = ThumbUtils.getThumbnail(absolutePath, AlbumViewLoader.maxWidth);
                    return ThumbUtils.getThumbnail((String)ex, AlbumViewLoader.maxWidth);
                }
                o = bitmap;
            }
            return (Bitmap)o;
        }
        return ThumbUtils.getThumbnail((String)ex, AlbumViewLoader.maxWidth);
    }

    boolean imageViewReused(final PhotoToLoad photoToLoad) {
        final String s = imageViews.get(photoToLoad.imageView);
        return s == null || !s.equals(photoToLoad.url);
    }

    class BitmapDisplayer implements Runnable
    {
        Bitmap bitmap;
        PhotoToLoad photoToLoad;

        public BitmapDisplayer(final Bitmap bitmap, final PhotoToLoad photoToLoad) {
            this.bitmap = bitmap;
            this.photoToLoad = photoToLoad;
        }

        @Override
        public void run() {
            if (!AbstractImageLoader.this.imageViewReused(this.photoToLoad)) {
                if (this.bitmap != null) {
                    this.photoToLoad.imageView.setImageBitmap(this.bitmap);
                    this.photoToLoad.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    return;
                }
                if (this.photoToLoad.placeholder_stub > -1) {
                    this.photoToLoad.imageView.setImageResource(this.photoToLoad.placeholder_stub);
                    this.photoToLoad.imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
                }
            }
        }
    }

    private class PhotoToLoad
    {
        public ImageView imageView;
        public int placeholder_stub;
        public String url;

        public PhotoToLoad(final String url, final ImageView imageView, final int placeholder_stub) {
            this.url = url;
            this.imageView = imageView;
            this.placeholder_stub = placeholder_stub;
        }
    }

    class PhotosLoader implements Runnable
    {
        PhotoToLoad photoToLoad;

        PhotosLoader(final PhotoToLoad photoToLoad) {
            this.photoToLoad = photoToLoad;
        }

        @Override
        public void run() {
            try {
             /*   if (!imageViewReused(this.photoToLoad)) {
                    return;
                }*/
                final Bitmap bitmap = AbstractImageLoader.this.getBitmap(this.photoToLoad.url);
                if (bitmap != null) {
                    MemCache.put(this.photoToLoad.url, bitmap);
                }

                    AbstractImageLoader.this.handler.post((Runnable)new BitmapDisplayer(bitmap, this.photoToLoad));

            }
            catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }
}

这是我创建位图的实用程序类:

  public static Bitmap getThumbnail(final String s, int n) {
        final BitmapFactory.Options bitmapFactory$Options = new BitmapFactory.Options();
        bitmapFactory$Options.inSampleSize = 1;
        bitmapFactory$Options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(s, bitmapFactory$Options);
        if (bitmapFactory$Options.mCancel || bitmapFactory$Options.outWidth == -1 || bitmapFactory$Options.outHeight == -1) {
            return null;
        }
        final int outHeight = bitmapFactory$Options.outHeight;
        final int outWidth = bitmapFactory$Options.outWidth;
        final float max = Math.max(n / outWidth, n / outHeight);
        n = (int)(outWidth * max);
        final int n2 = (int)(outHeight * max);
        bitmapFactory$Options.inSampleSize = calculateInSampleSize(bitmapFactory$Options, n, n);
        bitmapFactory$Options.inJustDecodeBounds = false;
        bitmapFactory$Options.inDither = true;
        bitmapFactory$Options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bmp = BitmapFactory.decodeFile(s, bitmapFactory$Options);
        return ThumbnailUtils.extractThumbnail(bmp, n, n, 2);
    }

所以这是我的问题:

1.在我的缩略图实用程序方法中,这个计算:

 final float max = Math.max(n / outWidth, n / outHeight);
            n = (int)(outWidth * max);
            final int n2 = (int)(outHeight * max);

n总是返回0.因此缩略图没有加载,所以暂时我将其硬编码为212并开始加载缩略图

但是在加载了一定数量的图像后,我仍然会得到out of memory exception

这是logcat:

 java.lang.OutOfMemoryError: Failed to allocate a 347790 byte allocation with 294944 free bytes and 288KB until OOM
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:639)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:615)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at com.geekmk.audiofx.test.ThumbUtils.getThumbnail(ThumbUtils.java:66)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at com.geekmk.audiofx.test.AbstractImageLoader.getBitmap(AbstractImageLoader.java:110)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at com.geekmk.audiofx.test.AbstractImageLoader$PhotosLoader.run(AbstractImageLoader.java:171)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-10 09:57:19.448 22498-22683/com.geekmk.audiofx W/System.err:     at java.lang.Thread.run(Thread.java:818)

请帮帮我 提前谢谢。

2 个答案:

答案 0 :(得分:0)

  

n总是返回0.因此缩略图没有被加载,所以   暂时我把它硬编码到212并开始加载缩略图

这是因为你正在混合int和float。尝试更改此代码以使用浮动。

public static Bitmap getThumbnail(final String s, float n) {

final float outHeight = bitmapFactory$Options.outHeight;
final float outWidth = bitmapFactory$Options.outWidth;

不确定为什么你在那里使用决赛,我认为没必要。

使用像Picasso这样的东西可以节省大量的代码和时间。

您可以从Fragment或ViewHolder

执行此类操作
Picasso.with(context).load(R.drawable.landing_screen).into(imageView1);
Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2);
Picasso.with(context).load(new File(...)).into(imageView3);

答案 1 :(得分:0)

我使用以下方法获取缩小的位图,以便不抛出OOM异常:

private static Bitmap getBitmapFromUri(@NonNull Context context, @NonNull Uri uri) throws IOException {

        ParcelFileDescriptor parcelFileDescriptor =
                context.getContentResolver().openFileDescriptor(uri, "r");
        assert parcelFileDescriptor != null;
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        parcelFileDescriptor.close();

        TinyDB tinyDB = new TinyDB(context);
        int maxSize = Math.min(tinyDB.getInt(AppConstants.DEVICE_WIDTH, 720), tinyDB.getInt(AppConstants.DEVICE_HEIGHT, 1080));
        int outWidth;
        int outHeight;
        int inWidth = image.getWidth();
        int inHeight = image.getHeight();
        if(inWidth > inHeight){
            outWidth = maxSize;
            outHeight = (inHeight * maxSize) / inWidth;
        } else {
            outHeight = maxSize;
            outWidth = (inWidth * maxSize) / inHeight;
        }

        return Bitmap.createScaledBitmap(image, outWidth, outHeight, false);
    }

在代码中,TinyDBSharedPreferences的包装,我会在应用启动后立即以像素为单位存储屏幕大小。