Reputation:
I am building a simple Wikipedia browser using Flutter. Since there is no native Flutter Webview, I have to manually parse and convert the HTML fragment into equivalent Flutter widgets. I managed to do so but after navigating several pages deep (by clicking on the blue links), the page transition animation became excruciatingly slow.
Steps to reproduce:
Add the following dependencies
dependencies:
flutter:
sdk: flutter
fluro: "^1.1.0"
html: "^0.13.2"
Paste and run the following code (in release mode for clearer observation).
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§ions=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
}
}
What could be the problem? Garbage collector issue? Any help is appreciated.
[√] 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
Upvotes: 2
Views: 3574
Reputation:
I found the solution. The trick is to
maintainState
in MaterialPageRoute to false
so that previous computations are always discarded from memory. The downside is that we need to regenerate previously visited pages as we pop from our current page.Upvotes: 1