flutter memory leak my widget in homescreen - flutter

this is the error cause when I return to home screen. Is there any way to solve this? I tried dispose my timer but it did not work
bool containerClicked = false;
int nextSpinValue = 0;
int? widgetIndex = 0;
var spinController = StreamController<int>.broadcast();
void spin() => spinController.add(++nextSpinValue)
#override
void initState() {
Redirects.drawerList();
super.initState();
}
#override
void dispose() {
_timer!.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
var mHeight = MediaQuery.of(context).size.height;
var mWidth = MediaQuery.of(context).size.width;
final _formKey = GlobalKey<FormState>();
var spinController = StreamController<int>.broadcast();
int nextSpinValue = 0;
void spin() => spinController.add(++nextSpinValue);
Timer.periodic(const Duration(seconds: 3), (timer) async {
if (nextSpinValue >= 3) {
nextSpinValue = 0;
}
spin();
});
caused somewhere in setstate

The problem happens due to the fact that StreamController has to be closed. Otherwise, StreamController object stays in the memory even if the widget getting stream events no longer exists. dispose() is a good place to call the close method.
AFAIK it's a property of Flutter Controllers. You have to close them.

Related

How to add continuously change color of container in flutter between RGB values

I want to create an animation where the container changes colors just the LED lights do in real life.
I this would be automatic so I dont want any 'onPressed()' working classes
I tried doing it through 'Timer' and 'AnimatedContainer()' but the timer only responds to initState value i.e. 0
Either help me setState the state of Container after every second or give me some another solution.
This is my code currently
late Timer timer;
int start = 0;
void startTimer() {
const oneSec = Duration(seconds: 1);
timer = Timer.periodic(
oneSec,
(Timer timer) {
setState(() {
start++;
});`your text`
},
);
}
#override
void initState() {
super.initState();
startTimer();
setState(() {
_changeColor();
});
}
_changeColor() {
setState(() {
if (start % 3 == 0) {
changingColor = Colors.green;
} else if (start % 3 == 1) {
changingColor = Colors.blue;
} else if (start % 3 == 2) {
changingColor = Colors.red;
}
});
}
Use setState for start won't call _changeColor, so you have to call _changeColor inside Timer.
class LEDWidget extends StatefulWidget {
const LEDWidget({super.key});
#override
State<LEDWidget> createState() => _LEDWidgetState();
}
class _LEDWidgetState extends State<LEDWidget> {
Color changingColor = Colors.green;
int start = 0;
late Timer timer;
#override
void dispose() {
timer.cancel();
super.dispose();
}
#override
void initState() {
super.initState();
timer = Timer.periodic(const Duration(seconds: 1), (_) {
start++;
_changeColor();
});
}
_changeColor() {
setState(() {
if (start % 3 == 0) {
changingColor = Colors.green;
} else if (start % 3 == 1) {
changingColor = Colors.blue;
} else if (start % 3 == 2) {
changingColor = Colors.red;
}
});
}
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(seconds: 1),
color: changingColor,
);
}
}

How to detect device rotation (orientation change) in flutter?

My app has a draggable floating action button that could move everywhere on the screen and stay at that position when being dropped.
The code for the button is from a blogspot and not mine.
The problem is, since everything is set in portrait mode, and there is no detection when rotation occurs, the button could be unreachable when device rotates from portrait mode to landscape mode (if the button was previously on the bottom half of the screen in portrait mode).
Is there anyway to detect previous orientation in order to set the offset for the button again when it rotates?
Here is the code for the floating button class/widget
import 'package:flutter/material.dart';
class DraggableFloatingActionButton extends StatefulWidget {
final Widget child;
final double deviceWidth;
final double deviceHeight;
final Function onPressed;
final GlobalKey parentKey;
DraggableFloatingActionButton({
required this.child,
required this.deviceWidth,
required this.deviceHeight,
required this.onPressed,
required this.parentKey,
});
#override
State<StatefulWidget> createState() => _DraggableFloatingActionButtonState();
}
class _DraggableFloatingActionButtonState extends State<DraggableFloatingActionButton> {
final GlobalKey _key = GlobalKey();
bool _isDragging = false;
late Offset _offset;
late Offset _minOffset;
late Offset _maxOffset;
#override
void initState() {
_offset = Offset(widget.deviceWidth * 0.8, widget.deviceHeight * 0.75);
WidgetsBinding.instance.addPostFrameCallback(_setBoundary);
super.initState();
}
void _setBoundary(_) {
final RenderBox parentRenderBox =
widget.parentKey.currentContext?.findRenderObject() as RenderBox;
final RenderBox renderBox = _key.currentContext?.findRenderObject() as RenderBox;
try {
final Size parentSize = parentRenderBox.size;
final Size size = renderBox.size;
setState(() {
_minOffset = const Offset(0, 0);
_maxOffset = Offset(parentSize.width - size.width, parentSize.height - size.height);
});
} catch (e) {
print('catch: $e');
}
}
void _updatePosition(PointerMoveEvent pointerMoveEvent) {
double newOffsetX = _offset.dx + pointerMoveEvent.delta.dx;
double newOffsetY = _offset.dy + pointerMoveEvent.delta.dy;
if (newOffsetX < _minOffset.dx) {
newOffsetX = _minOffset.dx;
} else if (newOffsetX > _maxOffset.dx) {
newOffsetX = _maxOffset.dx;
}
if (newOffsetY < _minOffset.dy) {
newOffsetY = _minOffset.dy;
} else if (newOffsetY > _maxOffset.dy) {
newOffsetY = _maxOffset.dy;
}
setState(() {
_offset = Offset(newOffsetX, newOffsetY);
});
}
#override
Widget build(BuildContext context) {
return Positioned(
left: _offset.dx,
top: _offset.dy,
child: Listener(
onPointerMove: (PointerMoveEvent pointerMoveEvent) {
_updatePosition(pointerMoveEvent);
setState(() {
_isDragging = true;
});
},
onPointerUp: (PointerUpEvent pointerUpEvent) {
print('onPointerUp');
if (_isDragging) {
setState(() {
_isDragging = false;
});
} else {
widget.onPressed();
}
},
child: Container(
key: _key,
child: widget.child,
),
),
);
}
}
As you can see, it only sets the button's offset based on portrait mode once in initState function, and doesn't deal with rotation.
A walk around that I could think of at this moment is just having another floating button specifically set for landscape mode.
Thank you in advance for any answer.
Ok, so I still don't know how to detect rotation, but my walk around works.
All I do is create another class(widget) for a landscape floating button.
In main, check device orientation to use either the floating button portrait class or landscape class.
The only thing that I change in the landscape button class is
from
_offset = Offset(widget.deviceWidth * 0.8, widget.deviceHeight * 0.75);
to
_offset = Offset(widget.deviceHeight * 1.75, widget.deviceWidth * 0.3);
You shouldn't care about orientation. You should use something like LayoutBuilder to determine your space available, and make breakpoint decisions based on that. LayoutBuilder will update immediately if the device space changes, and you should react to that by doing another layout.

