在Android的Backstack碎片占用太多内存 [英] Android Fragments on Backstack taking up too much memory

查看:137
本文介绍了在Android的Backstack碎片占用太多内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

我有一个Android应用程序,允许用户浏览到用户的个人资料 ViewProfileFragment 。在 ViewProfileFragment 用户可以单击将带他到 StoryViewFragment 其中,不同用户的照片显示的图像上。它可以点击用户个人资料照片,将带他们到新用户的配置文件 ViewProfileFragment 的另一个实例。如果用户对用户的个人资料反复点击,点击会将其带入到库中,然后点击另一个配置文件中的片段在内存堆叠起来很快引起可怕的的OutOfMemoryError 的图像。以下是我所描述的示意图流量:

I have an Android application that allows a user to browse to a user's profile ViewProfileFragment. Inside ViewProfileFragment a user can click on an image that will take him to StoryViewFragment where various users' photos show up. It is possible to click on a user profile photo that will take them to another instance of ViewProfileFragment with the new user's profile. If a user repeatedly clicks on user's profiles, clicks an image that takes them to the gallery then clicks on another profile the Fragments stack up in memory quickly causing the dreaded OutOfMemoryError. Here is a diagram flow of what I am describing:

用户A点击Bob的个人资料。内部Bob的个人资料用户A点击ImageA带他到各种用户(包括Bob的)的照片画廊。用户A点击苏的个人资料,然后对她的形象之一 - 过程不断重复,等等,等等。

UserA clicks on Bob's profile. Inside Bob's profile UserA clicks on ImageA taking him to a gallery of photos of various users (including Bob's). UserA clicks on profile of Sue then on one of her images - process repeats, etc, etc.

UserA -> ViewProfileFragment
         StoryViewFragment -> ViewProfileFragment
                               StoryViewFragment -> ViewProfileFragment

所以你可以从一个典型的流量看到有很多的实例 ViewProfileFragment StoryViewFragment 在堆积如山在backstack。

So as you can see from a typical flow there are lots of instances of ViewProfileFragment and StoryViewFragment piling up in the backstack.

相关code

我在这些装载的片段与以下逻辑:

I am loading these in as fragments with the following logic:

//from MainActivity
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.activity_main_content_fragment, fragment, title);
ft.addToBackStack(title);

我已经试过

1)我特别使用 FragmentTransaction 替换,使的onPause 替换发生的方法将被触发。在的onPause 我想,如 ListView中清理出的数据适配器腾出尽可能多的资源,我可以(, 归零出来的变量,等),这样,当该片段不是活性片段和压入backstack会有更多的存储器释放。但我的努力,释放资源是只取得部分成功。据MAT我还有很多的内存是由 GalleryFragment ViewProfileFragment

1) I am specifically using FragmentTransaction replace so that the onPause method will be triggered when the replace takes place. Inside onPause I am trying to free up as many resources as I can (such as clearing out data in ListView adapters, "nulling" out variables, etc) so that when the fragment is not the active fragment and pushed onto the backstack there will be more memory freed up. But my efforts to free up resources is only a partial success. According to MAT I still have a lot of memory that is consumed by GalleryFragment and ViewProfileFragment.

2)我也删除了调用addToBackStack(),但很明显,提供了一个不好的用户体验,因为他们不能穿越回来(当用户点击后退按钮的应用程序只是关闭)。

2) I've also removed the call to addToBackStack() but obviously that offers a poor user experience because they can't traverse back (the app just closes when the user hits the back button).

3)我用MAT,找出所有我占用了大量的空间物体,我已经处理了那些以各种方式中的的onPause (和 onResume )的方法来释放资源,但他们还是在大小相当。

3) I have used MAT to find all of the objects that I take up a lot of space and I have dealt with those in various ways inside the onPause (and onResume) methods to free up resources but they are still considerable in size.

4)我也写了一个在两个片段的onPause ,设置了我所有的 ImageViews 为空循环使用以下逻辑:

4) I also wrote a for loop in both fragments' onPause that sets all of my ImageViews to null using the following logic:

 for (int i=shell.getHeaderViewCount(); i<shell.getCount(); i++) {

     View h = shell.getChildAt(i);
     ImageView v = (ImageView) h.findViewById(R.id.galleryImage);
       if (v != null) {
           v.setImageBitmap(null);
       }
  }

