前言
基于之前的新版本发布version已经支持开始支持了Web开发者开发,那这个编程语言的前景已经不言而喻了,不仅仅是一门跨双端的编程语言,更是可能成为未来的主流语言之一。当前这句话说的有点绝对,但是和React Native这一类语言不同的地方偶尔可能也是显而易见的,基于的底层框架的修改,前者基于的是JS的一种扩展。所以接下来就是对这个编程语言的一种学习了。
另外本文应该会呈现4-5天的持续性更新,基于的后台将是泓洋大神的wanandroid,有兴趣的读者都可以学习一下。
Flutter中文网,安装步骤及基础使用等都已经在这份文档里了。
逃不过的安装
材料清单:
1. 操作系统:OSX 10.15.3
2. Flutter版本:flutter_macos_v1.12.13+hotfix.7-stable
3. 软件:Android Studio
我一顿猛如虎的操作下来基本是没有问题的,不过Gtihub
上拉,确实有点慢,可以直接下载稳定版玩儿。
项目的源码将集成在WanAndroid-Flutter中,因为项目是android官网推出的,所以直接讲解。
使用
通过以上的这些基础内容,我们基本上就可以开始初级的开发了。
见于对整个开发代码的审阅,我们将基于Flutter Inspector
对整体的代码进行观察。
开发
- 网络部分
见于官方文档中同样建议我们使用dio
进行网络请求,所以整体的网络请求及数据解析将依靠json_serializable
+dio
。
创建类似如下模版:
@JsonSerializable()
class User{
User(this.name, this.email);
String name;
String email;
//不同的类使用不同的mixin即可
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
编码完成以后,运行命令行flutter packages pub run build_runner build
,就会自动生成.g.dart
文件就可以进行使用了。
因为没有类似于Java
的反射机制,所以格式化的过程一般会比较麻烦,当然也可以去搜索解析的框架。
另外在源码中,因为书写方式是鉴于wanandroid
一个开放的项目,已经比较符合规范,所以可以选择直接誊写。
另外因为数据的原因,其实我还是直接建议调用这个demo已经做好的数据。
项目结构
|-- libs
|-- api (Api接口)
|-- common (公共类)
|-- fonts (字体类)
|-- model (Bean类)
|-- pages (UI页面)
|-- util (工具类)
|-- widget (自定义组件)
单个模块分析
因为页面的逻辑基本一致,其实我们只用分析单个页面,就能完全理解整体代码的逻辑了。
这里主讲的是一个project
也就项目页。
抛出显示效果,其实整体的框架就是一个TabBar
、RefreshIndicator
还有Card
的组合其实进入以后也能很清楚的发现。在界面上出现了一些叉叉的符号,那是因为我的删减程序中并没有加入字体库。
apkLink: ,
author: Mstian,
chapterId: 402,
chapterName: 跨平台应用,
collect: false,
courseId: 13,
desc: 使用前端跨端框架开发一款安卓版本的玩安卓App,具体实现了登录注册, 体系, 公众号, 项目列表功能, 还有导航功能, 收藏文章项目功能等。 还使用了高德地图api实现机主定位功能。,
envelopePic: https: //www.wanandroid.com/blogimgs/aeb17245-d43c-4ad3-ac35-aae45096aef8.png,
fresh: false,
id: 10726,
link: https://www.wanandroid.com/blog/show/2714,
niceDate: 2019-12-06 16:02,
origin: ,
projectLink: https://github.com/Mstian/wanAndroid,
publishTime: 1575619327000,
superChapterId: 294,
superChapterName: 开源项目主Tab,
tags: [Instance of 'ArticleTagModel'],
title: 前端框架uniapp版玩安卓客户端,
type: 0,
userId: -1,
visible: 1,
zan: 0
这份json
数据其实就是抓取来的数据之一,他所对应的就是Card
,也就是我们所看到的卡片,对应的就是ArticleItemPage.dart
。
而我们看到的列表的呈现、下拉刷新、上拉加载也只是一个ListView
和RefreshIndicator
的结合使用,下面使用到源码中的一段进行验证。
代码位于ArticleListPage.dart
中
listView = ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
itemCount: itemCount,
controller: getControllerForListView(),
itemBuilder: (context, index) {
if (index == 0 && null != widget.header) {
// 当数据为0,并且存在头部时,就返回头部
return widget.header;
} else if (index - (null == widget.header ? 0 : 1) >=
_listData.length) {
// 如果出现index大于数据长度,就出现加载更多
return _buildLoadMoreItem();
} else {
// 正常范围状态下,就构建Item
return _buildListViewItemLayout(
context, index - (null == widget.header ? 0 : 1));
}
});
var body = NotificationListener<ScrollNotification>(
onNotification: onScrollNotification,
child: RefreshIndicator(
child: listView,
color: GlobalConfig.colorPrimary,
onRefresh: handleRefresh,
),
);
这里其实也就是我所说的那一系列代码的核心了,中间还有一些分页的功能以及缓存的工作,可以详见ProjectPage.dart
中的下述代码
因为这部分代码和
ArticleListPage.dart
的耦合,所以放在一起讲。
Widget _buildSinglePage(ProjectClassifyItemModel bean) {
return ArticleListPage(
keepAlive: _keepAlive(),
request: (page) {
return CommonService().getProjectListData((bean.url == null)
? ("${Api.PROJECT_LIST}$page/json?cid=${bean.id}")
: ("${bean.url}$page/json"));
},
);
}
bool _keepAlive() {
if (_cachedPageNum < _maxCachePageNums) {
_cachedPageNum++;
return true;
} else {
return false;
}
}
在这个dart
文件中,存在一个网络请求和缓存数,缓存就是通过上述的一个_keepAlive()
的函数进行操作的。
网络请求
网络请求部分其实才是整个项目的重点。
笔主将原有的模式,进行了一定的修改,从设计模式上来讲就是单例模式中的恶汉式,从java
以及我个人的角度来讲,因为网络请求是一个一定会被使用到的变量,通过饿汉式的创建方法,其实也是对性能的一种优化。
先调用一份dio
的使用方法。
在这个项目中,我们频繁的会看到类似如下代码
CommonService().getProjectListData((bean.url == null)
? ("${Api.PROJECT_LIST}$page/json?cid=${bean.id}")
: ("${bean.url}$page/json"))
这其实是写代码的人对这个网络请求的一个封装。
而为了通过拿到真实数据我们的一般操作模版如下代码所示
dio.get(Api.PROJECT_CLASSIFY, options: _getOptions()).then((response) {
callback(ProjectClassifyModel.fromJson(response.data));
});
其实原理很简单,我们还记得自己创造的bean
吗?通过调用他的fromJson()
函数,我们就能得到了相对的数据实体了。
让我们在看下Dio
中的Reponse
。
{
/// Response body. may have been transformed, please refer to [ResponseType].
T data;
/// Response headers.
Headers headers;
/// The corresponding request info.
Options request;
/// Http status code.
int statusCode;
/// Whether redirect
bool isRedirect;
/// redirect info
List<RedirectInfo> redirects ;
/// Returns the final real request uri (maybe redirect).
Uri realUri;
/// Custom field that you can retrieve it later in `then`.
Map<String, dynamic> extra;
}
这个类中的变量很多,不过因为data中保存的是服务器传回来的数据,所以我们也就知道了为什么一般调用是data
这个变量了。
另外还有一个点就是我们经常在网络请求中看到的两个关键词async
和await
,这两个变量就是为了让我们进行异步处理,知道ANR机制的读者们,想来也就清楚了异步处理的重要性了。
另外这个项目因为是类似于组件化的开发,不过最近几年组件化开发兴起,确实有着它难以想象的好处,不论是复用机制,还是节省开发成本,他都带来了难以想象的好处,所以这个开发模式还是很建议学习的。
以上就是我的学习成果,如果有什么我没有思考到的地方或是文章内存在错误,欢迎与我分享。
相关文章推荐:
Flutter的性能优化