Skip to content

Commit 9d557a7

Browse files
committed
Avoid NPE if addPerfListener is called out of order with creating
perfManager.getCurrentStats() Add removePerfListener call so we don't have to guess about lifecycles for perf listeners.
1 parent 8bb7a47 commit 9d557a7

File tree

5 files changed

+38
-4
lines changed

5 files changed

+38
-4
lines changed

src/io/flutter/perf/FlutterWidgetPerf.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class StatsForReportKind {
6363
private boolean requestInProgress = false;
6464
private long lastRequestTime;
6565

66-
private final List<PerfModel> perfListeners = new ArrayList<>();
66+
private final Set<PerfModel> perfListeners = new HashSet<>();
6767

6868
private final Map<TextEditor, EditorPerfModel> editorDecorations = new HashMap<>();
6969
private final TIntObjectHashMap<Location> knownLocationIds = new TIntObjectHashMap<>();
@@ -246,6 +246,11 @@ public void addPerfListener(PerfModel listener) {
246246
perfListeners.add(listener);
247247
}
248248

249+
@Override
250+
public void removePerfListener(PerfModel listener) {
251+
perfListeners.remove(listener);
252+
}
253+
249254
private StatsForReportKind getStatsForKind(PerfReportKind kind) {
250255
StatsForReportKind report = stats.get(kind);
251256
if (report == null) {

src/io/flutter/perf/FlutterWidgetPerfManager.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public FlutterWidgetPerf getCurrentStats() {
6262
private boolean trackRepaintWidgets = trackRepaintWidgetsDefault;
6363
private boolean debugIsActive;
6464

65+
private final Set<PerfModel> listeners = new HashSet<>();
66+
6567
/**
6668
* File editors visible to the user that might contain widgets.
6769
*/
@@ -197,6 +199,10 @@ private void debugActive(Project project, FlutterViewMessages.FlutterDebugEvent
197199
(TextEditor textEditor) -> new EditorPerfDecorations(textEditor, app),
198200
path -> new DocumentFileLocationMapper(path, app.getProject())
199201
);
202+
203+
for (PerfModel listener : listeners) {
204+
currentStats.addPerfListener(listener);
205+
}
200206
}
201207

202208
public void stateChanged(FlutterApp.State newState) {
@@ -318,6 +324,21 @@ public void dispose() {
318324
if (currentStats != null) {
319325
currentStats.dispose();
320326
currentStats = null;
327+
listeners.clear();
328+
}
329+
}
330+
331+
public void addPerfListener(PerfModel listener) {
332+
listeners.add(listener);
333+
if (currentStats != null) {
334+
currentStats.addPerfListener(listener);
335+
}
336+
}
337+
338+
public void removePerfListener(PerfModel listener) {
339+
listeners.remove(listener);
340+
if (currentStats != null) {
341+
currentStats.removePerfListener(listener);
321342
}
322343
}
323344
}

src/io/flutter/perf/WidgetPerfListener.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ public interface WidgetPerfListener {
1818
void onNavigation();
1919

2020
void addPerfListener(PerfModel listener);
21+
void removePerfListener(PerfModel listener);
2122
}

src/io/flutter/view/WidgetPerfSummaryView.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import java.awt.*;
2020
import java.awt.event.ActionEvent;
2121

22-
class WidgetPerfSummaryView extends JPanel {
22+
class WidgetPerfSummaryView extends JPanel implements Disposable {
2323
private static final int REFRESH_TABLE_DELAY = 100;
2424
private final FlutterApp app;
2525
private final FlutterWidgetPerfManager perfManager;
@@ -45,14 +45,19 @@ class WidgetPerfSummaryView extends JPanel {
4545

4646
table = new WidgetPerfTable(app, parentDisposable, metric);
4747

48-
perfManager.getCurrentStats().addPerfListener(table);
48+
Disposer.register(parentDisposable, this);
49+
50+
perfManager.addPerfListener(table);
4951

5052
add(ScrollPaneFactory.createScrollPane(table), BorderLayout.CENTER);
5153

5254
// Perf info and tips
5355
myWidgetPerfTipsPanel = new WidgetPerfTipsPanel(parentDisposable, app);
56+
}
5457

55-
Disposer.register(parentDisposable, refreshTableTimer::stop);
58+
public void dispose() {
59+
perfManager.removePerfListener(table);
60+
refreshTableTimer.stop();
5661
}
5762

5863
public WidgetPerfTipsPanel getWidgetPerfTipsPanel() {

testSrc/unit/io/flutter/perf/FlutterWidgetPerfTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ public void testOverallStatsCalculation() throws InterruptedException, Execution
515515
// Verify that an idle event occurs once we wait the idle time delay.
516516
Thread.sleep(IDLE_DELAY_MILISECONDS);
517517
assertEquals(1, perfModel.idleCount);
518+
519+
flutterWidgetPerf.removePerfListener(perfModel);
518520
flutterWidgetPerf.dispose();
519521
}
520522
}

0 commit comments

Comments
 (0)