How to implement Audioplayers with audioservice in flutter? using offline playlist

I want to make an audio app in flutter Having audioplayers and audioservice package in flutter.
how to implement them please help me.
here is my code:
class _PlayerScreenState extends State
with SingleTickerProviderStateMixing, Observer {
_PlayerScreenState(
#required this.songArray, this.songIndex, this.songArrayFiles);
var songArray = [];
var songArrayFiles = [];
var songIndex = 0;
var autoplay = "Autoplay On";
double volume = 1;
bool playing = false;
Duration _duration = const Duration();
Duration _position = const Duration();
late AudioPlayer advancedPlayer;
late AudioCache audioCache;
late AnimationController _controller;
final Color color = HexColor.fromHex('#F30C4E');
//INIT STATE;
#override
void initState() {
super.initState();
initPlayer();
}
autoplaysong() {
advancedPlayer.stop();
songIndex = songIndex;
playSongs(songArray[songIndex]);
}
void initPlayer() {
advancedPlayer = AudioPlayer();
audioCache = AudioCache(fixedPlayer: advancedPlayer);
advancedPlayer.onDurationChanged.listen(
(d) => setState(() => _duration = d),
);
advancedPlayer.onPlayerCompletion.listen((event) {
if (autoplay == "Autoplay On") {
autoplaysong();
} else {
nextsong();
}
});
advancedPlayer.onAudioPositionChanged
.listen((p) => setState(() => _position = p));
playSongs(songArray[songIndex]);
}

Center to user location google maps initializer error

I am trying to set a center loading point whenever user enters the app. I am getting the errow with initializer. Not sure how to fix this.
The instance member 'StartingLocation' can't be accessed in an initializer.
class _GmapState extends State<Gmap> {
Location location = new Location();
GoogleMapController? mapController;
late Future<Map> futureAdventures;
var StartingLocation;
var _initialCameraPosition = CameraPosition(target:
LatLng(StartingLocation.latitude, StartingLocation.longitude),
zoom: 15);
#override
void initState() {
super.initState();
var pos = location.getLocation();
StartingLocation = pos;
}
Tried this as well
var pos;
#override
void initState() {
super.initState();
setState(() {
pos = _location.getLocation();
pos = _StartingLocation;
_initialCameraPosition = CameraPosition(target:
LatLng(_StartingLocation.latitude, _StartingLocation.longitude),
zoom: 15);
});

Flutter Timer.periodic register/run once

i would like to have a Timer runing once in main.dart to check user activity
#override
void initState() {
super.initState();
initPlatformState();
_fetchMasterData("a", "b");
_startActivityTimer();
}
bool _activityTimerRunning = false;
void _startActivityTimer() {
if (!_activityTimerRunning) {
Timer.periodic(Duration(seconds: 5), (timer) {
_timerTicked(timer);
setState(() {
_activityTimerRunning = true;
});
print("Timer started");
});
}
}
But initState gets called more than once, so it is not the right place to register the timer. Where should it be placed?
The code in the question has i silly mistake, the print statement is in the wrong place. Here is the working code:
#override
void initState() {
super.initState();
initPlatformState();
_fetchMasterData("a", "b");
_startActivityTimer();
}
void _startActivityTimer() {
print("Timer started");
Timer.periodic(Duration(seconds: 5), (timer) {
_timerTicked(timer);
});
}
"TimerStarted" get executed only once
Try this sample code.
int start = 5;
fName(){
Timer _timer;
const oneSecond = Duration(seconds: 5);
_timer = Timer.periodic(
oneSecond,
(Timer timer) => setState((){
if(start == 0)
timer.cancel();
else{
_activityTimerRunning = true;
start -= 1;
}
})
);
}
When you want to start you timer, call fName() method, after that timer can started. So and also you can check condition, when
if(start != 0){
...
}