The argument type 'List<HospitalListModel>?' can't be assigned to the parameter type 'HospitalListModel' - flutter

i have bloc class and it throw an error with a message The argument type 'List<HospitalListModel>?' can't be assigned to the parameter type 'HospitalListModel'.
this is the bloc class:
class HospitalListBloc extends Bloc<HospitalListEvent, HospitalListState> {
HospitalListBloc() : super(HospitalListInitial()) {
final ApiRepository _apiRepository = ApiRepository();
on<GetCovidList>((event, emit) async {
try {
emit(HospitalListLoading());
final mList = await _apiRepository.fetchHospitalList();
emit(HospitalListLoaded(mList));
} on NetworkError {
emit(HospitalListError("Failed to fetch data. is your device online?"));
}
});
}
}
and the error is on emit(HospitalListLoaded(mList));, and in case if you want to know the API provider:
class ApiProvider {
final Dio _dio = Dio();
final String _url = 'http://lovemonster.my.id/hospital';
Future<List<HospitalListModel>?> fetchHospitalList() async {
try {
Response response = await _dio.get(_url);
return hospitalListModelFromJson(response.data);
} catch (error, stacktrace) {
print("Exception occurred: $error stackTrace: $stacktrace");
return Future.error("");
}
}
}

your HospitalListLoaded function should be
HospitalListLoaded(List<HospitalListModel> mList)

The argument type 'List<HospitalListModel>?' can't be assigned to the parameter type 'HospitalListModel'.
Your HospitalListLoaded function is declared as this:
void HospitalListLoaded(HospitalListModel model){
....
}
Here the parameter type is a single HospitalListModel, not a list of them. So, you can either pass a single HospitalListModel or you can change the parameter type to List<HospitalListModel>. In that case, you must change your logic inside that function.
Plus, notice the ? null operator. If the List you pass can be null, then the parameter type must be nullable. In that case,
void HospitalListLoaded(List<HospitalListModel>? models){
....
}

