Null check operator used on a null value- futter chat - flutter

I'm creating a chat app with sending voice message. now I'm getting this error in my code. appreciate your help on this. I HAVE INSERTED FOLLOWING CODE ANS THEN ERROR APPEARS. Cant find a exact file error occurring.
Null check operator used on a null value
class SoundRecorder {
FlutterSoundRecorder? _audioRecorder;
bool _isRecorderInitialised = false;
bool get isRecording => _audioRecorder!.isRecording;
Future init() async {
_audioRecorder = FlutterSoundRecorder();
await _audioRecorder?.openAudioSession(); //start recording
//asking permisson
final status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
throw RecordingPermissionException("Microphone permission");
}
await _audioRecorder!.openAudioSession();
_isRecorderInitialised = true;
}
void dispose() {
if (!_isRecorderInitialised) return;
_audioRecorder!.closeAudioSession();
_audioRecorder = null;
_isRecorderInitialised = false;
}
Future _record() async {
if (!_isRecorderInitialised) return;
await _audioRecorder!.startRecorder(toFile: pathToSaveAudio);
}
Future _stop() async {
if (!_isRecorderInitialised) return;
await _audioRecorder!.stopRecorder();
}
Future toggleRecording() async {
if (_audioRecorder!.isStopped) {
await _record();
} else {
await _stop();
}
}
}

Looks like at some point you use the ! operator to assert that _audioRecorder isn't null but it actually is. From the stack, I think this would be from the isRecording getter.
A simple fix to this would be to make the getter bool get isRecording => _audioRecorder?.isRecording ?? false, since if _audioRecorder is null, then you can't be recording, right?

Related

how to create a stream in flutter that return a bool in every second

i am making a app. And i want to check my server state every minite and give user information
about the server. How do i do it. is stream good for it. Can some provide me a code for that.
just follow this guide
suppose your bool return value function is
Future<bool> isGpsOn() async {
return await Geolocator().isLocationServiceEnabled();
}
and this is create stream from bool value
Stream futureToStream(fn, defaultValue, Duration duration) async* {
var result;
while (true) {
try {
result = await fn();
}
catch (error) {
result = defaultValue;
}
finally {
yield result;
}
await Future.delayed(duration);
}
}
final gpsStatusStream = futureToStream(isGpsOn, false, Duration(seconds: 5));
gpsStatusStream.listen((enabled) {
print(enabled ? 'enabled' : 'disabled');
});
Use asyncMap
Stream<String> checkConnectionStream() async* {
yield* Stream.periodic(Duration(seconds: 1), (_) {
return //your function
}).asyncMap((event) async => await event);
}

How to return catch exception in flutter

I working on error handling of api's. i want if api is crashed then it display a message of "Server is down" something like this, in UI.
I created a class where i'm creating methods of api, here in getBooks method if i modify the api url then it is printing this Exception, and i want it in UI. The problem is getBooks return type is List<Book>> so we can't return this Exception, any solution how to do this?
Exception
E/flutter (12924): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Exception
here is my api code
class BooksApi {
static Future<List<Book>> getBooks(String query) async {
try {
final url = Uri.parse(
'https://gist.githubusercontent.com/JohannesMilke/d53fbbe9a1b7e7ca2645db13b995dc6f/raw/eace0e20f86cdde3352b2d92f699b6e9dedd8c70/books.json');
final response = await http.get(url);
if (response.statusCode == 200) {
final List books = json.decode(response.body);
return books.map((json) => Book.fromJson(json)).where((book) {
final titleLower = book.title.toLowerCase();
final authorLower = book.author.toLowerCase();
final searchLower = query.toLowerCase();
return titleLower.contains(searchLower) ||
authorLower.contains(searchLower);
}).toList();
} else {
throw Exception;
}
} catch (e) {
print("e");
print(e);
}
throw Exception;
}
}
and calling it like
Future init() async {
setState(() {
isLoading = true;
});
var books = await BooksApi.getBooks(query); //this
var response = await obj.getProduct();
print(response);
setState(() => this.books = books);
setState(() {
isLoading = false;
});
}
You could handle errors with then and onError :
await BooksApi.getBooks(query).then((books) async {
setState(() => {
this.books = books;
this.isLoading = false;
})
}, onError: (error) {
// do something with error
});
or a simple try-catch (you can write try-catch clauses the same way you would in synchronous code).
See handling errors.
You can also use catchError id you don't use async/await :
BooksApi.getBooks(query).then((books) {
setState(() => {
this.books = books;
this.isLoading = false;
})
}).catchError((error, stackTrace) {
print("error is: $error");
});
See futures error handling.
Try to wrap 'var books = await BooksApi.getBooks(query)' with try and catch.
...
try {
var books = await BooksApi.getBooks(query);
} catch (e) {
// To do for UI
}
...
For api, you need to make something like this:
APIModel{
final int code;
// or a success flag
// final bool success;
final String message;
final List<Book> data;
APIModel({this.code,this.message,this.data});
}
It means, every api have its own code,message,and data filed.
When you request, you can check your code or success:
var response = await request(params);
isLoading = false;
if(response.code == 0){}
// or
if(response.success){
// do what you want
}
else {
Toast.show(response.message);
}
You can use build_runner and json_serializable.

