Hi, I'm trying to upgrade an old code to null safety, but since I'm just starting to learn null safety, I'm encountering errors and I couldn't figure out why, I would be glad if you could help.
I've tried a few things, but I'm leaving it in its original form so as not to confuse things further for you. source code: https://github.com/MarcusNg/flutter_instagram
auth_event
part of 'auth_bloc.dart';
abstract class AuthEvent extends Equatable {
const AuthEvent();
@override
bool get stringify => true;
@override
List<Object> get props => [];
}
class AuthUserChanged extends AuthEvent {
final auth.User user;
const AuthUserChanged({required this.user});
@override
List<Object> get props => [user];
}
class AuthLogoutRequested extends AuthEvent {}
auth_state
part of 'auth_bloc.dart';
enum AuthStatus { unknown, authenticated, unauthenticated }
class AuthState extends Equatable {
final auth.User user;
final AuthStatus status;
const AuthState({
this.user,
this.status = AuthStatus.unknown,
});
factory AuthState.unknown() => const AuthState();
factory AuthState.authenticated({required auth.User user}) {
return AuthState(user: user, status: AuthStatus.authenticated);
}
factory AuthState.unauthenticated() =>
const AuthState(status: AuthStatus.unauthenticated);
@override
bool get stringify => true;
@override
List<Object> get props => [user, status];
}
auth_bloc
part 'auth_event.dart';
part 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final AuthRepository _authRepository;
StreamSubscription<auth.User> _userSubscription;
AuthBloc({
required AuthRepository authRepository,
}) : _authRepository = authRepository,
super(AuthState.unknown()) {
_userSubscription =
_authRepository.user.listen((user) => add(AuthUserChanged(user: user)));
}
@override
Future<void> close() {
_userSubscription?.cancel();
return super.close();
}
@override
Stream<AuthState> mapEventToState(AuthEvent event) async* {
if (event is AuthUserChanged) {
yield* _mapAuthUserChangedToState(event);
} else if (event is AuthLogoutRequested) {
await _authRepository.logOut();
}
}
Stream<AuthState> _mapAuthUserChangedToState(AuthUserChanged event) async* {
yield event.user != null
? AuthState.authenticated(user: event.user)
: AuthState.unauthenticated();
}
}
Non-nullable instance field '_userSubscription' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
A value of type 'StreamSubscription<User?>' can't be assigned to a variable of type 'StreamSubscription'. Try changing the type of the variable, or casting the right-hand type to 'StreamSubscription'.
The argument type 'User?' can't be assigned to the parameter type 'User'. (_authRepository.user.listen((user) => add(AuthUserChanged(user: user)));)
The receiver can't be null, so the null-aware operator '?.' is unnecessary. Try replacing the operator '?.' with '.'. (_userSubscription?.cancel();)
The operand can't be null, so the condition is always true. Remove the condition. (event.user != null)
The parameter 'user' can't have a value of 'null' because of its type, but the implicit default value is 'null'. Try adding either an explicit non-'null' default value or the 'required' modifier. (this.user)
This error is happening because you have set your user
variable as non-nullable and final
. If you're new to nullsafety, to make the variable nullable, simply add a ?
at the end of the type. There's two different routes to fix this one:
user
is never ever going to be null, then simply do this:const AuthState({
required this.user,
this.status = AuthStatus.unknown,
});
required
tells the compiler "hey, this variable can never be set to null".
user
could be null, then do final auth.User? user;
. The ?
tells the compiler "hey, this variable can potentially be null`.However in your case you must go with option 2 because of this code:
factory AuthState.unauthenticated() =>
const AuthState(status: AuthStatus.unauthenticated);
Since you don't pass user
in the constructor you have to tell Dart that the variable can be null.
Non-nullable instance field '_userSubscription' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
Add the late
identifier here: late StreamSubscription<auth.User> _userSubscription;
. This tells Dart that yes, the variable won't ever be null, I am just not setting it when I define it. I will set it to a non-null value before it gets used elsewhere.
A value of type 'StreamSubscription<User?>' can't be assigned to a variable of type 'StreamSubscription'. Try changing the type of the variable, or casting the right-hand type to 'StreamSubscription'.
Dart has stricter type checking now due to nullsafety, so for this one I think you need to change this line: StreamSubscription<auth.User> _userSubscription;
into StreamSubscription<auth.User?> _userSubscription;
(don't forget to add late
like I mentioned earlier).
The argument type 'User?' can't be assigned to the parameter type 'User'. (_authRepository.user.listen((user) => add(AuthUserChanged(user: user)));)
In AuthUserChanged
, you made auth.User user
required
. In that line of code, you are assigning a nullable variable to a non-nullable variable. So you have to change the class to look like this:
class AuthUserChanged extends AuthEvent {
final auth.User? user;
const AuthUserChanged({this.user});
@override
List<Object> get props => [user];
}
The receiver can't be null, so the null-aware operator '?.' is unnecessary. Try replacing the operator '?.' with '.'. (_userSubscription?.cancel();)
This is just a warning, all you have to do is make _userSubscription?.cancel();
into _userSubscription.cancel();
. The warning is just letting you know that _userSubscription
will never be null so you don't need to check if it is null using the ?
operator.
The operand can't be null, so the condition is always true. Remove the condition. (event.user != null)
Same thing as the previous condition. Just a warning, all you have to do is remove that line of code because it is unnecessary.
Hope this helps you! I'd suggest looking at Dart's documentation for nullsafety to get a better idea of how all the new operators and keywords work.