You are returning an Object of HospitalListModel but your Bloc class having method which accept list of HospitalListModel
You need to return list not an object
Check below code which will be useful
class ApiProvider {
final Dio _dio = Dio();
final String _url = 'http://lovemonster.my.id/hospital';
Future<List<HospitalListModel>?> fetchHospitalList() async {
try {
List<HospitalListModel> hospitalList = [];
Response response = await _dio.get(_url);
var mData = responseData.data as List;
hospitalList = mData.
.map<HospitalListModel?>((e) => hospitalListModelFromJson(e)
.toList();
return hospitalList;//return List not object
} catch (error, stacktrace) {
print("Exception occurred: $error stackTrace: $stacktrace");
return Future.error("");
}
}
}

Related

Flutter unit test: type 'Null' is not a subtype of type 'T' in type cast

I tried to run unit test but i found an issue like below:
type 'Null' is not a subtype of type 'LoginResponse' in type cast
dart:async new Future.value
test/mock_utils.mocks.dart 259:22 MockBaseRepository.call
package:swap_recycling/features/auth/data/repository/login/login_repository_impl.dart 33:42 LoginRepositoryImpl.login
test/features/auth/data/repository/login/login_repository_impl_test.dart 30:38
and these my codes:
test.dart
void main() {
late MockLoginApiService _mockLoginApiService;
late MockSecureStorage _mockSecureStorage;
late MockBaseRepository _mockBaseRepository;
setUp(() {
_mockLoginApiService = MockLoginApiService();
_mockSecureStorage = MockSecureStorage();
_mockBaseRepository = MockBaseRepository();
});
test('Given LoginRepository When login Then return loginResponseSuccess',
() async {
final _repository = LoginRepositoryImpl(
_mockLoginApiService,
_mockSecureStorage,
_mockBaseRepository,
);
final result = await _repository.login(loginRequest);
expect(result, loginResponseSuccess);
verify(_mockLoginApiService.login(loginRequest)).called(1);
});
Login_repository.dart
final loginRepositoryProvider = Provider<LoginRepository>((ref) {
final loginApiService = ref.watch(provideLoginApiService);
final secureStorage = ref.watch(secureStorageProvider);
final baseRepository = ref.watch(baseRepositoryProvider);
return LoginRepositoryImpl(loginApiService, secureStorage, baseRepository);
});
class LoginRepositoryImpl extends LoginRepository {
final LoginApiService _loginApiService;
final SecureStorage _secureStorage;
final BaseRepository _baseRepository;
LoginRepositoryImpl(
this._loginApiService,
this._secureStorage,
this._baseRepository,
);
#override
Future<LoginResponse> login(LoginRequest request) async {
final result = await _baseRepository.call<LoginResponse>(
() => _loginApiService.login(request),
);
return result;
}
base_repository.dart
final baseRepositoryProvider = Provider<BaseRepository>((ref) {
return BaseRepository();
});
class BaseRepository {
Future<T> call<T>(FutureOr<T> Function() call) async {
try {
return await call();
} on DioError catch (e) {
if (e.error is SocketException) {
throw Failure(message: e.message);
}
if (e.response?.statusCode == serverErrorCode) {
throw Failure(
message: 'Server has some issue, please try again',
code: e.response?.statusCode,
);
}
throw Failure(
message: e.response?.statusMessage ?? 'Something went wrong',
code: e.response?.statusCode,
exception: e,
);
}
}
}
I tried to create a reuse function to return HTTP calls or handle errors.
I set generic type and send LoginResponse to tell BaseRepository that I want to return LoginResponse.
I can run it on an emulator but it doesn't work in a unit test.
Why It returns Null type?
I used mockito to generate mock class
mocks.dart
#GenerateNiceMocks([
//Repository
MockSpec<LoginRepository>(),
MockSpec<SettingRepository>(),
//Service
MockSpec<LoginApiService>(),
MockSpec<SecureStorage>(),
//Base
MockSpec<BaseRepository>(),
MockSpec<LoginRepositoryImpl>(),
])

Value of type 'Resource<dynamic>' can't be returned as T where T extends Resource

Here's my program (you can run it as a dart file):
/// Fetches data from TestRepository and shows result
main () async {
final repository = TestRepository();
final resource = await repository.fetchString();
if (resource.isError) {
print("| Error: ${resource.error}");
} else {
print("| Success: ${resource.data}");
}
}
/// A class to get Success or Error responses
class Resource<S> {
final S? _data;
final String? _message;
Resource.success(S data)
: _data = data,
_message = null;
Resource.error(String message)
: _data = null,
_message = message;
bool get isError => _message != null;
S get data => _data!;
String get error => _message!;
}
/// A sample repository class to use API and handle errors
class TestRepository {
Future<Resource<String>> fetchString() {
return _dummyApiCall().useErrorHandler();
}
/// Dummy API Call mimicking
Future<Resource<String>> _dummyApiCall() async {
await Future.delayed(const Duration(seconds: 1));
if (true) {
// to mimic an exception so that we can catch it
throw Exception("Error Occurred");
}
return Resource.success("Hello World");
}
}
/// An extension to wrap Resource Futures with error handler
extension FutureResourceExt<T extends Resource> on Future<T> {
Future<T> useErrorHandler() {
return onError((error, stacktrace) => handleError(error));
}
}
/// A function to handle errors thrown by Future.onError
T handleError<T extends Resource>(dynamic error) {
return Resource.error("Error: $error");
}
I have a code error on following line:
return Resource.error("Error: $error");
The error says:
A value of type 'Resource<dynamic>' can't be returned from the function 'handleError' because it has a return type of 'T'
If I change the implementation to add as T to above statement, code error disappears and gets thrown on runtime.
Unhandled Exception: type 'Resource<dynamic>' is not a subtype of type 'Resource<SomeDataType>' in type cast
I don't know why can I not assign Resource to T extends Resource return type.
How should I implement Resource class such that I can do this without knowing S type of Resource?
Here's the line with error code:
return Resource.error("Error: $error");
Here's the solution:
return Resource<Never>.error("Error: $error") as T;
I received a hint from this nice answer. Never knew something like Never existed.

Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast

Objective is to convert a String to List using map and return the value to a function call.
I am using SharedPreferences to save a list of object called where in I save the data at a point and get the data when it is to be put on view.
The below block is the function where the error is occurring.
void getData() async {
final prefs = await SharedPreferences.getInstance();
final String taskString = prefs.getString('task_data').toString();
List<Task> tasksData = Task.decode(taskString);
_tasks = tasksData;
notifyListeners();
}
decode() looks basically does the conversion.
static List<Task> decode(String tasks) {
return (jsonDecode(tasks) as List<dynamic>).map<Task>((task) {
return Task.fromJson(task);
}).toList();
It advises to check for null condition in type cast of decode(). But on performing the check, it gives the same error.
your response might be not a proper map so it cannot decode that data using the jsonDecode function so it returns Null, so you can use your function like this might be helpful for you :
static List<Task> decode(String tasks) {
var data = (jsonDecode(tasks) as List<dynamic>?);
if(data != null){
return (jsonDecode(tasks) as List<dynamic>?)!.map<Task>((task) {
return Task.fromJson(task);
}).toList();
} else {
return <Task>[];
}
}

Try replacing the reference to the instance member with a different expression

I am using Riverpod to fetch Api and display in the app, and my method , "getMovieList()" requires a String, but in the below code I am getting this Error :
"The instance member 'pageNumber' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expressiondartimplicit_this_reference_in_initializer"
class StateManager {
final String pageNumber;
StateManager(this.pageNumber);
static final movieStateFuture = FutureProvider<List<Movie>>((ref) async {
return ApiSetup.getMovieList(pageNumber); // The error is Here "The instance member 'pageNumber' can't be accessed in an initializer."
});
}
class ApiSetup {
static List<Movie> parsePhotos(String responseBody) {
List<Movie> listMovies = [];
for (var mov in jsonDecode(responseBody)['results']) {
final movie = Movie.fromJson(mov);
listMovies.add(movie);
}
return listMovies;
}
static Future<List<Movie>> getMovieList(String pageNum) async {
final response = await http.get(Uri.parse(
"https://api.themoviedb.org/3/movie/now_playing?api_key=${Constants.apiKey}&language=en-US&page=$pageNum"));
if (response.statusCode == 200) {
return compute(parsePhotos, response.body);
} else {
print("Error here");
}
throw Exception("Some Random Error");
}
}
You can not refer a non static member from inside a static method. Your pageNumber is an attribute that belongs to the instance/object of StateManager whereas static methods belongs to the class.
If you want to use pageNumber while accessing the future try using family provider instead:
static final movieStateFuture = FutureProvider.family<List<Movie>,int>( //<-- Add '.family' modifer and 'datatype' of the argument
(ref, pageNum) async { //<-- Second argument to create method is the parameter you pass
return ApiSetup.getMovieList(pageNum);
}
);
Now while calling movieStateFuture, pass in the argument like this:
watch(movieStateFuture(/*PAGE_NUMBER_HERE*/));

dartz: exception in function is not caught in attempt

I am using dartz with flutter. I want to use Either type with all API calls as suggested in this article
Below is the way I have wrapped API to Task
Future<Either<ApiException, SendOtpDto>> receiveOtp(
String phoneNumber) async {
return Task<SendOtpDto>(() async {
final String url = 'AuthenticationApi/sendOtp/$phoneNumber';
final Map<String, dynamic> response = await apiWrapper.get(url);
final SendOtpDto dto = SendOtpDto.fromJson(response);
if (!dto.success) {
throw ServerErrorException(dto.error); //Exception is thrown here
}
return dto;
}).attempt().mapLeftToFailure().run();
}
I expect attempt() should catch all throw as ApiException. Currently it gives error type 'Future<Either<ApiException, dynamic>>' is not a subtype of type 'FutureOr<Either<ApiException,
SendOtpDto>>
Below is how I am using the Api
if (event is GetOtpButtonPressed) {
yield LoginApiLoading();
final Either<ApiException, SendOtpDto> result = await apiManager.authentication(context).receiveOtp(event.username);
yield result.fold<LoginState>(
(ApiException exception) { return LoginFailure(error: exception.toString()); },
(SendOtpDto dto) { return LoginOtpSent(dto: dto); });
}