在几页深度之后,页面转换变得非常缓慢

时间:2017-07-30 11:52:13

标签: dart flutter

我正在使用Flutter构建一个简单的Wikipedia浏览器。由于没有本机Flutter Webview,我必须手动解析HTML片段并将其转换为等效的Flutter小部件。我设法这样做但是在浏览了几页之后(通过点击蓝色链接),页面过渡动画变得极其缓慢。

重现的步骤:

添加以下依赖项

dependencies:
  flutter:
    sdk: flutter
  fluro: "^1.1.0"
  html: "^0.13.2"

粘贴并运行以下代码(在发布模式下以便更清晰地观察)。

import 'dart:async';
import 'dart:convert';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:fluro/fluro.dart';
import 'package:html/dom.dart' as DOM;
import 'package:html/parser.dart' show parse;

void main() {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final router = new Router(); // Fluro router

  @override
  void initState() {
    super.initState();
    router.define(
      '/wiki',
      handler: new Handler(
        handlerFunc: (_, params) => new WikiPage(title: params['q'])
      )
    );
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      onGenerateRoute: router.generator, // delegate to Fluro
      routes: {
        '/': (BuildContext context) => new WikiPage(title: 'Firefox')
      },
    );
  }
}

class WikiPage extends StatefulWidget {
  WikiPage({Key key, this.title}) : super(key: key);
  final String title;

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

class _WikiPageState extends State<WikiPage> {

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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text(widget.title)),
      body: new FutureBuilder<String>(
        future: getPage(widget.title),
        builder: (context, snapshot) {
          if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
          if (snapshot.hasData) {
            if (snapshot.data.isEmpty) return new Container(); // empty result

            // parse HTML
            DOM.Document document = parse(snapshot.data);
            document.querySelector('.infobox')?.remove(); // remove the infobox table
            List<DOM.Element> paragraphs = document.getElementsByTagName('p');

            // convert HTML tree to Flutter widgets
            return new ListView(
              padding: const EdgeInsets.all(16.0),
              children: paragraphs.map((paragraph) =>
                new RichText(
                  text: new TextSpan(
                    text: '',
                    style: DefaultTextStyle.of(context).style,
                    children: paragraph.nodes.map((node) {
                      if (node.toString() == '<html a>') { // HTML <a> tag
                        String href = node.attributes['href'];
                        return new TextSpan( // as blue link
                          text: node.text,
                          style: Theme.of(context).textTheme.body1.copyWith(
                            color: Colors.blue
                          ),
                          recognizer: new TapGestureRecognizer()
                            ..onTap = () => Navigator.of(context).pushNamed(
                              '/wiki?q=${href.split('/')[2]}'
                            )
                        );
                      } else {
                        return new TextSpan(text: node.text);
                      }
                    }).toList()
                  )
                )
              ).toList()
            );

          } else { // waiting for data
            return new Center(child: new CircularProgressIndicator());
          }
        },
      )
    );
  }

  Future<String> getPage(String title) async {
    final String url = 'https://en.wikipedia.org/w/api.php?' +
    'action=mobileview&format=json&sections=0&noimages=1&noheadings=1' +
    '&formatversion=2&page=${Uri.encodeComponent(title)}';

    final response = await http.get(url);
    final json = JSON.decode(response.body);
    return json['mobileview']['sections'][0]['text']; // retrieve HTML string
  }
}
  1. 点击任意蓝色维基百科链接进行导航。最初页面过渡动画(前2-3页)是平滑的。新页面从底部(Android平台)滑入。
  2. 但是每次导航时页面转换变得不稳定,直到它冻结一段时间(自下而上的页面转换完全消失)。
  3. 可能是什么问题?垃圾收集器问题?任何帮助表示赞赏。

    [√] Flutter (on Microsoft Windows [Version 10.0.15063], locale en-US, channel master)
        • Flutter at C:\Users\tzm\Downloads\flutter_sdk
        • Framework revision 6655074b37 (2 days ago), 2017-07-28 15:44:38 -0700
        • Engine revision 232f4636e5
        • Tools Dart version 1.25.0-dev.7.0
    

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。诀窍是

  • 使用Dart Isolate将昂贵的HTML解析卸载到单独的线程。
  • 将MaterialPageRoute中的maintainState设置为false,以便以前的计算始终从内存中丢弃。缺点是我们需要在从当前页面弹出时重新生成以前访问过的页面。