问题描述
我尝试过
var e = [2,5,6,7];
e.forEach((element) {
print(element);
Timer.periodic(new Duration(seconds: element),(timer) {
debugPrint(element.toString());
sleep(Duration(seconds: element));
});
});
但它似乎混乱了,计时器无法按预期工作。
输出为2,2,7,7
预期输出为2,7
我的目标是我需要使用不同的计时器生成类似GIF的图像。
我需要提取dart中的HTML代码,在HTML代码中有图像路径和每个图像的显示时间。
目前,我可以通过图像网络生成图像。但是计时器仍然有问题。我尝试过上面的代码,但是输出错误。
这里是完整代码,
import 'dart:async';
import 'dart:developer';
import 'dart:ffi';
import 'dart:io';
import 'dart:convert';
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:Flutter/material.dart';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:Flutter/src/foundation/constants.dart';
import 'package:html/parser.dart' show parse;
import 'package:html/dom.dart' as Dom;
import 'package:shared_preferences/shared_preferences.dart';
// import 'package:firebase_admob/firebase_admob.dart';
import 'player_widget.dart';
typedef void OnError(Exception exception);
const kUrl1 =
'http://n0c.radiojar.com/1t04vq7uc6quv?rj-ttl=5&rj-tok=AAABcd71RMcAnUEp0f_GRjz3pw';
const String testDevice = 'MobileId';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false,home: ExampleApp()));
}
class ExampleApp extends StatefulWidget {
@override
_ExampleAppState createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
AudioCache audioCache = AudioCache();
AudioPlayer advancedplayer = AudioPlayer();
String localFilePath;
String a;
@override
void initState() {
super.initState();
if (kIsWeb) {
// Calls to Platform.isIOS fails on web
return;
}
if (Platform.isIOS) {
if (audioCache.fixedplayer != null) {
audioCache.fixedplayer.startHeadlessService();
}
advancedplayer.startHeadlessService();
}
}
Future saveCompanyAds() async {
final response = await Client().get("http://www.putrajaya.fm/");
final SharedPreferences prefs = await SharedPreferences.getInstance();
final List<String> listlogo = [];
final List<String> listBanner = [];
final List<int> listNumberlogo = [];
final List<int> listNumberBanner = [];
final List<int> listTimelogo = [];
final List<int> listTimeBanner = [];
final List<Tag> tagsBanner = [];
final List<Tag> tagslogo = [];
RegExp expBanner = new RegExp(r'(gambar)\[[0-9]\].+');
RegExp explogo = new RegExp(r'(images)\[[0-9]\].+');
RegExp expNumArr = new RegExp(r'\[[0-9]+\]');
RegExp expURL =
new RegExp(r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+');
RegExp expTime = new RegExp(r'(\/\/time=)[0-9]+');
prefs.remove("banner");
prefs.remove("logo");
if (response.statusCode == 200) {
var document = parse(response.body);
String text = document.getElementById("radio_jar").outerHtml;
Iterable<RegExpMatch> matchesBanner = expBanner.allMatches(text);
Iterable<RegExpMatch> matcheslogo = explogo.allMatches(text);
matchesBanner.forEach((matchB) {
listBanner.add(text.substring(matchB.start,matchB.end));
});
matcheslogo.forEach((matchL) {
listlogo.add(text.substring(matchL.start,matchL.end));
});
listBanner.forEach((fB) {
var a = expNumArr.stringMatch(fB);
var b = a.replaceAll(RegExp('[^0-9]+'),'');
var c = int.parse(b);
listNumberBanner.add(c);
var g = expURL.stringMatch(fB);
var d = expTime.stringMatch(fB);
var e = d.replaceAll(RegExp('[^0-9]+'),'');
var f = int.parse(e);
listTimeBanner.add(f);
tagsBanner.add(Tag(c,g,f));
});
listlogo.forEach((fL) {
var a = expNumArr.stringMatch(fL);
var b = a.replaceAll(RegExp('[^0-9]+'),'');
var c = int.parse(b);
listNumberlogo.add(c);
var g = expURL.stringMatch(fL);
var d = expTime.stringMatch(fL);
var e = d.replaceAll(RegExp('[^0-9]+'),'');
var f = int.parse(e);
listTimelogo.add(f);
tagslogo.add(Tag(c,f));
});
String jsonTagsBanner = jsonEncode(tagsBanner);
String jsonTagslogo = jsonEncode(tagslogo);
prefs.setString("banner",jsonTagsBanner);
prefs.setString("logo",jsonTagslogo);
}
}
Future readCompanyAds() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
List listBannerjsonDecode = [];
List listlogoJSONDecode = [];
listBannerjsonDecode = jsonDecode(prefs.getString("banner"));
listlogoJSONDecode = jsonDecode(prefs.getString("logo"));
List<String> bannerList = List<String>();
List<int> timerbannerList = List<int>();
final List<String> listBannerNetwork = List<String>();
final List<int> listBannerTimer = List<int>();
listBannerjsonDecode.forEach((elementBanner) => {
listBannerNetwork.add(elementBanner['url']),listBannerTimer.add(elementBanner['time'])
});
listBannerNetwork.forEach((urlBanner) {
bannerList.add(urlBanner);
});
//Currently I insert the first element to avoid app crash
a = bannerList[0];
listBannerTimer.forEach((timeBanner) {
timerbannerList.add(timeBanner);
});
//this is where I want to insert the GIF with different timer by using
//timerbannerList and I want to replace it with the variable "a" above.
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: Future.wait([saveCompanyAds(),readCompanyAds()]),builder: (BuildContext context,AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: new Column(
mainAxisSize: MainAxisSize.min,children: [
new CircularProgressIndicator(
backgroundColor: Colors.white,),],);
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return MultiProvider(
providers: [
StreamProvider<Duration>.value(
initialData: Duration(),value: advancedplayer.onAudioPositionChanged),child: Scaffold(
appBar: AppBar(
title: Text('Putrajaya FM'),body: Column(
children: <Widget>[
Image.asset('images/putrajayafm.jpg',fit: BoxFit.fill,height: 200,width: double.infinity),Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[PlayerWidget(url: kUrl1)])),Container(
margin: EdgeInsets.only(top: 20),child: Row(
mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: <Widget>[
//this is where I call the "a" variable,//where it should be repalced with list of
//image with different timer
Image.network(a,height:
(MediaQuery.of(context).size.width / 2),width:
(MediaQuery.of(context).size.width / 2)),Image.asset('images/logo2.gif',width:
(MediaQuery.of(context).size.width / 2))
],)),Expanded(
child: Container(
child: Image.network(a,width: MediaQuery.of(context).size.width),))
],);
}
},);
}
}
class Tag {
int number;
String url;
int time;
Tag(this.number,this.url,this.time);
Map<String,dynamic> toJson() => {'number': number,'url': url,'time': time};
}
解决方法
您所显示的代码的预期行为正是您所看到的。
听起来您真正想要的是一个10秒的重复间隔,然后在每个间隔的2、5、6和7秒处发生一次事件。 您可以通过多种不同方式来实现。计时器最少的计时器使用四个重复计时器,以及四个非重复计时器在不同的时间启动它们:
void startTimers(
Duration repeat,List<Duration> offsets,void Function(Duration) callback) {
for (var e in offsets) {
Timer(e,() {
callback(e); // First call.
Timer.peridic(repeat,(_) => callback(e)); // More calls after that.
});
}
}
另一种选择是有一个重复计时器,然后为每个偏移量启动非重复计时器:
Timer startTimers(
Duration repeat,void Function(Duration) callback) {
void go(_) {
for (var e in offsets) Timer(e,() => callback(e));
}
go(null);
return Timer.periodic(repeat,go);
}
如果您需要再次停止计时器,那么我会采用后一种方法,并接受即使我尝试取消,本轮比赛也将完成。 (否则,您将需要一些更复杂的代码来保留所有计时器并取消它们)。