dart future method with bool return type always returns false

I am calling class method which is in a different file from the main method of main.dart. Here I am trying to get the session status of the user. I am not sure what I am doing wrong, the return value always returns false when called in from the main method, but returns true if printed out in the actual method.
Here the expected result is true as the user is currently in the system and is signed in.
Here is my main method -
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await Authenticate().getSessionStatus().then((status) => {
print(status)
});
}
Here is my class method -
class Authenticate {
Future<bool> getSessionStatus() async {
bool _isSessionActive = false;
await FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user == null) {
//print('User is currently signed out!');
_isSessionActive = false;
} else {
//print('User is signed in!');
_isSessionActive = true;
}
});
return _isSessionActive;
}
}
The print statements inside the Authenticate class method, if turned on returns true which is the expected value, but calling the getSessionStatus method from the main method and then printing the value of the status variable always returns false. I believe it has something to do with order in which it is processed, but I am not able to fix it at all.
You can't check if the user is logged with FirebaseAuth.instance.authStateChanges(), since this method only notifies when the user status changes.
You can use the FirebaseAuth.instance.currentUser property instead:
class Authenticate {
Future<bool> getSessionStatus() async {
return FirebaseAuth.instance?.currentUser != null;
}
}
You cannot await the StreamSubscription (which the compiler should warn you about) returned by FirebaseAuth.instance.authStateChanges().listen(...). Below is a minimal example to illustrate what is happening.
void main() async {
bool test = await awaitMe();
print('Main received:' + test.toString());
}
Future<bool> awaitMe() async {
bool innerVal = false;
print('start');
await streamMe().listen((val) {
print('Listener received: ' + val.toString());
innerVal = true;
});
print('end');
return innerVal;
}
Stream<bool> streamMe () async* {
yield true;
}
This will print:
start
end
Main received:false
Listener received: true
So you are actually not awaiting anything.

Display Loading spinner waitint for request to complete while using provider package

I am using a provider package. I want to display a loading spinner while waiting for a request to complete. The pattern below is too verbose. Please help me make it less verbose. Here is my code
class APIService with ChangeNotifier {
// Check for working API backend
bool isWorking = false;
bool isLoading = false;
set _isLoading(bool value) {
isLoading = value; <--
notifyListeners();
}
Future<bool> selectAPI(String input) async {
_isLoading = true; <-- 1
final uri = Uri.tryParse('https://$input$url')!;
final response = await http.get(uri);
if (response.statusCode == 200) {
final body = jsonDecode(response.body) as Map<String, dynamic>;
bool isTrue = body['info']['title'] == 'SamFetch';
_isLoading = false; <-- 2
notifyListeners();
return isWorking = isTrue;
}
_isLoading = false; <-- 3
throw response;
}
}
Here is my UI code
IconButton(
icon: apiService.isLoading
? CircularProgressIndicator()
: Icon(Icons.done),
onPressed: () async {
await addAPI(apiService, cache);
}),
}
Below is addAPI() method
Future<void> addAPI(APIService apiService, Cache cache) async {
if (api != null) {
try {
await apiService.selectAPI(api!);
if (apiService.isWorking) {
await cache.saveAppName(api!);
}
} on SocketException catch (e) {
print(e);
} catch (e) {
await cache.clearCache();
}
}
}
Is setState the final solution?
You can use Future Builder and set your Future Function in future attribute. You can control the visible widget based on the status of your function. So you dont have to use isloading variable.

How to return a bool value from aync/await function and pass it to other variable in other page

I want check if device is connected to internet or not and i done with class that do this work and return to me a bool value and i use from this class to other page and pass returned value to bool variable but get get this error that say Future<dynamic> is not a subtype of type bool in type cast
import 'dart:io';
class CheckConnection{
static Future<bool> checkConnection() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return (await checkConnection()) == true;
}
} on SocketException catch (_) {
print('not connected');
}
}
}
In place where you want to check you have to do like this:
CheckConnection.checkConnection().then((bool result){
/* check result here */
})
Or you can do this inside async function like checkConnection:
void _myFunction() async {
bool result = await CheckConnection.checkConnection();
/* check result here */
}
I don't get why you call checkConnection again inside for it (recursive effect). Are you sure you don't want to do like:
class CheckConnection {
static Future<bool> checkConnection() async {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
/* try catch also can be applied! */
return false;
}
}
Just return this
return await checkConnection();