(Flutter) Upgrading To NullSafety

Issue

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];
}
  • 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)

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)


Solution

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:

  1. If you know that 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".

  1. If 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.

Answered By – Tanay Neotia

Answer Checked By – Marie Seifert (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *