I try to get List from jsonPlaceHolder using flutter rxdart stream and try to apply bloc pattern on it.
this class that response for get post response from api
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/post_item.dart';
class ItemApi {
Future<List<JsonItem>> getPost() async {
String _url = 'https://jsonplaceholder.typicode.com/posts';
final _response = await http.get(_url);
if (_response.statusCode == 200) {
return (json.decode(_response.body) as List)
.map((jsonItem) => JsonItem.fromJson(jsonItem))
.toList();
}
}
}
I using repository class to wrap using ItemApi class
import 'json_item_request.dart';
import '../models/post_item.dart';
class Repository{
final jsonItemResponse = ItemApi();
Future<List<JsonItem>> getItem() => jsonItemResponse.getPost();
}
at the last i using bloc class that response for get data and set it inside PublishSubject
import '../models/post_item.dart';
import '../resouces/repository.dart';
import 'package:rxdart/rxdart.dart';
class JsonBloc {
final _repository = Repository();
final _streamOfJsonList = PublishSubject<List<JsonItem>>();
Observable<List<JsonItem>> get jsonList=> _streamOfJsonList.stream;
fetchAllPost() async{
Future<List<JsonItem>> list = _repository.getItem();
}
dispose(){
_streamOfJsonList.close();
}
}
My question is how i can set response inside _streamOfJsonList variable to using it when list changed.
Sounds like you already have all the moving parts connected? If so you just need to add the item list to the PublishSubject:
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
_streamOfJsonList.add(list);
}
This will trigger the onListen callback with the new list on anything that is listening to the stream.
You can add error and data to ReplaySubject like below :
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
if (list != null) {
_streamOfJsonList.sink.add(list);
} else {
_streamOfJsonList.addError("ERROR");
}
}
Related
this is mycode .please solve this problem
import 'dart:convert' as convert;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:internetconnectivityusingbloc/repos/user_model.dart';
class UserRepositories {
Future<void> getUsers() async {
List<UserData>? userData = [];
String urlEndPoint = "https://reqres.in/api/users?page=2";
// Await the http get response, then decode the json-formatted response.
Response response = await http.get(Uri.parse(urlEndPoint));
if (response.statusCode == 200) {
userData = [];
// final List result = jsonDecode(response.body);
return userData.addAll(UserModel.fromjson(response.body));
} else {
throw Exception(response.reasonPhrase);
// print('Request failed with status: ${response.statusCode}.');
}
}
}
i am trying to solve this problem .but i am failed.so i expecting u are solve this problem
Add [] inside addAll:
return userData.addAll([UserModel.fromjson(response.body)]);
If you are only adding one model is better to only use the method add.
Howerver you are trying to add a type UserModel to a list of UserData and that might throw another error if UserModel is not a child of UserData. So if you are expecting to fill the variable userData you should use UserData.fromjson(response.body) to fill the new data, so you should adjust UserData parameters to get the data that response.body will bring.
I have a flutter 3.0.5 getx(get: 4.6.5) controller defined like this:
import 'package:get/get.dart';
import '../../../common/repo.dart';
import '../../../models/Channel.dart';
import '../../../models/Item.dart';
import '../../../models/enumn/stories_type.dart';
import '../../../models/request/article/article_request.dart';
class ChannelDetailController extends GetxController {
var channel = Channel().obs;
int isFav = 0;
StoriesType? currentStoriesType;
ArticleRequest? articleRequest;
RxList<Item> articles = List<Item>.empty(growable: true).obs;
void updateChannelFav(int isFav) {
channel.value.isFav = isFav;
update();
}
Future<void> getChannelArticles(int channelId) async {
Channel? channelResponse = await Repo.fetchChannelItem(channelId);
if (channelResponse != null) {
channel.value = channelResponse;
if (channelResponse.articleDTOList != null) {
articles.value = channelResponse.articleDTOList!;
}
update();
}
}
}
when I invoke the updateChannelFav function, I found that the controller articles will be cleared. why did this happen? does the controller resetted when update?
I'm learing test writing with mockito but i have some problems with testing remote_data_source_class.
Here's my abstract class
abstract class ApiRemoteDataSource {
Future<PokemonsListResponseModel> getPokemons();
}
Here's the implementation
import 'dart:convert';
import 'package:injectable/injectable.dart';
import 'package:http/http.dart' as http;
import '../../models/pokemons_list_response_model.dart';
import 'api_remote_data_source.dart';
#Injectable(as: ApiRemoteDataSource)
class ApiRemoteDataSourceImpl implements ApiRemoteDataSource {
ApiRemoteDataSourceImpl(this.client);
final http.Client client;
final pokemonListUrl = Uri.parse('https://pokeapi.co/api/v2/pokemon');
#override
Future<PokemonsListResponseModel> getPokemons() async {
final response = await client.get(pokemonListUrl);
final data = response.body;
final modelData = PokemonsListResponseModel.fromJson(json.decode(data));
return modelData;
}
}
Now Iwant to verify that when i invoke method .getPokemons() on mock data source my http.Client will execute a call to given endpoint:
#GenerateMocks([http.Client, ApiRemoteDataSource])
void main() {
late ApiRemoteDataSource dataSource;
late MockClient mockHttpClient;
setUp(() async {
await configureDependencies();
mockHttpClient = MockClient();
dataSource = MockApiRemoteDataSource();
print('test: $mockHttpClient, data source $dataSource');
});
group('getPokemonsList', () {
test('Should perform a GET request on a URL', () async {
final url = Uri.parse('https://pokeapi.co/api/v2/pokemon');
// arrange
when(mockHttpClient.get(url, headers: anyNamed('headers')))
.thenAnswer((_) async => http.Response(fixture('pokemon_list.json'), 200));
// act
dataSource.getPokemons();
// assert
verify(mockHttpClient.get(Uri.parse('https://pokeapi.co/api/v2/pokemon')));
});
});
}
Running test above gives me this error: "MissingStubError: 'getPokemons'
No stub was found which matches the arguments of this method call:
getPokemons()"
When i replace dataSource.getPokemons() in //act part with "mockHttpClient.get(url)" everything works but I'm not sure if that kind of test is valid
I have the following code that does not work:
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
main(){
String firstTitle = "";
firstTitle = logic().then((list) => getFirstTitle(list)); // I want to store this data into the variable
// firstTitle for later use.
// However my IDE does not recognize the second firstTitle as being linked to the declaration String firstTitle.
}
class MyList {
static var list = [1];
}
logic() async{
final result = await http.get('https://invidio.us/api/v1/search?q=tech+lead');
final data = json.decode(result.body);
final myList = [];
data.forEach((e) {
myList.add({"title": e['title'], 'videoId': e['videoId'], 'duration': e['lengthSeconds'], "date": e['publishedText']});
//print(myList);
});
return myList;
}
String getFirstTitle(aList){
return aList[0]["title"];
}
I understand that we await for the data to be fetched from the source but once it is how can I keep as any variable ex: String instead of having it as a Future.
UPDATE: To better illustrate the problem with the IDE.
Use async await.
main() async {
String firstTitle = "";
List list=[];
list=await logic();
firstTitle = getFirstTitle(list));
}
I have 3 .dart files: The Model, the API Call and the view. View call to the service to retrieve data, like this.
Model
class MapData {
String calle;
String pais;
String poblacion;
String postal;
String provincia;
MapData({
this.calle,
this.pais,
this.poblacion,
this.postal,
this.provincia,
});
factory MapData.fromJson(Map<String, dynamic> json) => new MapData(
calle: json["results"][0]['address_components'][1]["long_name"],
pais: json["results"][0]['address_components'][5]["long_name"],
poblacion: json["results"][0]['address_components'][2]["long_name"],
postal: json["results"][0]['address_components'][6]["long_name"],
provincia: json["results"][0]['address_components'][3]["long_name"],
);
}
Service
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:datameter/models/mapData_model.dart';
class DatameterService {
static Future<MapData> getMapData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final response = await http
.get(
'https://maps.google.com/maps/api/geocode/json?latlng=' +
"43.321146" +
',' +
"-3.008724" +
'&key=KEY",
)
.catchError((error) {
print(error.toString());
});
var responseJson = json.decode(response.body);
if (responseJson != null) {
final responseJson = json.decode(response.body);
return MapData.fromJson(responseJson);
}
return null;
}
}
Main view
void initState() {
print(DatameterService.getMapData()); //This doesn´t work
super.initState();
}
The problem: I don´t know how can i get the data.
So: What is the rigth way to get api call data?
You are trying to print a future!
Maybe try this:
void initState() {
DatameterService.getMapData().then((map){
print(map);
});
super.initState();
}
In the initstate you cannot await for future to complete but you can do something when it completes with the keyword "then".