方向改变后,Fragment 对 mActivity 的引用变为 null。碎片状态维护无效

2024-02-05

我的应用程序由几个片段组成。到目前为止,我已经将它们的引用存储在自定义应用程序对象中,但我开始认为我做错了什么。

当我意识到我的片段对 mActivity 的所有引用在方向更改后都变为空时,我的问题就开始了。因此,当我在方向更改后调用 getActivity() 时,会引发 NullPointerException。 我已经检查过在调用 getActivity() 之前调用了片段的 onAttach() ,但它仍然返回 null。

以下是我的 MainActivity 的精简版本,它是我的应用程序中唯一的活动。

public class MainActivity extends BaseActivity implements OnItemClickListener,
        OnBackStackChangedListener, OnSlidingMenuActionListener {

    private ListView mSlidingMenuListView;
    private SlidingMenu mSlidingMenu;

    private boolean mMenuFragmentVisible;
    private boolean mContentFragmentVisible;
    private boolean mQuickAccessFragmentVisible;

    private FragmentManager mManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /*
         * Boolean variables indicating which of the 3 fragment slots are visible at a given time
         */
        mMenuFragmentVisible = findViewById(R.id.menuFragment) != null;
        mContentFragmentVisible = findViewById(R.id.contentFragment) != null;
        mQuickAccessFragmentVisible = findViewById(R.id.quickAccessFragment) != null;

        if(!savedInstanceState != null) {
            if(!mMenuFragmentVisible && mContentFragmentVisible) {
                setupSlidingMenu(true);
            } else if(mMenuFragmentVisible && mContentFragmentVisible) {
                setupSlidingMenu(false);
            }

            return;
        }

        mManager = getSupportFragmentManager();
        mManager.addOnBackStackChangedListener(this);

        final FragmentTransaction ft = mManager.beginTransaction();
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

        if (!mMenuFragmentVisible && mContentFragmentVisible) {
            /*
             * Only the content fragment is visible, will enable sliding menu
             */
            setupSlidingMenu(true);
            onToggle();

            ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG);

        } else if (mMenuFragmentVisible && mContentFragmentVisible) {
            setupSlidingMenu(false);
            /*
             * Both menu and content fragments are visible
             */
            ft.replace(R.id.menuFragment, getCustomApplication().getMenuFragment(), MenuFragment.TAG);
            ft.replace(R.id.contentFragment, getCustomApplication().getSportsFragment(), SportsFragment.TAG);
        }

        if (mQuickAccessFragmentVisible) {
            /*
             * The quick access fragment is visible
             */
            ft.replace(R.id.quickAccessFragment, getCustomApplication().getQuickAccessFragment());
        }

        ft.commit();
    }

    private void setupSlidingMenu(boolean enable) {
        /*
         * if enable is true, enable sliding menu, if false
         * disable it
         */
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        // launch the fragment that was clicked from the menu
    }

    @Override
    public void onBackPressed() {
        // Will let the user press the back button when
        // the sliding menu is open to display the content.
        if (mSlidingMenu != null && mSlidingMenu.isMenuShowing()) {
            onShowContent();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public void onBackStackChanged() {
        /*
         * Change selected position when the back stack changes
         */
        if(mSlidingMenuListView != null) {
            mSlidingMenuListView.setItemChecked(getCustomApplication().getSelectedPosition(), true);    
        }
    }

    @Override
    public void onToggle() {
        if (mSlidingMenu != null) {
            mSlidingMenu.toggle();
        }
    }

    @Override
    public void onShowContent() {
        if (mSlidingMenu != null) {
            mSlidingMenu.showContent();
        }
    }
}

以下是 CustomApplication 的精简版本。我对这一实现的想法是保证在我的应用程序的整个生命周期中每个片段只有一个实例。

public class CustomApplication extends Application {

    private Fragment mSsportsFragment;
    private Fragment mCarsFragment;
    private Fragment mMusicFragment;
    private Fragment mMoviesFragment;

    public Fragment getSportsFragment() {
        if(mSsportsFragment == null) {
            mSsportsFragment = new SportsFragment();
        }

        return mSsportsFragment;
    }

    public Fragment getCarsFragment() {
        if(mCarsFragment == null) {
            mCarsFragment = new CarsFragment();
        }

        return mCarsFragment;
    }

    public Fragment getMusicFragment() {
        if(mMusicFragment == null) {
            mMusicFragment = new MusicFragment();
        }

        return mMusicFragment;
    }

    public Fragment getMoviesFragment() {
        if(mMoviesFragment == null) {
            mMoviesFragment = new MoviesFragment();
        }

        return mMoviesFragment;
    }
}

我对如何最好地实现多个片段以及如何维护它们的状态的技巧非常感兴趣。供您参考,到目前为止,我的应用程序由 15 个以上的片段组成。 我做了一些研究,似乎 FragmentManager.findFragmentByTag() 是一个不错的选择,但我还没有能够成功实现它。

我的实现似乎运行良好,除了 mActivity 引用在方向更改后变为空这一事实之外,这让我相信我也可能存在一些内存泄漏问题。

如果您需要查看更多代码,请告诉我。我故意避免包含片段代码,因为我坚信问题与我的活动和应用程序实现有关,但我可能是错的。

谢谢你的时间。


我对这一实现的想法是保证在我的应用程序的整个生命周期中每个片段只有一个实例

这可能是您遇到困难的部分原因(如果不是全部的话)。

在配置更改时,Android 将重新创建您的片段通过使用公共零参数构造函数来创建一个新实例。因此,您的全局范围片段将不会“保证每个片段仅一个实例”。

请删除此自定义Application班级。请允许片段自然地重新创建,或者如果它们需要在单个活动的生命周期内存在,请使用setRetainInstance(true)。不要尝试跨活动重用片段。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

方向改变后,Fragment 对 mActivity 的引用变为 null。碎片状态维护无效 的相关文章

  • 使用 JSONArray 还是普通数组来存储/读取数据更有效?

    我正在使用一个连接到PHP MySQL返回所有内容的服务器JSON格式 例如 用户列表作为JSONArray of JSONObject 每个对象都包含单个用户的信息 姓名 位置 电话号码等 处理这种格式的信息时 将所有内容保留在其中会更有
  • 如何在应用程序关闭时在 Android 通知中显示操作按钮?

    我有一个安卓应用程序 对于通知 我们必须显示一些操作按钮 当应用程序打开时 我们可以自由地构建通知并显示操作按钮 但是当应用程序关闭时 通知会在 Android 的通知托盘中收到 应用程序开发人员无法控制构建用户界面和操作按钮 我们现在如何
  • 使用 Fragment 在工具栏中实现 SearchView

    当前情况 我的应用程序主页由导航抽屉组成 因此我将视图作为片段加载 我的工具栏中也有搜索图标 我在中实现了它menu xml 下一步我实施了SearchView通过以下问题的答案来获取搜索图标在工具栏中实现搜索 https stackove
  • 如何通过我的活动在 Android 中设置铃声?

    我正在尝试找到一种方法来通过 Android 活动中的代码设置新的默认铃声 我已经将铃声下载到bytearray 最后 我设法将默认铃声设置为我下载的铃声 下面不包含下载代码 仅包含将其设置为默认铃声所需的代码 File k new Fil
  • 改造中的多个队列导致内存不足错误?

    我正在使用retrofit2 做我的项目 当我的呼叫失败时 我再次重复相同的呼叫 重复此 呼叫使我的应用程序强制关闭 当我查看日志时 我得到了错误日志 如下所示 我觉得这是由于同一呼叫的多次排队造成的 所以我在排队之前就这样做了 我打电话给
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • 覆盖 Android 中的电源按钮

    我正在开发一个应用程序 其中我需要在按下电源按钮时执行一个操作 但不幸的是我无法处理按下电源按钮时的操作 我尝试使用 onKeyDown 和dispatchKeyEvent 方法 但似乎没有任何效果 任何人都可以建议我解决这个问题的任何其他
  • Android 全屏对话框确认和拒绝操作

    材料设计中的全屏对话框应该在操作栏 工具栏上有确认和拒绝操作 我的问题是 我该怎么做 显示对话框 getFragmentManager beginTransaction add R id container new MyDialogFrag
  • 华为手机“受保护的应用程序”设置及处理方法

    我有一台搭载 Android 5 0 的华为 P8 用于测试应用程序 该应用程序需要在后台运行 因为它跟踪 BLE 区域 我发现华为内置了一个名为 受保护的应用程序 的 功能 可以从手机设置 电池管理器 gt 受保护的应用程序 访问该功能
  • Ionic 2 RC0 和 Angular 2 最新的 Android 构建错误(ngc:错误:静态解析符号值时遇到错误)

    当我使用构建android时出现错误ionic build android命令 ngc 错误 静态解析符号值时遇到错误 引用本地 非导出 符号 字典 考虑导出符号 原始 ts文件中的位置14 8 解析符号TRANSLATION PROVID
  • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

    这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
  • MIUI 权限被拒绝活动 KeyguardLocked

    当应用程序处于后台且屏幕被锁定时 我无法启动活动 没有异常或警告 只是不调用 onCreate 我一直在与这个问题作斗争 我想我终于找到了它的根源 日志中有一行 D com android server am ExtraActivityMa
  • 如何使用 SharedPreferences 保存多个值?

    我正在开发一个字典应用程序 在我的应用程序中 我假设用户想要保存最喜欢的单词 我决定使用共享首选项保存这些值 我知道 SQLite 和文件更好 但我坚持使用 SharedPreferences 所以继续使用它 下面是我的代码 Overrid
  • 是否可以通过 Android 应用程序来录音?

    我是一名开发人员 希望创建一个 Android 应用程序来记录电话 这是出于我个人的需要 为了我自己的目的和记录而记录电话 是否有可能做到这一点 是否可以访问麦克风以及通过扬声器发出的声音 我对 Android 开发有点陌生 所以请耐心等待
  • 在android中,将相机预览流到视图上

    我想将 Android 相机的相机预览流式传输到视图上 目的是随后使用 onDraw 将各种内容添加到视图中 我不需要随时实际捕捉图像 它不必是最高质量或每秒最大数量的帧 有谁知道如何做到这一点 将其添加到您的 xml 中
  • 在运行时更改用作背景的 Drawable xml 内的形状纯色

    我有一个 Drawable xml 文件 background xml
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • Android SearchView 在启动时隐藏键盘

    我有一个小问题正在尝试解决 当我打开应用程序时 键盘会显示输入搜索视图的查询 不过 我只想在单击搜索视图时显示键盘 我该如何解决 Thanks 这对我有用 用于隐藏焦点的代码 searchView SearchView view findV
  • 当目标小于 Android O 时,如何在 Android O 上创建快捷方式?

    背景 Android O 对快捷方式的工作方式进行了各种更改 https developer android com preview behavior changes html as https developer android com
  • 丢失应用程序的密钥库文件(但已启用 Google Play 应用程序签名)

    我已经失去了原来的keystore用于签署我的应用程序的文件 我的应用启用了 Google Play 应用签名 如果我联系 Google 支持人员 是否可以重置密钥 以便我可以继续上传到此包 我希望我可以做到这一点 因为应用程序签名已启用

随机推荐

  • 为什么迭代器方法不能采用“ref”或“out”参数?

    我今天早些时候尝试过这个 public interface IFoo IEnumerable
  • 容器内可滚动的 div

    我有以下 HTML http jsfiddle net fMs67 http jsfiddle net fMs67 我想让 div2 尊重 div1 的大小并滚动 div3 的内容 这可能吗 Thanks 更新1 这是我在提出问题时过于简单
  • JAR 文件:找不到主类

    好吧 我有一个奇怪的问题 我想将我的程序之一作为 jar 文件运行 但是当我双击打开它时 我收到一条错误消息 例如 找不到主类 程序正在关闭 我很确定我做的一切都是正确的 罐子应该可以工作 我也尝试过其他程序 每个程序都是一样的 我通过 B
  • printf 与 std::cout [重复]

    这个问题在这里已经有答案了 可能的重复 我应该在 C 代码中使用 printf 吗 https stackoverflow com questions 2017489 should i use printf in my c code 如果我
  • 如何在一张表中创建多个序列?

    我有一张 收据 表 我有列 customer id 谁有收据 和收据号 对于每个客户 receipt number 应从 1 开始 并且是一个序列 这意味着 customer id 和receipt number 将是唯一的 我怎样才能优雅
  • VIM 自定义箭头键映射不适用于窗口切换?

    我一直在尝试创建一个在 vim 中打开的窗口拆分之间切换的快捷方式 而不是必须使用 ctrl w arrowkey 我更愿意只能够使用 ctrl arrow key 这是我当前的 vimrc 中的内容 map
  • 如何实现hbase安全批量加载

    我已经在 kerberos 集群中的 hbase 中创建了一个批量加载 其驱动程序类与此类似 工作 public static void main String args try int response ToolRunner run HB
  • PHP 传递一个类作为引用?

    在Python中 你可以这样做 class SomeClass object pass s SomeClass someClassInstance s 如何在 PHP 中实现同样的效果 据我了解 你不能这样做吗 这是真的 您可以创建动态类名
  • 向 Pandas Dataframe 中的字符串添加前导零

    我有一个 pandas 数据框 其中前 3 列是字符串 ID text1 text 2 0 2345656 blah blah 1 3456 blah blah 2 541304 blah blah 3 201306 hi blah 4 1
  • 除非填写所有文本输入字段,否则禁用表单按钮

    我有一个具有多个文本输入的表单 我不想为每个输入添加 id 因为它们是从服务器端代码生成的 字段数量可能不同等 我只是希望能够禁用提交按钮 直到出现是输入到每个文本输入中的文本 我已经做到了这一点 但仅在文本输入到一个文本输入字段之前禁用按
  • 如何使用 boost bcp?

    我有 bcp 工具 它是用 boost 安装程序预先构建的 我想将 boost 所需的依赖项提取到一个较小的文件中 因为我希望能够在学校构建这个项目 我正在尝试使用 bcp 但我不明白如何使用它 尽管有以下说明 http www boost
  • Mongodb + Node.js:删除多个文档并返回

    我使用下面的代码一次删除多个文档 db collection testcollection deleteMany id in 1 2 3 function error response 有没有办法一次性删除并返回所有已删除的文档 NOTE
  • 使用 C# 自定义属性进行异常和审计跟踪日志记录

    是否可以创建一个自定义功能来捕获由自定义属性设置的方法中发生的异常 我打算做这样的事情 Logging FeatureEnum SomeFeature IntentEnum SomeIntent some comment public vo
  • 如何构建Graceful Degradation AJAX网页?

    我想用 优雅降级 构建网页 即 即使JavaScript被禁用 网页也能正常工作 现在我必须对 AJAX 响应的格式做出设计决策 如果禁用 javascript 则对服务器的每个 HTTP 请求都会生成 HTML 作为响应 浏览器将刷新并显
  • 为什么结构对齐取决于字段类型是原始类型还是用户定义的?

    In 野田时间 http nodatime orgv2 我们正在转向纳秒分辨率 这意味着我们不能再使用 8 字节整数来表示我们感兴趣的整个时间范围 这促使我研究 Noda Time 的 许多 结构体的内存使用情况 这反过来又引导我发现 CL
  • 让 NppExec 了解 Notepad++ 中当前文件的路径(对于 Python 脚本)

    很长一段时间以来第一次使用 Windows 并使用了 notepad 并使用 nppexec 插件来运行 python 脚本 但是 我注意到 notepad 没有选择保存脚本的目录 例如 我将 script py 放在 我的文档 中 但是
  • 当在 jQueryUI 自动完成列表中选择一个项目时,如何防止输入元素更新?

    我有以下 jQueryUI 自动完成功能 clientSearch autocomplete source function request response var url window apiUrl clients searchText
  • PostgreSQL:在 plpgsql 函数中回滚事务?

    来自 MS SQL 领域的我倾向于大量使用存储过程 我目前正在编写一个应用程序 使用了很多 PostgreSQL plpgsql 函数 我想做的是 如果我在特定函数中的任何点出现异常 则回滚特定函数中包含的所有插入 更新 我最初的印象是每个
  • Xamarin.Forms预览器“连接已关闭”[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 刚刚打开 Xamarin Forms 预览器 它显示 出现问题 连接已关闭 它是全新的 Visual Studio 2017 安装和空白的
  • 方向改变后,Fragment 对 mActivity 的引用变为 null。碎片状态维护无效

    我的应用程序由几个片段组成 到目前为止 我已经将它们的引用存储在自定义应用程序对象中 但我开始认为我做错了什么 当我意识到我的片段对 mActivity 的所有引用在方向更改后都变为空时 我的问题就开始了 因此 当我在方向更改后调用 get