这是我第一次写(不专业技术文,请大家多多包涵),希望大家会喜欢。可以留言问我问题,或是给我一点写技术文件的意见。我有看到都会回复呦~
|-- lib
|-- bloc // bloc 资料夹
|-- restaurant_bloc.bloc.dart
|-- restaurant_bloc.event.dart
|-- restaurant_bloc.state.dart
|-- data // 用来装 respository、model
|-- model
|-- api_result_model.dart
|-- respository
|-- restaurant_respository.dart
|-- res
|-- string
|-- strings.dart
|-- ui
|-- pages
|-- about_page.dart
|-- home_page.dart
|-- main.dart
{
"success" : true,
"message" : "SUCCESS",
"data" : [ {
"id" : 0,
"name" : "八方云集沙鹿静宜店",
"description" : "营业时间:10:00 – 21:00\n中午不外送",
"phone" : "0426321128",
"address" : "台中市沙鹿区英才路17号",
"lowest_price" : 300
}, {
"id" : 1,
"name" : "伟哥咸酥鸡台中静宜店",
"description" : "营业时间:15:30 – 12:15\n没有提供外送服务",
"phone" : "0423809838",
"address" : "台中市沙鹿区北势东路517之1号",
"lowest_price" : 0
} ]
}
我是使用 http 的套件来串接 API。
官网介绍
另外一种也是很多人用的 API 串接方式。(当然还有很多,在这边不一一介绍)。
Dio
我是使用 quicktype 来帮我自动转成我要的物件。
Bloc 分成 3 部分,Event Bloc State
就是当你要取得资料====> 事件。
当你与画面进行互动====> 事件。
取得资料中 => 状态
取资料成功 => 状态
取资料失败 => 状态
去做判断
如果这个事件 = 取得资料 那就属於什麽状态
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Api-Get',
home: BlocProvider(
create: (context) => RestaurantBloc(restaurantRepository: RestaurantRepository()),
child: HomePage(),
),
);
}
}
abstract class RestaurantEvent extends Equatable{
@override
List<Object> get props =>[];
}
class FetchRestaurantEvent extends RestaurantEvent {}
abstract class RestaurantState extends Equatable {
@override
List<Object> get props => [];
}
class RestaurantLoadingState extends RestaurantState {
}
class RestaurantSuccessState extends RestaurantState {
final RestaurantModel restaurantModel;
RestaurantSuccessState({@required this.restaurantModel});
@override
// TODO: implement props
List<Object> get props => [restaurantModel];
}
class RestaurantFailState extends RestaurantState {
final String message;
RestaurantFailState({@required this.message});
@override
// TODO: implement props
List<Object> get props => [message];
}
class RestaurantBloc extends Bloc<RestaurantEvent, RestaurantState> {
RestaurantRepository restaurantRepository;
RestaurantBloc({@required this.restaurantRepository}) : super(RestaurantLoadingState());
RestaurantState get initialState => RestaurantLoadingState();
@override
Stream<RestaurantState> mapEventToState(RestaurantEvent event) async* {
if (event is FetchRestaurantEvent) {
yield RestaurantLoadingState();
try {
RestaurantModel restaurantModel = await restaurantRepository.getRestaurantData();
print("Bloc Success");
yield RestaurantSuccessState(restaurantModel: restaurantModel);
} catch (e) {
print( await restaurantRepository.getRestaurantData());
yield RestaurantFailState(message: "???");
}
}
}
}
class RestaurantRepository {
Future<RestaurantModel> getRestaurantData() async {
final response = await http.get(AppStrings.cricArticleUrl);
if (response.statusCode == 200) {
List<int> bytes = response.body.toString().codeUnits;
var responseString = utf8.decode(bytes);
return RestaurantModel.fromJson(jsonDecode(responseString));
} else {
print("EEEE");
throw Exception();
}
}
}
这部分请参考 quicktype 转成物件。
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
RestaurantBloc _restaurantBloc;
Size size;
@override
void initState() {
super.initState();
_restaurantBloc = BlocProvider.of<RestaurantBloc>(context);
_restaurantBloc.add(FetchRestaurantEvent());
}
@override
Widget build(BuildContext context) {
size = MediaQuery.of(context).size;
return MaterialApp(
home: Builder(
builder: (context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: Text("Api-Get"),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
_restaurantBloc.add(FetchRestaurantEvent());
},
),
IconButton(
icon: Icon(Icons.info),
onPressed: () {
navigateToAboutPage(context);
},
)
],
),
body: Container(
child: BlocListener<RestaurantBloc, RestaurantState>(
listener: (context, state) {
if (state is RestaurantFailState) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
),
);
}
},
child: BlocBuilder<RestaurantBloc, RestaurantState>(
builder: (context, state) {
if (state is RestaurantLoadingState) {
return _buildLoading();
} else if (state is RestaurantSuccessState) {
return buildArticleList(state.restaurantModel);
} else if (state is RestaurantFailState) {
return _buildErrorUi(state.message);
}
return Container();
},
),
),
),
),
);
},
),
);
}
Widget _buildLoading() {
return Center(
child: CircularProgressIndicator(),
);
}
Widget _buildErrorUi(String message) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
message,
style: TextStyle(color: Colors.red),
),
),
);
}
Widget buildArticleList(RestaurantModel restaurantModel) {
return Container(
child: new ListView.builder(
padding: EdgeInsets.only(top: 30),
itemCount: restaurantModel.data.length,
itemBuilder: (context, int index) =>
buildCustomItem(context, index, restaurantModel.data),
));
}
void navigateToAboutPage(BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return AboutPage();
}));
}
/// 餐厅 listView 的 Item 画面
Widget buildCustomItem(BuildContext context, int index, List<Datum> data) {
return Container(
padding:
EdgeInsets.only(left: size.width * 0.1, right: size.width * 0.1),
// height: 500,
width: size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Container(
// height: size.height * 0.3,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.all(Radius.circular(25.0))),
// child: Image.network(RestaurantList[index].storeLink),
// // child: _ImgaeNetWorkStyle(RestaurantList[index].storeLink)
// ),
Padding(
padding: EdgeInsets.only(top: 16, right: 8.0, left: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
data[index].name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.cyan[700]),
),
Text(
"最低\$" + data[index].lowestPrice.toString() + "外送",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.cyan[700]),
),
],
),
),
Padding(
padding: EdgeInsets.all(8),
child: Text(data[index].description,
style: TextStyle(fontSize: 15, color: Colors.cyan[700])),
),
Padding(
padding: EdgeInsets.only(bottom: 16, right: 8.0, left: 8.0),
child: Text(data[index].address,
style: TextStyle(fontSize: 15, color: Colors.cyan[700])),
),
],
));
}
}
class AboutPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("About"),
),
body: Container(
alignment: Alignment.center,
child: Text("Developer : [email protected]"),
),
);
}
}
这是以上我写 Flutter 并使用 Bloc 来串接 API 的实际例子。
这是我的 Github 开源码 Flutter-Api-Get-Bloc 可以参考这里。
<<: 如何在 SSMS 查寻资料库的复原模式 - 心得分享
>>: SEO:关於 Custom Campaign Tracking
风险评监首步曲:资讯资产盘点 标题没打错呦...建立资安制度前,请先确认自已的资安范围有多大。 实务...
怎麽选取到元素改变网页原有外观呢?本篇主要整理CSS选取器分类及CSS优先权 切版学习途中,你是否...
在 Ruby 内有符号(Symbol)这个物件,他跟字串的用法蛮像的,但本质上则不一样。 究竟 Sy...
「食神归位!」,从天上传来一个声音,「你本来是掌管烧菜的神仙,因触犯天条,而被罚落凡间受三十六劫、七...
一个大包的专案程序码解压缩後看着满满的程序码思考着我可以实现计画案的目标吗...。接下来这三天会将专...