myListViewAdapter.clear()

问题

1)我俯瞰办法,让一个片段留在backstack也腾出了资源,以便.replace(片段)的周期也不吃了我所有的记忆?

1) Am I overlooking a way to allow a Fragment to remain on the backstack but also free up its resources so that the cycle of .replace(fragment) doesn't eat up all of my memory?

2)什么是最佳实践的时候,预计很多碎片可以加载到backstack?如何开发用正确此方案处理? (或者是逻辑在我的应用天生的缺陷,我只是做了?)

2) What are the "best practices" when it is expected that a lot of Fragments could be loaded onto the backstack? How does a developer correctly deal with this scenario? (Or is the logic in my application inherently flawed and I'm just doing it wrong?)

在集思广益解决这个任何帮助将大大AP preciated。

Any help in brainstorming a solution to this would be greatly appreciated.

推荐答案

原来,碎片共享相同的生命周期其父活动。按照片段文档

It turns out that fragments share the same lifecycle as their parent activity. According to the Fragment documentation:

一个片段必须始终嵌入的活动和片段的
  生命周期直接受主机活动的生命周期。对于
  例如,当活动被暂停,因此在所有的碎片,和
  当活动被破坏,所以都是碎片。然而,虽然
  活动正在运行(这是在恢复生命周期状态),可以
  独立操作每个片段。

A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently.

所以,你走上清理的onPause一些资源步骤()片段会不会触发除非父活动暂停。如果你正在由父活动加载最可能是你正在使用的交换某种机制哪一个是活动的多个片段。

So the step that you took to clean up some resources in onPause() of the fragment wouldn't trigger unless the parent activity pauses. If you have multiple fragments that are being loaded by a parent activity then most likely you are using some kind of mechanism for switching which one is active.

您可能能够通过不依赖于的onPause ,但通过覆盖<一个解决您的问题href=\"http://developer.android.com/reference/android/support/v4/app/Fragment.html#setUserVisibleHint(boolean)\"相对=nofollow> setUserVisibleHint 的片段。这给你一个好地方,决定在哪里做你的资源设置或清除资源起来的时候片段进来,拿出来看(例如,当你有一个从切换到碎裂一FragmentB PagerAdapter)。

You might be able to solve your issue by not relying on the onPause but by overriding setUserVisibleHint on the fragment. This gives you a good place to determine where to do your setup of resources or clean up of resources when the fragment comes in and out of view (for example when you have a PagerAdapter that switches from FragmentA to FragmentB).

public class MyFragment extends Fragment {
  @Override
  public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
      //you are visible to user now - so set whatever you need 
      initResources();
    }
    else { 
     //you are no longer visible to the user so cleanup whatever you need
     cleanupResources();
    }
  }
}

由于已经提到您是在backstack堆放物品了,所以它预计将有至少一个内存占用一点点,但是当片段拿出来看的,你可以最大限度地减少清理资源的足迹上述技术。

As was already mentioned you are stacking items up on a backstack so it's expected that there will be at least a little bit of a memory footprint but you can minimize the footprint by cleaning up resources when the fragment is out of view with the above technique.

另一个建议是在了解内存分析工具的输出( MAT 得到非常好的一般)和内存分析。 这里是一个很好的起点。这是很容易在Android的内存泄漏因此它在我看来是个必要熟悉的概念,以及如何内存可以从你走。这有可能是你的问题,是由于你没有释放资源时的片段超出视图的以及的某种类型的内存泄漏,所以如果你去使用的路线 setUserVisibleHint 来触发资源的清理和你仍然可以看到正在使用的内存的高容量,然后内存泄漏可能是罪魁祸首所以一定要排除他们两个。

The other suggestion is to get really good at understanding the output of the memory analyzer tool (MAT) and memory analysis in general. Here is a good starting point. It is really easy to leak memory in Android so it's a necessity in my opinion to get familiar with the concept and how memory can get away from you. It's possible that your issues are due to you not releasing resources when the fragment goes out of view as well as a memory leak of some kind so if you go the route of using setUserVisibleHint to trigger cleanup of your resources and you still see a high-volume of memory being used then a memory leak could be the culprit so make sure to rule them both out.

这篇关于在Android的Backstack碎片占用太多内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