草庐IT

android - Backstack上的Android fragment 占用过多内存

coder 2023-06-07 原文

问题:

我有一个Android应用程序,允许用户浏览到用户的个人资料ViewProfileFragment。在ViewProfileFragment内部,用户可以单击图像,将其带到StoryViewFragment,其中显示了各种用户的照片。可以单击用户个人资料照片,将其带到具有新用户个人资料的另一个ViewProfileFragment实例。如果用户反复单击用户的配置文件,请单击将其带到图库的图像,然后单击另一个配置文件,这些碎片会迅速堆积在内存中,从而导致可怕的OutOfMemoryError。这是我所描述的流程图:

UserA单击Bob的个人资料。在Bob的个人资料中,UserA单击ImageA,将他带到各种用户(包括Bob的用户)的照片画廊。 UserA单击Sue的个人资料,然后单击她的一张图像-处理重复等,依此类推。

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

因此,从典型流程中可以看到,backstack中堆积了许多ViewProfileFragmentStoryViewFragment实例。

相关代码

我使用以下逻辑将它们作为片段加载:
//from MainActivity
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.activity_main_content_fragment, fragment, title);
ft.addToBackStack(title);

我尝试过的内容

1)我专门使用FragmentTransaction replace,以便在onPause发生时触发replace方法。在onPause内部,我试图释放尽可能多的资源(例如,清除ListView适配器中的数据,“清空”变量等),以便当该片段不是 Activity 片段并被插入Backstack时,释放更多的内存。但是我为释放资源所做的努力只是部分成功。根据MAT,我仍然有很多内存被GalleryFragmentViewProfileFragment占用。

2)我也删除了对addToBackStack()的调用,但是显然,由于它们无法向后移动(用户单击后退按钮时,应用会关闭),因此提供了较差的用户体验。

3)我已经使用MAT查找占用了很多空间的所有对象,并且在onPause(和onResume)方法内部以各种方式处理了这些对象以释放资源,但是它们的大小仍然很大。

4)我还在两个片段的onPause中编写了一个for循环,使用以下逻辑将我的所有ImageViews设置为null:
 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)我是否在忽略一种方法,该方法允许Fragment保留在后台但又释放其资源,以使.replace(fragment)循环不会耗尽我的所有内存?

2)预计可以将很多Fragment加载到Backstack上时,“最佳实践”是什么?开发人员如何正确处理这种情况? (或者我的应用程序中的逻辑固有存在缺陷,而我做错了吗?)

我们将不胜感激,为解决此问题提供了思路。

最佳答案

事实证明,片段与其父 Activity 共享相同的生命周期。根据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.



因此,除非父 Activity 暂停,否则您不会执行清理片段的onPause()中的某些资源的步骤。如果您有一个父 Activity 正在加载多个片段,那么很可能您正在使用某种机制来切换哪个是 Activity 的。

通过不依赖onPause而是在片段上覆盖setUserVisibleHint,也许可以解决您的问题。这为您提供了一个很好的位置,可以确定在片段进入和离开 View 时(例如,当您具有从FragmentA切换到FragmentB的PagerAdapter时)在何处进行资源设置或清理资源。
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();
    }
  }
}

如前所述,您正在将项目堆叠在一个后堆栈上,因此可以预期至少会有一点内存占用空间,但是当使用上述技术看不到该片段时,可以通过清理资源来最小化占用内存的空间。

另一个建议是真正真正地理解内存分析器工具(MAT)的输出以及一般的内存分析。 Here is a good starting point。在Android中泄漏内存确实很容易,因此我认为有必要熟悉该概念以及内存如何脱离您的需求。您的问题很可能是由于当片段不可见时您没有释放资源以及某种类型的内存泄漏,因此,如果走使用setUserVisibleHint触发资源清理的路线,您仍然会看到高如果使用了大量的内存,则可能是造成内存泄漏的罪魁祸首,因此请确保将它们都排除在外。

关于android - Backstack上的Android fragment 占用过多内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28483600/

有关android - Backstack上的Android fragment 占用过多内存的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  3. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  4. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  5. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  6. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  7. ruby-on-rails - Ruby - 如何从 ruby​​ 上的 .pfx 文件中提取公钥、rsa 私钥和 CA key - 2

    我有一个.pfx格式的证书,我需要使用ruby​​提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o

  8. 键删除后 ruby​​ 哈希内存泄漏 - 2

    你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

  9. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

  10. ruby-on-rails - rails 上的 ruby : radio buttons for collection select - 2

    我有一个集合选择:此方法的单选按钮是什么?谢谢 最佳答案 Rails3中没有这样的助手。在Rails4中,它是collection_radio_buttons. 关于ruby-on-rails-rails上的ruby:radiobuttonsforcollectionselect,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/18525986/

随机推荐