方向改变后,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。碎片状态维护无效 的相关文章

  • Android短音的正确播放方法?

    我正在创建一个应用程序 屏幕上将有多个图像 这些图像将是按钮 点击时会播放短促的声音 我对此进行了研究 只能找到我当前用来播放声音的方法 这似乎根本没有响应 我希望声音能够快速播放并且能够响应多次快速点击 我不确定这在 Android 中是
  • AdapterContextMenuInfo 始终为 null

    我尝试通过 android 开发文档中的书来做到这一点 this didn t create a menu i don t know why registerForContextMenu getListView setListAdapter
  • 如何使用 Google Maps for Android V2 处理地图移动结束?

    我想在地图中心更改后立即对地址进行地理编码 如何使用新的 Android 版 Google 地图 V2 处理地图移动 我说的是用户用手指拖动地图的情况 查看新的地图 API Override public void onMapReady G
  • Android 初学者:Android gridview 中的触摸事件

    我正在使用以下代码来使用 gridview 执行操作 稍作修改http developer android com resources tutorials views hello gridview html http developer a
  • 如何重定向到 instagram://user?username={username}

    我的 html 页面上有这个链接 可以在特定用户上打开 Instagram 应用程序 a href Link to Instagram Profile a 我一直在寻找自动运行 url instagram user username USE
  • ExoPlayer2 - 如何使 HTTP 301 重定向工作?

    我开始使用 ExoPlayer 来传输一些音频 一切都很顺利 直到我遇到一个带有 301 永久移动 重定向的 URL ExoPlayer2 默认情况下不处理该问题 我已经看过这个线程 https github com google ExoP
  • 在 android 中建立与 MySQL 的池连接

    我需要从我的 Android 应用程序访问 MySQL 数据库 现在所有的工作都通过 DriverManager getConnection url 等等 但我必须从多个线程访问数据库 所以我必须使用连接池 问题1 是 com mysql
  • 从 BroadcastReceiver 类调用活动方法

    我知道我可以做一个内部接收器类来调用接收器中的任何方法 但我的主要活动太大了 要做的事情也很多 因此 我需要一个扩展广播接收器的类 但它不是内部类 并且可以从我的主要活动中调用一种方法 我不知道是否可能 但我的活动是家庭活动和 single
  • Android - AudioRecord类不读取数据,audioData和fftArray返回零

    我是 Android 新手 一直在开发音调分析器应用程序 最低 SDK 8 我读了很多关于如何实现 Audiorecord 类的文章 但我想知道为什么它在我录制时不读取任何数据 我尝试显示 audioData 和 fftArray 的值 但
  • Android 构建发布失败,原因为:java.lang.ArrayIndexOutOfBoundsException:213(pr​​oguard 问题)

    我的项目使用调试构建变体构建得很好 但使用发布变体 Android Studio 会抛出 引起原因 java lang ArrayIndexOutOfBoundsException 213 可能是什么问题 如果我设置minifyEnable
  • OnLongClickListener 不工作

    我有一个ImageView 我需要使用onLongClickListener对于图像视图 当我使用这段代码时 什么也没有发生 Code gallery Gallery findViewById R id gall1 gallery setA
  • 您使用什么物理 Android 设备进行测试?

    有什么好的推荐用于测试目的的物理 Android 设备吗 我正在苹果阵营寻找像 iPod touch 这样的设备 可以帮助 iOS 开发人员测试他们的东西 我知道有 Nexus One 但那东西相当昂贵 而且我并不真正关心手机的东西 而是可
  • Dagger 2 没有生成我的组件类

    我正在使用 Dagger 2 创建我的依赖注入 几个小时前它还在工作 但现在不再生成组件 这是我创建组件的地方 public class App extends Application CacheComponent mCacheCompon
  • Android 如何将总天数准确更改为年、月、日?

    我正在做一个应用程序 该应用程序与根据给定的生日日期输入获取一个人的年龄有关 为此 我从下面的代码中获取从该日期到当前日期的总天数 String strThatDay 1991 05 10 SimpleDateFormat formatte
  • 通过系统应用程序以编程方式静默安装 apk(无需 root)

    我有带有 android sharedUserId android uid system UID 1000 的系统级应用程序 设备未root INSTALL PACKAGES 权限包含在清单中 我可以静默安装下载的 apk 吗 我已经发现这
  • 没有支持 FEATURE_CAMERA_EXTERNAL 的 Android 设备

    根据this doc https source android com devices camera external usb cameras一些 Android 设备允许使用 Camera2 API 访问外部 USB 摄像头 我检查了大约
  • 如何使用 AccessibilityService 在 Android 中模拟按键

    我正在编写一个辅助服务 我一直在尝试在应用程序上进行一些自动搜索 我使用accessibilityservice action paste来填充EditText 然后我需要模拟软键盘上的按键 但我不知道如何做 你们能帮我一下吗 你可以尝试A
  • 我的应用程序中的后退按钮出现问题[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想在手机关闭时清除共享首选项值 你
  • Dagger 2 中“HasFragmentInjector”的实际用法是什么

    我之前已经实现了 dagger2 v2 2 但现在他们也添加了 dagger android 部分 所以我正在用它创建示例项目 我知道旧的方法论 Provide and Modules and 成分等注释 但从 Dagger 2 8 开始
  • Git 实验分支还是单独的实验存储库?

    我正在开发一个 Android 应用程序 并且在整个开发周期中一直使用 Git 现在 我想构建并发布实验性功能 供人们尝试和安装 同时仍将原始的 稳定的应用程序安装在他们的设备上 现在 这意味着我需要使用不同的包名称 这会更改开发项目中的一

随机推荐

  • 为什么迭代器方法不能采用“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