Skip to content

fix: null check operator used on a null value#3447

Merged
mdmohsin7 merged 2 commits intomainfrom
fix/null-check
Nov 30, 2025
Merged

fix: null check operator used on a null value#3447
mdmohsin7 merged 2 commits intomainfrom
fix/null-check

Conversation

@krushnarout
Copy link
Copy Markdown
Member

@krushnarout krushnarout commented Nov 17, 2025

setState was called after the widget was already removed

fix: Added mounted checks and moved provider updates outside of setState

closes #3442

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully addresses the issue of calling setState on a disposed widget by adding mounted checks. The refactoring of _applyFilter to use a single setState call is a good improvement. However, this has led to a situation in initState where two setState calls are made in succession, which is inefficient. My review includes suggestions to consolidate these into a single call to improve performance and fully align with the goal of using a single setState.

Comment on lines 176 to +181
_applyFilter(_currentFilter);

// Mark initial load as complete
if (mounted) {
setState(() {
_isInitialLoad = false;
});
}
setState(() {
_isInitialLoad = false;
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two separate setState calls here, one inside _applyFilter and another one here to set _isInitialLoad. This is inefficient as it causes two rebuilds. After applying the suggested change to _applyFilter to accept a callback, you can combine these into a single state update.

      _applyFilter(_currentFilter, andThen: () {
        _isInitialLoad = false;
      });

Comment thread app/lib/pages/memories/page.dart Outdated
Comment on lines 192 to 216
void _applyFilter(FilterOption option) {
setState(() {
_currentFilter = option;
if (!mounted) return;

switch (option) {
case FilterOption.interesting:
_filterByCategory(MemoryCategory.interesting);
MixpanelManager().memoriesFiltered('interesting');
break;
case FilterOption.system:
_filterByCategory(MemoryCategory.system);
MixpanelManager().memoriesFiltered('system');
break;
case FilterOption.all:
_filterByCategory(null); // null means no category filter
MixpanelManager().memoriesFiltered('all');
break;
}
});
}
MemoryCategory? category;
switch (option) {
case FilterOption.interesting:
category = MemoryCategory.interesting;
MixpanelManager().memoriesFiltered('interesting');
break;
case FilterOption.system:
category = MemoryCategory.system;
MixpanelManager().memoriesFiltered('system');
break;
case FilterOption.all:
category = null; // null means no category filter
MixpanelManager().memoriesFiltered('all');
break;
}

void _filterByCategory(MemoryCategory? category) {
if (!mounted) return;

setState(() {
_currentFilter = option;
_selectedCategory = category;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To allow combining setState calls from different places (like in initState), you can modify this method to accept an optional callback. This callback can be executed inside the setState block, consolidating multiple state updates into one. This improves performance by reducing unnecessary rebuilds.

Additionally, the mounted check on line 211 is redundant since there's already a check on line 193 and no await operations are performed in between. The suggested change removes it.

  void _applyFilter(FilterOption option, {void Function()? andThen}) {
    if (!mounted) return;

    MemoryCategory? category;
    switch (option) {
      case FilterOption.interesting:
        category = MemoryCategory.interesting;
        MixpanelManager().memoriesFiltered('interesting');
        break;
      case FilterOption.system:
        category = MemoryCategory.system;
        MixpanelManager().memoriesFiltered('system');
        break;
      case FilterOption.all:
        category = null; // null means no category filter
        MixpanelManager().memoriesFiltered('all');
        break;
    }

    setState(() {
      _currentFilter = option;
      _selectedCategory = category;
      andThen?.call();
    });
  }

@aaravgarg
Copy link
Copy Markdown
Collaborator

@krushnarout conflicts

@aaravgarg
Copy link
Copy Markdown
Collaborator

@krushnarout ready? if yes pls tag thinh

@mdmohsin7 mdmohsin7 merged commit e880f0e into main Nov 30, 2025
1 check passed
@mdmohsin7 mdmohsin7 deleted the fix/null-check branch November 30, 2025 08:24
ellaaicare pushed a commit to ellaaicare/omi that referenced this pull request Dec 6, 2025
Cherry-picked crash fixes from BasedHardware/omi:
- 51351be: null check operator fix in app_detail.dart (BasedHardware#3305)
- cfba83e: RangeError fix in capture_provider.dart (BasedHardware#3306)
- e875812: async device null crash fix (BasedHardware#3476)
- a491646: audio file handling fix in Swift SDK (BasedHardware#3501)
- ec86179: mounted checks in memories page (BasedHardware#3447)

These fixes prevent:
- Null pointer crashes on app detail page
- RangeError when processing transcripts
- Async device connection crashes
- Audio file accumulation in Swift SDK
- Widget state errors after unmount

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
`setState` was called after the widget was already removed

fix: Added mounted checks and moved provider updates outside of setState

closes BasedHardware#3442
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FlutterError - MemoriesPageState._applyFilter

3 participants