Closed osehmathias closed 10 months ago
Thanks for the report.
Can you confirm it occurs when disposing AudioRecorder
without calling any method before (start, stop, or anything else)?
Fixed in v5.0.3.
@llfbandit - thanks! Impressed with your package and speed of support.
However, the problem is still ongoing.
This is the error now:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(record, Recorder has not yet been created or has already been disposed., null, null)
#0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:651:7)
#1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:322:18)
<asynchronous suspension>
#2 RecordMethodChannel.dispose (package:record_platform_interface/src/record_method_channel.dart:112:5)
<asynchronous suspension>
#3 AudioRecorder.dispose (package:record/src/record.dart:167:5)
<asynchronous suspension>
Thanks for your reactivity. v5.0.4 has been released. Better testing than assuming... 😞
Beautiful! This is working now! Thank you @llfbandit
Shoot me a link if you have a buy me a coffee or one of those things :)
I'll never provide such links ! (Also, I'm trying to avoid coffee now😄) Kind and supportive community is more than enough to me.
Legend
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:record/record.dart' as record_pkg;
import '../../../../utils/constants/app_colors.dart';
import '../../../../utils/constants/app_text_styles.dart';
import '../../../../utils/extensions/duration_extension.dart';
import '../../../../widgets/buttons/app_circular_button.dart';
import '../../cubits/recording/recording_cubit.dart';
class AudioRecorder extends StatefulWidget {
const AudioRecorder({super.key});
@override
State<AudioRecorder> createState() => _AudioRecorderState();
}
class _AudioRecorderState extends State<AudioRecorder> {
final _record = record_pkg.AudioRecorder();
Duration _duration = Duration.zero;
Timer? _timer;
Timer? _volumeTimer;
double _volume = 0.0;
final double _minVolume = -45.0;
bool _isRecording = false;
@override
void dispose() {
_record.dispose();
super.dispose();
}
@override
void initState() {
_record.onStateChanged().listen(
(state) {
if (!mounted) return;
switch (state) {
case record_pkg.RecordState.stop:
_stopTimer();
setState(() => _duration = Duration.zero);
case record_pkg.RecordState.pause:
_stopTimer();
context
.read<RecordingCubit>()
.record(status: RecordingStatus.paused);
case record_pkg.RecordState.record:
_startTimer();
context
.read<RecordingCubit>()
.record(status: RecordingStatus.played);
}
},
);
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<RecordingCubit, RecordingState>(
builder: (context, recordingState) {
final status = recordingState.status;
final isStatusInitializedOrRemoved =
status == RecordingStatus.initialized ||
status == RecordingStatus.removed;
return isStatusInitializedOrRemoved
? _renderCircularRedStartRecordButton(context, status)
: _renderRecordingTimeAndButtons(context, status);
},
);
}
void _updateVolume() async {
final ampl = await _record.getAmplitude();
if (ampl.current > _minVolume) {
setState(() {
_volume = (ampl.current - _minVolume) / _minVolume;
});
print('VOLUME: $_volume');
}
}
int volume0to(int maxVolumeToDisplay) {
// Invert the volume calculation to start from 100.
return ((1 - _volume) * maxVolumeToDisplay).round().abs();
}
void _handleTrashRecording(BuildContext context) async {
context.read<RecordingCubit>().record(status: RecordingStatus.removed);
await _record.cancel();
_stopTimer();
}
void _handlePlayOrPauseRecording(BuildContext context) async {
if (_isRecording) {
await _record.pause();
_stopTimer();
setState(() {
_isRecording = false;
});
return;
}
await _record.resume();
_startTimer();
_isRecording = true;
}
void _handleFinishRecording(BuildContext context) async {
final path = await _record.stop();
if (!context.mounted) return;
context
.read<RecordingCubit>()
.record(status: RecordingStatus.finished, path: path);
}
void _startTimer() {
_timer?.cancel();
_timer = Timer.periodic(
const Duration(seconds: 1),
(timer) => setState(() {
_duration += const Duration(seconds: 1);
}),
);
_volumeTimer ??= Timer.periodic(
const Duration(milliseconds: 50), (timer) => _updateVolume());
}
void _stopTimer() {
_timer?.cancel();
_timer = null;
}
Column _renderCircularRedStartRecordButton(
BuildContext context,
RecordingStatus status,
) {
return Column(
children: [
Text(
_duration.formatAudioRecordTime,
style: AppTextStyles.title1.copyWith(
fontSize: 40,
),
),
const SizedBox(height: 16),
AppCircularButton(
onPressed: () async {
final appDocumentsDir = await getApplicationDocumentsDirectory();
final filePath = p.join(appDocumentsDir.path, 'recording.m4a');
if (await _record.hasPermission()) {
await _record.start(
const record_pkg.RecordConfig(),
path: filePath,
);
_startTimer();
setState(() {
_isRecording = true;
});
}
if (!context.mounted) return;
context
.read<RecordingCubit>()
.record(status: RecordingStatus.played);
},
size: 95,
child: const CircleAvatar(
radius: 100,
backgroundColor: AppColors.snackbarFailure,
),
),
],
);
}
Column _renderRecordingTimeAndButtons(
BuildContext context,
RecordingStatus status,
) {
return Column(
children: [
Text(
_duration.formatAudioRecordTime,
style: AppTextStyles.title1.copyWith(
fontSize: 40,
),
),
const SizedBox(height: 16),
//* Uncomment to see the voice animation in action.
Container(
height: volume0to(200).toDouble(),
width: volume0to(200).toDouble(),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.navixAccent.withOpacity(0.4)),
child: Center(child: Text(volume0to(100).toString())),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
AppCircularButton(
onPressed: () => _handleTrashRecording(context),
size: 70,
child: const Icon(
Icons.delete_rounded,
color: AppColors.snackbarFailure,
),
),
AppCircularButton(
onPressed: () => _handlePlayOrPauseRecording(context),
size: 95,
child: Icon(
_isRecording ? Icons.pause_rounded : Icons.play_arrow_rounded,
size: 50,
color: AppColors.navixText,
),
),
AppCircularButton(
onPressed: () => _handleFinishRecording(context),
size: 70,
child: const Icon(
Icons.check_rounded,
color: AppColors.lightGreen,
),
),
],
),
],
);
}
}
having same error :
PlatformException (PlatformException(record, Recorder has not yet been created or has already been disposed., null, null))
If I go back to previous page.
Package version 5.0.2
Environment
Describe the bug
I am using Record in a PageView widget where you can swipe back and forth to perform different actions.
Record throws this error consistently.
Add your record configuration
RecordConfig(...)
RecordConfig()
To Reproduce
Steps to reproduce the behavior:
Expected behavior
No errors in the terminal. Record has no late initialised variables being accessed.
Additional context
This is the code: