跟踪我的OOM错误(内存不足)

问题描述 投票:0回答:1

所以我对自己的问题有一些理论,但是我读到了一些相互矛盾的信息,这使我的处境有些困惑。

从顶级视图概述我的问题:

我有一个选项卡布局中带有3 Fragments的应用程序。其中第一个(在应用加载时显示)包含RecyclerView。每个ViewHolder包含一行TextView和3 ImageButtons,它们全部具有从存储在.jpg文件夹中的小(100-300kb)/drawable-nodpi图像加载的背景纹理。 “图像”按钮还具有一个附加的小(1kb).png,显示在这些纹理的顶部。

RecyclerView与主要活动中的ImageButton之间,图像总计约为6MB,应用程序在启动时最终将不得不加载这些图像。

分别地,该应用程序可以在最新的API或通常在较新的手机上正常运行。该应用程序倾向于在API 23和波纹管范围内参差不齐。某些API 23电话可以运行,但是由于种种原因而导致某些崩溃。我意识到每次崩溃都可能有很多不同的原因,因此对于这个问题,我着眼于著名的"Out of Memory"错误。我确实有一个物理API 23手机,我一直在尝试使用android studio进行配置,并且内存看起来像这样:

enter image description here

到目前为止,这支持这样的想法,至少在具有API 23的特定电话上,我遇到图形渲染问题,也许是图像加载问题?尽管我的堆转储和内存分析不起作用,所以我无法获得特定的运行任务。

关于图像渲染现在,这是我感到困惑的地方。在这种情况下,大多数在线信息都指向使用诸如Glide或Picasso或Facebook自己的Fresco之类的库。但是,我在其他相关的SO帖子中也看到了评论,对于像我这样从Drawables文件夹加载图像的人来说,不需要使用这些库。 (特别是当我的图像与图库应用程序中的图像相比很小时,每张图片的大小为MB。)

然而,网上的压倒性信息表明,可以通过图书馆解决此问题,所以我的问题是:可以吗?还是我的问题出在其他地方,也许在我的片段代码或我的适配器中,等等。

我将从图像开始:

/ src / main / res

  • drawable /

    • 。png(平均1kb,小于100x100像素),这些是前景可绘制对象
  • drawable-nodpi /

    • 。jpg纹理(平均100-300kb,1200x1500px和3000x2000px)也许是可以在内存上保存的位置?

现在我将代码发布在这里,但是似乎不是,因为我的问题确实出在我上面的图像上,更多的是在我的后续回答中。我还经历并使用Glide进行了一些更改,但是很快就成了将我当前的逻辑迁移到其他图像加载结构中的大探险。

android out-of-memory glide
1个回答
0
投票

我在解决方案中的第一个尝试是将图像逻辑切换到适配器中。请注意,这些ImageButtons最初是通过分配给xml布局中的background属性来加载的。这涉及到围绕那些按钮归因于我的一些模型逻辑,以及在片段和适配器之间来回传递信息。

这最终看起来像这样:

public class MyFragment extends Fragment {
...

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {

        // initialize your data here

        mAdapter = new FooListAdapter(mfooList, getContext()); //<-- Pass Fragment reference
        mfooList.setAdapter(mAdapter);
        mfooList.setLayoutManager(new LinearLayoutManager(getContext()));
    }
...
}

public class FooListAdapter extends RecyclerView.Adapter<BeatListAdapter.ViewHolder> {
    private final RequestManager requestManager;
    private Context context;

    FooListAdapter(List<Foo> fooList, Context context) {
        this.fooList = fooList;
        this.context = context
        this.requestManager = Glide.with(context);
    }

    @Override
    public void onBindViewHolder(@NonNull FooListAdapter.ViewHolder viewHolder, int position) {
        // Initialize your views

        requestManager.load(R.Drawable.class.getField("name_" + model.fooId).getInt(null))
            .into(new CustomTarget<Drawable> {
                // override methods here, and set the background
                view.setBackground(resource);
            });

        // listeners

        buttonListener = (View view) -> {
            // change model
            // load new image with Glide
            // update model in fragment
        }

        // Set button listeners
    }
}

尽管我的按钮和模型有很多事情要做,但是这对我的逻辑结构来说是一个很大的改变,我放弃了这个想法,因为它似乎并没有带来直接的结果。我最初在Fragment中拥有侦听器,因此他们可以直接访问数据模型。

具有上述逻辑结构的一个缺点实际上是保留对Fragment的引用,并不断地来回传递信息,这不是很有效,并且可能稍后会导致内存泄漏。

解决方案当我考虑设置时,做了一些毫无用处的跟踪和内存分析时,我意识到我一直忽略的一个大因素。

我的图像可能相对较小,但是如果图像大于1000像素,则300kb无关紧要。这意味着,当android渲染图像时,实际上要占用大量像素并将其转换为bitmap

[我将图像放在nodpi文件夹中以“简化” Android的图像选择这一事实使这个问题更加严重。 Android正在拍摄我的1000多个图像,并试图将其安装到不超过200像素大的按钮中……这需要大量的计算。

所以我想我会尝试将图像缩小到更适合其预期用途的尺寸,这让我感到惊讶。我的300kb图片大小减少到10kb !!!现在它们的大小更合适了,我启动了我的应用程序,没有发生任何崩溃!

现在是我的其他错误...

© www.soinside.com 2019 - 2024. All rights reserved.