Business background

The fish-Redux framework is used in the project. In the state, datetime.now ().toISO8601String () is used to assign uniqueId to each state in the list. This ID is required to be unique.

Those who understand fish-Redux should know that when reduce updates the state in the list, they need to judge whether the uniqueids of the states are the same. Only the uniqueids are the same can they be considered as the same state.

For specific Demo, please refer to the state implementation under fish-redux todo_compoent

The phenomenon of

The project list uses the third-party waterfall stream library Flutter_STAGgered_grid_view, and the result is that the same cards are repeatedly flashed in the adjacent locations, similar to the image below

The reason: The uniqueId generation method of the UniqueIdState class references datetime.now ().toiso8601String (). This method inside the flutter will be duplicate on iPhone 11 Pro Max. The generated String is accurate to the level of microseconds, but there is still a probability that two identical strings will be generated. I suspect it is because the first three microseconds are selected. I have to say that the CPU performance of iPhone 11 Pro Max is very good.

The uniqueId of the third card is the same as that of the fourth card. Notice that the last six digits of the UUID, 200307, indicate that the value of microseconds has been written in.

Solution: Introduce third-party librariesUuid

There are two main methods for Uuid to generate random numbers

1. Uuid().v1(); // The timestamp is also referenced
var clockSeq = (options['clockSeq'] ! = null) ? options['clockSeq'] : _clockSeq; // UUID timestamps are 100 nano-second units since the Gregorian epoch, // (1582-10-15 00:00). Time is handled internally as 'msecs' (integer // milliseconds) and 'nsecs' (100-nanoseconds offset from msecs) since unix // epoch, 1970-01-01 00:00. var mSecs = (options['mSecs'] ! = null) ? options['mSecs'] : (DateTime.now()).millisecondsSinceEpoch; // Note that the timestamp is also referenced, // Per 4.2.1.2, use count of uuid's generated during the current clock // cycle to simulate higher resolution clock var nSecs = (options['nSecs'] ! = null) ? options['nSecs'] : _lastNSecs + 1; // Time since last uuid creation (in msecs) var dt = (mSecs - _lastMSecs) + (nSecs - _lastNSecs) / 10000; / / Per 4.2.1.2. Bump clockseq on clock regression if (dt < 0 && options['clockSeq'] == null) { clockSeq = clockSeq + 1 & 0x3fff; } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new // time interval if ((dt < 0 || mSecs > _lastMSecs) && options['nSecs'] == null) { nSecs = 0; } // Per 4.2.1.2 Throw error if too many uuids are requested if (nSecs >= 10000) {Throw Exception('uuid.v1(): Can\'t create more than 10M uuids/sec'); } _lastMSecs = mSecs; _lastNSecs = nSecs; _clockSeq = clockSeq; Per 4.1.4 - Convert from Unix epoch to Gregorian epoch mSecs += 12219292800000; // Per 4.1.4 - Convert from Unix epoch to Gregorian epoch mSecs += 12219292800000; Return unparse(buf);Copy the code
2. The Uuid (). The v4 (); Based on random algorithm implementation, the final use of V4
options = (options ! = null) ? options : Map<String, dynamic>(); // Use the built-in RNG or a custom provided RNG var positionalArgs = (options['positionalArgs'] ! = null) ? options['positionalArgs'] : []; var namedArgs = (options['namedArgs'] ! = null) ? options['namedArgs'] as Map<Symbol, dynamic> : const <Symbol, dynamic>{}; var rng = (options['rng'] ! = null) ? Function.apply(options['rng'], positionalArgs, namedArgs) : _globalRNG(); Use provided values over RNG var RNDS = (options['random']! = null) ? options['random'] : rng; / / per 4.4, set bits for version and clockSeq high and reserved RNDS [6] = (RNDS [6] & 0 x0f) | 0 x40; rnds[8] = (rnds[8] & 0x3f) | 0x80; return unparse(rnds);Copy the code

The default implementation of _globalRNG()

var rand, b = List<int>(16); var _rand = (seed == -1) ? Random() : Random(seed); Double for (var I = 0; i < 16; i++) { if ((i & 0x03) == 0) { rand = (_rand.nextDouble() * 0x100000000).floor().toInt(); } b[i] = rand >> ((i & 0x03) << 3) & 0xff; } return b;Copy the code
Since you want to use, of course, to do performance comparison

It can be seen that the average value is relatively stable when the number of tests is between 10,000 and 100,000, which can be used as the actual reference value. The performance of uUID is still about a 20-fold difference compared to datetime.now ().toISO8601String (), but considering that business lists are not created more than 30 at a time, you can use V4 without a significant performance penalty. (ps Samsung s7 is a 16-year-old phone, iphone6 is a 14-year-old phone, but from the test results, the same code iphone6 is much faster than Samsung s7, apple dad nb)