Skip to content

Unhandled exception in dispose of message store #810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gnprice opened this issue Jul 13, 2024 · 0 comments · Fixed by #909
Closed

Unhandled exception in dispose of message store #810

gnprice opened this issue Jul 13, 2024 · 0 comments · Fixed by #909
Assignees
Labels
a-model Implementing our data model (PerAccountStore, etc.)

Comments

@gnprice
Copy link
Member

gnprice commented Jul 13, 2024

I saw the following exception on my device just now:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Concurrent modification during iteration: _Set len:0.
#0      _CompactIterator.moveNext (dart:collection-patch/compact_hash.dart:714)
#1      MessageStoreImpl.dispose (package:zulip/model/message.dart:57)
#2      PerAccountStore.dispose (package:zulip/model/store.dart:385)
#3      GlobalStore._setPerAccount (package:zulip/model/store.dart:135)
#4      GlobalStore._reloadPerAccount (package:zulip/model/store.dart:128)
<asynchronous suspension>
#5      UpdateMachine.poll (package:zulip/model/store.dart:733)
<asynchronous suspension>

The context was:

  • I'd had the app open previously, and was looking at a message list
  • Then I connected the device to my computer, and was looking at the logcat view in Android Studio
  • Then I opened up the app again, from the background
  • The error appeared a few seconds later.

From the stack trace, it looks like what happened is that the polling loop found the event queue had expired; it went to replace the store with a new one from a new initial fetch; and then it hit this exception while trying to dispose of the old store.


Looking at the call stack, I'm not sure there are user-visible symptoms from this error. It looks like there are only a few more steps that hadn't yet been taken, all of them various dispose calls.

On the other hand earlier this evening, I had observed a puzzling failure to replace the event queue:

So if this could cause a symptom like that after all, then this could be the diagnosis for that issue #809. (That issue is why I was looking at logcat in the first place. But no luck; it'd been a couple of hours since the issue had happened, and the logs from that time were long since gone.)

In any case, we should fix the issue so that MessageStoreImpl.dispose completes successfully.


A PR fixing this issue should include two kinds of tests:

  • A test focused on that dispose method: make a message store, register a message list or two on it, then call dispose. At a minimum this test can verify no exception is thrown; preferably it should also verify that dispose did its job.

  • A direct regression test for this issue, which will be a bit more of an integration test: make a PerAccountStore and UpdateMachine; register a message list or two on the store; then induce an expired-queue exception in the polling loop so that it replaces the store, and expect no unhandled exceptions. (I believe the test framework will automatically fail the test if there's an unhandled exception.)

    For this test, take as a model the existing tests of the expired-queue recovery feature.

The new tests should fail when run on the code from before the PR (e.g. with git checkout origin -- lib).

@gnprice gnprice added the a-model Implementing our data model (PerAccountStore, etc.) label Jul 13, 2024
@gnprice gnprice added this to the Beta 3: Summer 2024 milestone Jul 13, 2024
@PIG208 PIG208 self-assigned this Aug 22, 2024
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 22, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

The error originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 23, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

The error originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 29, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 29, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 29, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Aug 29, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 4, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 4, 2024
This fixes a bug caused by MessageListView instances unregistering themselves
from the collection containing these instances, while we are iterating the exact
same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a loop
over the exact same collection (the set MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not allowed

This fix avoids those errors by having the loop iterate over a clone of
that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 7, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 12, 2024
This fixes a bug caused by MessageListView instances unregistering
themselves from the collection containing these instances, while we
are iterating the exact same set when disposing the message store.

Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 12, 2024
Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Sep 12, 2024
Part of the work of disposing a MessageListView is to remove it from
a collection of MessageListViews, and we've been doing this in a
loop over the same collection (MessageStoreImpl._messageListViews).
This has been causing concurrent modification errors.

The errors originated from this requirement of dart Iterable:

> Changing a collection while it is being iterated is generally not
  allowed

This fix avoids those errors by having the loop iterate over a clone
of that collection instead.

See also: https://api.flutter.dev/flutter/dart-core/Iterable-class.html

Fixes: zulip#810

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 8, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 8, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 8, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 8, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 10, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/.60MentionAutocompleteView.2Edispose.60/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 11, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 11, 2025
PerAccountStore shouldn't be an owner of the MessageListView objects.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, MessageListView can be disposed twice:

1. before the frame is rendered, `GlobalStore.removeAccount`
   disposes the `PerAccountStore`, which disposes the
  `MessageListView` (via `MessageStoreImpl`), notifying listeners of
  `GlobalStore`.

  At this point `_MessageListState` is not yet disposed.

2. As a dependent of `GlobalStore`, a rebuilt is triggered for
   `PerAccountStoreWidget`. This time, the `MessageList` Element is no
   longer in the element tree

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/.60MentionAutocompleteView.2Edispose.60/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 11, 2025
PerAccountStore shouldn't be an owner of the MessageListView elements.

Its relationship to MessageListView is similar to that of
AutocompleteViewManager to MentionAutocompleteView (zulip#645).

With two owners, the MessageListView can be disposed twice:

1. before the frame is rendered, `removeAccount` disposes the
  `PerAccountStoreWidget`, which disposes the `MessageListView`;
   `_MessageListState` is not yet disposed;

2. during build, because `store` is set to `null`,
  `PerAccountStoreWidget` gets rebuilt. `_MessageListState`,
  a descendent of it, is no longer in the render tree;

3. during finalization, `_MessageListState` tries to dispose the
   `MessageListView`.

This removes regression tests added for zulip#810, because
`MessageStoreImpl.dispose` no longer exists.  `MessageListView` does not
get disposed unless there is a `_MessageListState` owner.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 12, 2025
`PerAccountStore` shouldn't be an owner of the `MessageListView`
objects.

Its relationship to `MessageListView` is similar to that of
`AutocompleteViewManager` to `MentionAutocompleteView` (zulip#645).

With two owners, `MessageListView` can be disposed twice:

1. Before the frame is rendered, after removing the `PerAccountStore`
   from `GlobalStore`, `removeAccount` disposes the `PerAccountStore` ,
   which disposes the `MessageListView` (via `MessageStoreImpl`).

   `removeAccount` also notifies the listeners of `GlobalStore`.

   At this point `_MessageListState` is not yet disposed.

2. Being dependent on `GlobalStore`, `PerAccountStoreWidget` is rebuilt.
   This time, the StatefulElement corresponding to the `MessageList`
   widget, is no longer in the element tree because `PerAccountStoreWidget`
   cannot find the account and builds a placeholder instead.

3. During finalization, `_MessageListState` tries to dispose the
   `MessageListView`, and fails to do so.

We couldn't've kept `MessageStoreImpl.dispose` with an assertion
`_messageListView.isEmpty`, because `PerAccountStore` is disposed before
`_MessageListState.dispose` (and similarily
`_MessageListState.onNewStore`) is called.  Fixing that will be a future
follow-up to this, as noted in the TODO comment.

A regression test for zulip#810 has been appropriated.  The original issue
is relevant because the scenario this integration test targeted still
applies after this change.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/MessageListView.20lifecycle/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 12, 2025
`PerAccountStore` shouldn't be an owner of the `MessageListView`
objects.

Its relationship to `MessageListView` is similar to that of
`AutocompleteViewManager` to `MentionAutocompleteView` (zulip#645).

With two owners, `MessageListView` can be disposed twice:

1. Before the frame is rendered, after removing the `PerAccountStore`
   from `GlobalStore`, `removeAccount` disposes the `PerAccountStore` ,
   which disposes the `MessageListView` (via `MessageStoreImpl`).

   `removeAccount` also notifies the listeners of `GlobalStore`.

   At this point `_MessageListState` is not yet disposed.

2. Being dependent on `GlobalStore`, `PerAccountStoreWidget` is rebuilt.
   This time, the StatefulElement corresponding to the `MessageList`
   widget, is no longer in the element tree because `PerAccountStoreWidget`
   cannot find the account and builds a placeholder instead.

3. During finalization, `_MessageListState` tries to dispose the
   `MessageListView`, and fails to do so.

We couldn't've kept `MessageStoreImpl.dispose` with an assertion
`_messageListView.isEmpty`, because `PerAccountStore` is disposed before
`_MessageListState.dispose` (and similarily
`_MessageListState.onNewStore`) is called.  Fixing that will be a future
follow-up to this, as noted in the TODO comment.

A regression test for zulip#810 has been appropriated.  The original issue
is relevant because the scenario this integration test targeted still
applies after this change.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/MessageListView.20lifecycle/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 12, 2025
`PerAccountStore` shouldn't be an owner of the `MessageListView`
objects.

Its relationship to `MessageListView` is similar to that of
`AutocompleteViewManager` to `MentionAutocompleteView` (zulip#645).

With two owners, `MessageListView` can be disposed twice:

1. Before the frame is rendered, after removing the `PerAccountStore`
   from `GlobalStore`, `removeAccount` disposes the `PerAccountStore` ,
   which disposes the `MessageListView` (via `MessageStoreImpl`).

   `removeAccount` also notifies the listeners of `GlobalStore`.

   At this point `_MessageListState` is not yet disposed.

2. Being dependent on `GlobalStore`, `PerAccountStoreWidget` is rebuilt.
   This time, the StatefulElement corresponding to the `MessageList`
   widget, is no longer in the element tree because `PerAccountStoreWidget`
   cannot find the account and builds a placeholder instead.

3. During finalization, `_MessageListState` tries to dispose the
   `MessageListView`, and fails to do so.

We couldn't've kept `MessageStoreImpl.dispose` with an assertion
`_messageListView.isEmpty`, because `PerAccountStore` is disposed before
`_MessageListState.dispose` (and similarily
`_MessageListState.onNewStore`) is called.  Fixing that will be a future
follow-up to this, as noted in the TODO comment.

A regression test for zulip#810 has been appropriated.  The original issue
is relevant because the scenario this integration test targeted still
applies after this change.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/MessageListView.20lifecycle/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this issue Feb 12, 2025
`PerAccountStore` shouldn't be an owner of the `MessageListView`
objects.

Its relationship to `MessageListView` is similar to that of
`AutocompleteViewManager` to `MentionAutocompleteView` (zulip#645).

With two owners, `MessageListView` can be disposed twice:

1. Before the frame is rendered, after removing the `PerAccountStore`
   from `GlobalStore`, `removeAccount` disposes the `PerAccountStore` ,
   which disposes the `MessageListView` (via `MessageStoreImpl`).

   `removeAccount` also notifies the listeners of `GlobalStore`.

   At this point `_MessageListState` is not yet disposed.

2. Being dependent on `GlobalStore`, `PerAccountStoreWidget` is rebuilt.
   This time, the StatefulElement corresponding to the `MessageList`
   widget, is no longer in the element tree because `PerAccountStoreWidget`
   cannot find the account and builds a placeholder instead.

3. During finalization, `_MessageListState` tries to dispose the
   `MessageListView`, and fails to do so.

We couldn't've kept `MessageStoreImpl.dispose` with an assertion
`_messageListView.isEmpty`, because `PerAccountStore` is disposed before
`_MessageListState.dispose` (and similarily
`_MessageListState.onNewStore`) is called.  Fixing that will be a future
follow-up to this, as noted in the TODO comment.

A regression test for zulip#810 has been appropriated.  The original issue
is relevant because the scenario this integration test targeted still
applies after this change.

See discussion:
  https://chat.zulip.org/#narrow/channel/243-mobile-team/topic/MessageListView.20lifecycle/near/2083074

Signed-off-by: Zixuan James Li <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a-model Implementing our data model (PerAccountStore, etc.)
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants