1 通用库
(1) Entity
/// 新闻分页 response
class NewsPageListResponseEntity {
int? counts;
int? pagesize;
int? pages;
int? page;
List<NewsItem>? items;
NewsPageListResponseEntity({
this.counts,
this.pagesize,
this.pages,
this.page,
this.items,
});
factory NewsPageListResponseEntity.fromJson(Map<String, dynamic> json) =>
NewsPageListResponseEntity(
counts: json["counts"],
pagesize: json["pagesize"],
pages: json["pages"],
page: json["page"],
items:
List<NewsItem>.from(json["items"].map((x) => NewsItem.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"counts": counts,
"pagesize": pagesize,
"pages": pages,
"page": page,
"items": items != null
? List<dynamic>.from(items!.map((x) => x.toJson()))
: [],
};
}
class NewsItem {
String id;
String title;
String category;
String thumbnail;
String author;
DateTime addtime;
String url;
NewsItem({
required this.id,
required this.title,
required this.category,
required this.thumbnail,
required this.author,
required this.addtime,
required this.url,
});
factory NewsItem.fromJson(Map<String, dynamic> json) => NewsItem(
id: json["id"],
title: json["title"],
category: json["category"],
thumbnail: json["thumbnail"],
author: json["author"],
addtime: DateTime.parse(json["addtime"]),
url: json["url"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"category": category,
"thumbnail": thumbnail,
"author": author,
"addtime": addtime.toIso8601String(),
"url": url,
};
}
/// 新闻推荐 request
class NewsRecommendRequestEntity {
String categoryCode;
String channelCode;
String tag;
String keyword;
NewsRecommendRequestEntity({
required this.categoryCode,
required this.channelCode,
required this.tag,
required this.keyword,
});
Map<String, dynamic> toJson() => {
"categoryCode": categoryCode,
"channelCode": channelCode,
"tag": tag,
"keyword": keyword,
};
}
(2) BaseProvider
继承自GetConnect
class BaseProvider extends GetConnect {
static const SERVER_API_URL = "101.42.134.18:8000";
@override
void onInit() {
httpClient.baseUrl = SERVER_API_URL;
// 请求拦截
httpClient.addRequestModifier<void>((request) {
request.headers['token'] = '12345678';
return request;
});
// 响应拦截
httpClient.addResponseModifier((request, response) {
return response;
});
}
}
2 法一(最麻烦)
- Provider 提供者模式, 由它决定从哪里、提供什么
- Repository 用来处理拉取数据细节
- Controller 控制器层 只要处理业务就行
(1) Provider
import 'package:fltest/common/utils/base_provider.dart';
import 'package:get/get.dart';
abstract class INewsProvider {
Future<Response<NewsPageListResponseEntity>> getNews();
}
class NewsProvider extends BaseProvider implements INewsProvider {
// 新闻分页
// @override
// Future<Response<NewsPageListResponseEntity>> getNews() => get("/news");
@override
Future<Response<NewsPageListResponseEntity>> getNews() async {
var response = await get("/news");
var data = NewsPageListResponseEntity.fromJson(response.body);
return Response(
statusCode: response.statusCode,
statusText: response.statusText,
body: data,
);
}
}
(2) Repository
import 'package:fltest/pages/get_connect/provider.dart';
abstract class INewsRepository {
Future<NewsPageListResponseEntity> getNews();
}
class NewsRepository implements INewsRepository {
NewsRepository({required this.provider});
final INewsProvider provider;
@override
Future<NewsPageListResponseEntity> getNews() async {
final response = await provider.getNews();
if (response.status.hasError) {
return Future.error(response.statusText!);
} else {
return response.body!;
}
}
}
(3) Controller
class NewsController extends SuperController<NewsPageListResponseEntity> {
NewsController({required this.repository});
final INewsRepository repository;
@override
void onInit() {
super.onInit();
}
// 拉取新闻列表
Future<void> getNewsPageList() async {
append(() => repository.getNews);
}
@override
void onReady() {
print('The build method is done. '
'Your controller is ready to call dialogs and snackbars');
super.onReady();
}
@override
void onClose() {
print('onClose called');
super.onClose();
}
@override
void didChangeMetrics() {
print('the window size did change');
super.didChangeMetrics();
}
@override
void didChangePlatformBrightness() {
print('platform change ThemeMode');
super.didChangePlatformBrightness();
}
@override
Future<bool> didPushRoute(String route) {
print('the route $route will be open');
return super.didPushRoute(route);
}
@override
Future<bool> didPopRoute() {
print('the current route will be closed');
return super.didPopRoute();
}
@override
void onDetached() {
print('onDetached called');
}
@override
void onInactive() {
print('onInative called');
}
@override
void onPaused() {
print('onPaused called');
}
@override
void onResumed() {
print('onResumed called');
}
}
(4) GetView
class NewsView extends GetView<NewsController> {
NewsView({Key? key}) : super(key: key);
_buildListView(NewsPageListResponseEntity? state) {
return ListView.separated(
itemCount: state != null ? state.items!.length : 0,
itemBuilder: (context, index) {
final NewsItem item = state!.items![index];
return ListTile(
onTap: () => null,
title: Text(item.title),
trailing: Text("分类 ${item.category}"),
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("GetConnect Page"),
),
body: controller.obx(
(state) => _buildListView(state),
onEmpty: Text("onEmpty"),
onLoading: Center(
child: Column(
children: [
Text("没有数据"),
ElevatedButton(
onPressed: () {
controller.getNewsPageList();
},
child: Text('拉取数据'),
),
],
),
),
onError: (err) => Text("onEmpty" + err.toString()),
),
);
}
}
(5) Bindings
class NewsBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<INewsProvider>(() => NewsProvider());
Get.lazyPut<INewsRepository>(() => NewsRepository(provider: Get.find()));
Get.lazyPut(() => NewsController(repository: Get.find()));
}
}
(6) Route
GetPage(
name: AppRoutes.GetConnect,
binding: NewsBinding(),
page: () => NewsView(),
),
3 法二(适中)
使用StateMixin可以节省一些代码, 不用写Repository
(1) provider
import 'package:fltest/common/utils/base_provider.dart';
import 'package:get/get.dart';
abstract class INewsProvider {
Future<Response> getNews();
}
class NewsStateMixinProvider extends BaseProvider implements INewsProvider {
@override
Future<Response> getNews() => get("/news");
}
(2) controller
class NewsStateMixinController extends GetxController
with StateMixin<NewsPageListResponseEntity> {
final NewsStateMixinProvider provider;
NewsStateMixinController({required this.provider});
// 拉取新闻列表
Future<void> getNewsPageList() async {
// 获取数据
final Response response = await provider.getNews();
// 判断,如果有错误
if (response.hasError) {
// 改变数据,传入错误状态,在ui中会处理这些错误
change(null, status: RxStatus.error(response.statusText));
} else {
// 否则,存储数据,改变状态为成功
var data = NewsPageListResponseEntity.fromJson(response.body);
change(data, status: RxStatus.success());
}
}
}
3 法三(最简单)
(1) http
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
const SERVER_API_URL = "101.42.134.18:8000";
class HttpUtil {
static final HttpUtil _instance = HttpUtil._internal();
factory HttpUtil() => _instance;
late Dio dio;
HttpUtil._internal() {
// BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
BaseOptions options = BaseOptions(
// 请求基地址,可以包含子路径
baseUrl: SERVER_API_URL,
// baseUrl: storage.read(key: STORAGE_KEY_APIURL) ?? SERVICE_API_BASEURL,
//连接服务器超时时间,单位是毫秒.
connectTimeout: 10000,
// 响应流上前后两次接受到数据的间隔,单位为毫秒。
receiveTimeout: 5000,
// Http请求头.
headers: {},
// 请求的Content-Type,默认值是"application/json; charset=utf-8".
// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
// 可以设置此选项为 `Headers.formUrlEncodedContentType`, 这样[Dio]
// 就会自动编码请求体.
contentType: 'application/json; charset=utf-8',
// [responseType] 表示期望以那种格式(方式)接受响应数据。
// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.
//
// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。
// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.
//
// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.
responseType: ResponseType.json,
);
dio = Dio(options);
// Cookie管理
CookieJar cookieJar = CookieJar();
dio.interceptors.add(CookieManager(cookieJar));
}
// restful get 操作
Future get(
String path, {
dynamic queryParameters,
Options? options,
}) async {
var response = await dio.get(
path,
queryParameters: queryParameters,
options: options,
);
return response.data;
}
}
(2) api
/// 新闻
class NewsAPI {
/// 翻页
static Future<NewsPageListResponseEntity> newsPageList(
{NewsRecommendRequestEntity? param}) async {
var response = await HttpUtil().get(
'/news',
queryParameters: param?.toJson(),
);
return NewsPageListResponseEntity.fromJson(response);
}
}
(3) controller
class NewsDioController extends GetxController {
var newsPageList =
Rx<NewsPageListResponseEntity>(NewsPageListResponseEntity());
@override
void onInit() {
super.onInit();
print("onInit");
}
@override
void onClose() {
super.onClose();
print("onClose");
}
getPageList() async {
newsPageList.value = await NewsAPI.newsPageList();
}
}