Skip to content

Flutter can load old or stale application code, randomly. #72868

@esDotDev

Description

@esDotDev

Problem
On android (and maybe elsewhere), Flutter can load old or stale application code, randomly. This leads to extremely frustrating test and debug cycles.

I have been experiencing this with Flutter, for over a year (since I started working with it), but it's always been hard to catch, and usually related to some runtime errors. It's my top issue with productivity in Flutter, but I've never had clean reproduction steps, it just happens, randomly, and usually at the most in-opportune times.

Today I think I've found a reproduceable way to make it happen when testing the Restoration API. And hopefully this can lead to fixing the issue overall.

2020-12-23_02-58-39.mp4

@29s, 39s, and 50s in this video, you can see Flutter loading the previous version of the application 3 times, even though I have repeatedly hot-reloaded a new view. The text has clearly been set to end-alignment, but somehow it reverts to center.

When I hot reload a 2d time, the new view comes back. When the app is restored, the old view comes back!

This is the stuff of developer nightmare fuel. Somewhere is a cached version of the app, that should definitely not be there.

Please, whatever you have to do, make sure that we never get an old version of the app running.. It might seem like a small issue, but at production, at scale, when you're chasing bugs, and you can never be quite sure if your new code is actually being ran... it's really tough to work with, and mentally draining.

It's exacerbated by the frameworks tendency to throw a ton of assert errors, which generally seem to precede this behavior. This makes it hard to spot on small projects as well, it tends to manifest when you're at scale, and when you're in the middle of crunch time. When you do a full stop and deploy, it goes away, which makes it extremely hard to catch.

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel dev, 1.26.0-1.0.pre, on Microsoft Windows [Version 10.0.19041.630], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.7.6)
[√] Android Studio (version 4.0)
[√] VS Code (version 1.52.1)
[√] Connected device (3 available)

Repro Steps:

  1. In Android Developer settings, set to "Don't Keep Activities"
  2. Install and run the following code
  3. Make changes to the _RestorableCounterState, and force the app to be reloaded, and observe as it easily gets out of sync.
import 'package:flutter/material.dart';

void main() => runApp(RestorationExampleApp());

class RestorationExampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      restorationScopeId: 'app',
      title: 'Restorable Counter',
      home: RestorableCounter(restorationId: 'counter'),
    );
  }
}

class RestorableCounter extends StatefulWidget {
  RestorableCounter({Key key, this.restorationId}) : super(key: key);

  final String restorationId;

  @override
  _RestorableCounterState createState() => _RestorableCounterState();
}

class _RestorableCounterState extends State<RestorableCounter> with RestorationMixin {
  RestorableInt _counter = RestorableInt(0);

  @override
  String get restorationId => widget.restorationId;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            Text('${_counter.value}', style: Theme.of(context).textTheme.headline4),
            SizedBox(height: 100)
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() => _counter.value++),
        child: Icon(Icons.add),
      ),
    );
  }

  @override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) => registerForRestoration(_counter, "_counter");
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: datalossCan result in the user losing their statec: performanceRelates to speed or footprint issues (see "perf:" labels)found in release: 1.25Found to occur in 1.25found in release: 1.26Found to occur in 1.26frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyr: fixedIssue is closed as already fixed in a newer version

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions