【问题标题】:ImageLoader out of memory in AndroidAndroid中的ImageLoader内存不足
【发布时间】:2015-08-04 06:26:56
【问题描述】:

我已经创建了一个应用程序,其中有 gridview,当我们选择任何缩略图时,我们会在 viewpager 中看到完整尺寸的图像。但是,当我多次单击缩略图并查看图像时,我在 android 中的内存不足。我进行了很多搜索,找到了一种使用 picasso 代替 imageloader 的解决方案,但我不能使用 picasso。我只用 imageloader 来做。谁能告诉我imageloader的确切配置和选项,这样我就不会内存不足????

请帮助我尝试了许多配置更改。

    public class ImagePagerAdapter extends PagerAdapter {
    LayoutInflater inflater;
    PhotoViewAttacher attacher;
    PhotoViewAttacher pic;
    private DisplayImageOptions options;
    List<Image> IMAGES_LIST = AppController.getInstance().getPrefManger()
            .getImages();

    public ImagePagerAdapter(Context context) {
        inflater = LayoutInflater.from(context);
        options = new DisplayImageOptions.Builder()
                .showImageForEmptyUri(R.drawable.ic_empty)
                .showImageOnFail(R.drawable.ic_error)
                .cacheOnDisc()
                .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
                .build();
    }

    @Override
    public Object instantiateItem(ViewGroup container, final int position) {
        final View imageLayout = inflater.inflate(
                R.layout.item_pager_image, container, false);
        assert imageLayout != null;
        pos = position;
        imageView = (TouchImageView) imageLayout.findViewById(R.id.image);
        imageView.setTag(position);


        imageView.setOnDoubleTapListener(new OnDoubleTapListener() {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                // TODO Auto-generated method stub
                try
                {
                timer.cancel();
                }
                catch(Exception ex){}
                if(IMAGES_LIST.get(position).getType().equalsIgnoreCase("image"))
                {
                mHandler.removeCallbacks(r);
                share.setVisibility(View.VISIBLE);
                play.setVisibility(View.VISIBLE);
                done.setVisibility(View.VISIBLE);
                if (!isCopyImage.equals("yes")) {
                    gimmy.setVisibility(View.VISIBLE);
                }
                comment.setVisibility(View.VISIBLE);
                count.setVisibility(View.VISIBLE);
                caption.setVisibility(View.VISIBLE);
                mHandler.postDelayed(r, 5 * 1000);
                }
                else{
                    mHandler.removeCallbacks(r);
                    done.setVisibility(View.VISIBLE);
                    mHandler.postDelayed(r, 5 * 1000);

                }
                return false;
            }

            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                // TODO Auto-generated method stub
                Log.i("hello", "");
                return false;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                // TODO Auto-generated method stub
                return false;
            }
        });

        try{
        final ProgressBar spinner = (ProgressBar) imageLayout
                .findViewById(R.id.loading);
        final ImageView videoplay = (ImageView) imageLayout
                .findViewById(R.id.play);
        if(IMAGES_LIST.get(position).getType().equalsIgnoreCase("image"))
        {
            videoplay.setVisibility(View.INVISIBLE);
            ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(container.getContext());
            config.memoryCache(new WeakMemoryCache());
            config.denyCacheImageMultipleSizesInMemory();
            config.discCache(new UnlimitedDiskCache(container.getContext().getCacheDir()));
            imageLoader=ImageLoader.getInstance();
            imageLoader.init(config.build());
            imageLoader.displayImage(
                AppConst.BASE_IMAGE_URL
                        + IMAGES_LIST.get(position).getFileName(),
                imageView, options, new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingStarted(String imageUri, View view) {
                        spinner.setVisibility(View.VISIBLE);
                        view.setVisibility(View.GONE);
                    }

                    @Override
                    public void onLoadingFailed(String imageUri, View view,
                            FailReason failReason) {
                        String message = null;
                        switch (failReason.getType()) {
                        case IO_ERROR:
                            message = "Input/Output error";
                            break;
                        case DECODING_ERROR:
                            message = "Image can't be decoded";
                            break;
                        case NETWORK_DENIED:
                            message = "Downloads are denied";
                            break;
                        case OUT_OF_MEMORY:
                            message = "Out Of Memory error";
                            break;
                        case UNKNOWN:
                            message = "Unknown error";
                            break;
                        }
                        spinner.setVisibility(View.GONE);
                    }

                    @Override
                    public void onLoadingComplete(String imageUri,
                            View view, Bitmap loadedImage) {
                        spinner.setVisibility(View.GONE);
                        view.setVisibility(View.VISIBLE);

                    }
                });

        container.addView(imageLayout, 0);

        }

【问题讨论】:

  • 这已经被问到(并回答了)severaltimes,请搜索一下,您会找到答案。
  • 我使用 imageloader 而不是位图从 url 加载图像,所以你给出的这两个链接不能被使用
  • 如果你想要一个答案,首先你应该展示你已经做了什么。包括一些代码。 StackOverflow 不是为别人写代码的人,而是在你尝试但找不到解决方案后寻求帮助。
  • 这是我的浏览器适配器。在这里,我正在从 url 加载图像,但是当在 pageradapter 中加载第十张图像时,我得到了 oom

标签: android universal-image-loader


【解决方案1】:

ImageLoader 不是直接你的问题;您遇到的主要问题是位图管理不善。

首先,您不应该为您需要的每个图像实例加载全新的位图对象。这会导致位图堆中的许多分配,并占用大量内存块。如Re-using bitmaps 中所述,您可以将新位图加载到可能不再使用的旧位图的内存空间中。您可以将此与LRUCache 结合使用,这样您就可以知道不再需要哪些图像,并且可以重复使用它们的内存。想想这个过程很像objectpools

其次,确保您使用的是正确的图像像素格式。正如Smaller Pixel Formats 中所述,使用 RGB_565 格式可以为每个像素节省大约 50% 的内存,非常适合从 JPG 文件加载的不透明图像。

第三,仔细检查您的内存分配,以确保您的位图对象被正确释放。如果您没有正确释放它们,您将创建一个占用内存的new memory leak,并且不会将其释放回应用程序。

解决所有这些问题对于具有高位图负载的应用程序至关重要,以避免内存不足问题。

【讨论】:

    【解决方案2】:

    需要考虑的重要一点是,图像通常使用每个像素 3 或 4 个字节进行解码。因此,一个 5Mpx 的图像将需要 20Mb,通常比操作系统在某些手机上允许您的应用程序所允许的还要多。您必须在加载图像时修改选项,以便在解码时按比例缩小。

    你读过this吗?有很多处理 Out Of Memory 错误的建议。

    如果您在使用 Universal Image Loader 的应用中经常遇到 OutOfMemoryError,那么:

    • 禁用内存中的缓存。如果 OOM 仍然发生,那么您的应用似乎存在内存泄漏。使用 MemoryAnalyzer 检测它。否则请尝试以下步骤(全部或多个):

    • 减少配置中的线程池大小 (.threadPoolSize(...))。建议使用 1 - 5。

    • 在显示选项中使用 .bitmapConfig(Bitmap.Config.RGB_565)。 RGB_565 中的位图消耗的内存是 ARGB_8888 中的 2 倍。

    • 使用 .imageScaleType(ImageScaleType.EXACTLY)

    • 在配置中使用 .diskCacheExtraOptions(480, 320, null)

    【讨论】:

    • 使用这些配置加载 25-26 张图片后内存不足
    • 如果你想同时加载 25 张全尺寸图像,我怀疑任何手机内存都足够了。大多数时候,一个就足以炸毁jvm。如果您想在画廊视图中显示它们,则必须在它们不在视野范围内时回收并重新加载图像。如果内存不够……那么内存不够,你将不得不同时加载更少的图像。
    • 我在加载完成时使用 imageloader.clearmemorycache() 但它仍在缓存 iamge
    【解决方案3】:

    我不相信它会解决您的问题,但是您应该在应用程序的 onCreate 方法中启动 ImageLoader(创建一个扩展 Application 的类并将信息放入清单中)。

    您还可以向我们展示您尝试加载的图片样本,使用 MemoryAnalyzer 查找占用这么多内存的内容,当然在这种情况下遵循推荐的选项(禁用缓存、imageScaleType... 如前所述)

    【讨论】:

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