如何实现应用程序屏幕的定期重新渲染

时间:2018-10-05 22:02:57

标签: dart flutter

在研究过程中,我发现了以下内容:

// ignore_for_file: camel_case_types
// ignore_for_file: constant_identifier_names
// ignore_for_file: non_constant_identifier_names

import 'dart:async';
import 'dart:io';
import 'dart:math';

main() {
  randomize_flash_indices();
  print ( "flash indices : $flash_indices" );

  listen_countup();
  }

List<int> flash_indices = [ ];
int       level = 9;
var       random = new Random ( );

void randomize_flash_indices() {

  flash_indices.clear();
  for ( int i = 0; ( i < level); i++ ) {
    flash_indices.add ( random.nextInt ( level ) );
  }
} // randomize_flash_indices()

listen_countup() async {
  await for (int i in level_countup()) {
    int flash_index = flash_indices[i];
    print("Flash Tile: $flash_index");
  }
} // listen_countup()

Stream<int> level_countup() async* {

   for ( int i = 0; ( i < level ); i++ ){
    sleep(new Duration(seconds: 1));
    yield i;
  }
} // level_countup()

执行时,我获得:

I/flutter (27111): flash indices : [5, 3, 7, 7, 7, 4, 3, 1, 0]
I/flutter (27111): Flash Tile: 5
I/flutter (27111): Flash Tile: 3
I/flutter (27111): Flash Tile: 7
I/flutter (27111): Flash Tile: 7
I/flutter (27111): Flash Tile: 7
I/flutter (27111): Flash Tile: 4
I/flutter (27111): Flash Tile: 3
I/flutter (27111): Flash Tile: 1
I/flutter (27111): Flash Tile: 0

每行以大约1秒的间隔输出。这种范例似乎是我实现应用程序屏幕的定期重新渲染所需要的。我的实现是:

// ignore_for_file: camel_case_types
// ignore_for_file: constant_identifier_names
// ignore_for_file: non_constant_identifier_names

// https://stackoverflow.com/questions/52523548/
//         rendering-a-screen-on-icon-tap/52525090#52525090
// https://sergiandreplace.com/flutter-animations-the-basics/

import 'package:flutter/material.dart';

import 'dart:async';
import 'dart:io';

import 'appconstants.dart';
import 'appstate.dart';

class Circles extends StatefulWidget {
  final AppState app_state;

  Circles({
    @required this.app_state,
    Key key,
  }) : super(key: key);

  @override
  CirclesState createState() =>
    new CirclesState();
} // class Circles

class CirclesState extends State<Circles>{

  int             flash_tile = -1;
  List<GridTile>  grid_tiles = <GridTile>[];

  @override
  void initState() {
    super.initState();
    listen_for_tick();
  } // initState()

  listen_for_tick() async {
    await for (int tick in up_tick()) {
print('listen_for_tick() tick: $tick');
      this.setState(() {
        this.flash_tile = widget.app_state.flash_indices[tick];
      });
    }
  }// listen_for_tick

  Stream<int> up_tick() async* {

    for ( int tick = 0; ( tick < widget.app_state.counter ); tick++ ){
print('up_tick() tick: $tick');
      sleep(Constants.ONE_SECOND);
      yield tick;
    }
  } // up_tick

  GridTile new_circle_tile(Color tile_color,
                           int   index) {
    GridTile tile = GridTile(
        child: GestureDetector(
          child: Container(
            decoration: BoxDecoration(
              color: tile_color,
              shape: BoxShape.circle,
            ),
          ),
        )
      );
    return (tile);
  } // new_circle_tile

  List<GridTile> create_circle_tiles() {
    grid_tiles = new List<GridTile>();

    for (int i = 0; (i < Constants.NUMBER_TILES); i++) {
      Color tile_color = ( this.flash_tile == i) ?
                  Circle_Colors.bright_colors[i] :
                  Circle_Colors.normal_colors[i];

      grid_tiles.add(new_circle_tile(tile_color, i));
    }
    return (grid_tiles);
  } // create_circle_tiles

  @override
  Widget build(BuildContext context) {
print(widget.app_state.toString()+' flash_tile: $flash_tile');
    return GridView.count(
      shrinkWrap: true,
      crossAxisCount: Constants.CROSS_AXIS_COUNT,
      childAspectRatio: 1.0,
      padding: const EdgeInsets.all(4.0),
      mainAxisSpacing: Constants.MAIN_AXIS_SPACING,
      crossAxisSpacing: Constants.CROSS_AXIS_SPACING,
      children: create_circle_tiles(),
    );
  }

} // class CirclesState

我每次点击AppBar图标时都会发生的事情是,每个圆圈都会按照flash_indices中指定的顺序闪烁。相反,我得到的是屏幕显示没有变化,而是:

Launching lib\main.dart on SM G925V in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
I/flutter (28374): AppState{counter: 0, flash_indices: []} flash_tile: -1
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 0
W/System  (28374): ClassLoader referenced unknown path: /system/framework/QPerformance.jar
E/BoostFramework(28374): BoostFramework() : Exception_1 = java.lang.ClassNotFoundException: Didn't find class "com.qualcomm.qti.Performance" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]
V/BoostFramework(28374): BoostFramework() : mPerf = null
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 1
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 0
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 1
I/flutter (28374): AppState{counter: 1, flash_indices: [0]} flash_tile: -1
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 0
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 1
I/flutter (28374): AppState{counter: 2, flash_indices: [1, 1]} flash_tile: -1
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 0
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 1
I/flutter (28374): AppState{counter: 3, flash_indices: [0, 0, 0]} flash_tile: -1
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 0
D/ViewRootImpl@6af19[MainActivity](28374): ViewPostImeInputStage processPointer 1
I/flutter (28374): AppState{counter: 4, flash_indices: [0, 2, 2, 2]} flash_tile: -1
Application finished.
Exited (sigterm)

似乎没有调用过listen_for_tick()。我不知道怎么了。

1 个答案:

答案 0 :(得分:0)

我认为sleep是您的恶棍,它是同步的,将其放在for中会干扰应用程序重新绘制自身的方式。 sleep锁定线程,应用程序挂在那里,而不是被重新绘制。

我已使用StreamControllerStreamSubscription重写了您的代码。我使用了sleep,而不是Future.delay。查看是否可以调整代码以使用控制器和订阅。

import 'package:flutter/material.dart';

import 'dart:async';
import 'dart:io';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Periodic',
      theme: new ThemeData(primarySwatch: Colors.indigo),
      home: new Circles(),
    );
  }
}

class AppState {
  AppState() {
    flash_indices = [5, 0, 3, 6, 2, 1, 4];
    counter = flash_indices.length;
  }

  List<int> flash_indices;
  int counter;

  String toString() {
    return "FakeAppState";
  }

  StreamController<int> _tickController;

  Stream<int> startTicking() {
    _tickController = new StreamController();

    for ( int tick = 0; ( tick < counter ); tick++ ) {
      Future.delayed(Duration(seconds: tick), () {
        print('startTicking() tick: $tick');
        _tickController.add(tick);
      });
    }

    return _tickController.stream;
  }
}

class Circles extends StatefulWidget {
  final app_state = new AppState();

  @override
  CirclesState createState() => new CirclesState();
}

class CirclesState extends State<Circles>{
  int flash_tile = -1;
  List<GridTile>  grid_tiles = <GridTile>[];

  StreamSubscription<int> tickListener;

  @override
  void initState() {
    super.initState();
    tickListener = widget.app_state.startTicking().listen(_individualTickListener);
  }

  @override
  void dispose() {
    if (tickListener != null) {
      tickListener.cancel();
      tickListener = null;
    }
    super.dispose();
  }

  _individualTickListener(int tick) async {
    print('listen_for_tick() tick: $tick');
    this.setState(() => this.flash_tile = widget.app_state.flash_indices[tick]);
  }

  GridTile new_circle_tile(Color tile_color,
                           int   index) {
    GridTile tile = GridTile(
        child: GestureDetector(
          child: Container(
            decoration: BoxDecoration(
              color: tile_color,
              shape: BoxShape.circle,
            ),
          ),
        )
      );
    return (tile);
  }

  List<GridTile> create_circle_tiles() {
    grid_tiles = new List<GridTile>();

    for (int i = 0; (i < widget.app_state.counter); i++) {
      Color tile_color = ( this.flash_tile == i) ?
                  Colors.yellow : Colors.green;

      grid_tiles.add(new_circle_tile(tile_color, i));
    }
    return (grid_tiles);
  }

  @override
  Widget build(BuildContext context) {
    print(widget.app_state.toString()+' flash_tile: $flash_tile');

    return Column(
      children: [
        GridView.count(
          shrinkWrap: true,
          crossAxisCount: widget.app_state.counter,
          childAspectRatio: 1.0,
          padding: const EdgeInsets.all(4.0),
          mainAxisSpacing: 2.0,
          crossAxisSpacing: 2.0,
          children: create_circle_tiles(),
        ),
        RaisedButton(
          child: Text("restart"), 
          onPressed: () {
            tickListener = widget.app_state.startTicking().listen(_individualTickListener);
          }
        ),
      ]
    );
  }
}