MVC、MVP、BloC,洞悉MySQL底层架构

}

到此,MVC整个框架的登录流程已进行完成。

MVP

该架构是在进行Android开发时,是一种比较常用的架构。

架构视图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

程序入口

main.dart是程序的入口,完成登录界面的启动,相关代码如下所示

void main() => runApp(MVPApp());

class MVPApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.black,
),
home: LoginPage(),
);
}
}

登录流程

MVC一致,可以参考MVC

文本监听

MVC一致,可以参考MVC

清空账号输入框

MVC一致,可以参考MVC

密码是否可见

MVC一致,可以参考MVC

触发登录

View层点击登录按钮,触发Presenter层登录逻辑,在Presenter层通过View层提供的接口来控制loading界面的展示和隐藏,loading UI相关代码如下所示

Offstage(
offstage: !isLoading,
child: new Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.black54,
child: new Center(
child: SpinKitCircle(
color: Theme.of(context).primaryColor,
size: 25.0,
),
),
),
),

上面代码中的isLoading状态已在基类中做了统一封装,下面对MVP做定义封装。

封装View层

触发网络请求,需要满足展示和隐藏loading界面,所以View的对外需要提供这两个最基本的接口,如下面代码所示

abstract class IBaseView {
showLoading();

hideLoading();
}

封装Presenter层

Presenter层的公共接口只需提供对View层的注册以及反注册,如下面代码所示

abstract class IBasePresenter {
void onAttachView(V view);

void onDetachView();
}

下面对Presenter层的代码实现上面所提供的接口,如下面代码所示

abstract class BasePresenter extends IBasePresenter {
V view;

@override
void onAttachView(IBaseView view) {
this.view = view;
}

@override
void onDetachView() {
this.view = null;
}
}

封装State基类

State基类中,需要提供Presenter的初始化的方法、loading状态、数据初始化以及视图的构建等,如下面代码所示

abstract class BaseState<T extends StatefulWidget, P extends BasePresenter,
V extends IBaseView> extends State implements IBaseView {
P presenter;

bool isLoading = false;

P initPresenter();

Widget buildBody(BuildContext context);

void initData() {
}

@override
void initState() {
super.initState();
presenter = initPresenter();
if (presenter != null) {
presenter.onAttachView(this);
}
initData();
}

@override
void dispose() {
super.dispose();
if (presenter != null) {
presenter.onDetachView();
presenter = null;
}
}

@override
@mustCallSuper
Widget build(BuildContext context) {
return new Scaffold(
body: buildBody(context),
);
}

@override
void showLoading() {
setState(() {
isLoading = true;
});
}

@override
void hideLoading() {
setState(() {
isLoading = false;
});
}
}

到此,MVP框架已经封装完,下面只需对登录界面做相应的实现即可。

实现登录逻辑

在进行登录时,Presenter层需要向View层提供登录接口,当进行登录完毕后,需要向View层进行登录状态的反馈,所以View需要提供登录成功、失败两个接口,如下面代码所示

abstract class ILoginPresenter extends BasePresenter {
void login(String name, String password);
}

abstract class ILoginView extends IBaseView {
void onLoginSuccess(UserBean userBean);

void onLoginFailed();
}

当相关接口定义完毕后,首先实现登录的Presenter层的代码,如下面代码所示

class LoginPresenter extends ILoginPresenter {
@override
void login(String name, String password) async {
if (view != null) {
view.showLoading();
}
final login = await LoginManager.instance.login(name, password);
//授权成功
if (login != null) {
final user = await LoginManager.instance.getMyUserInfo();
if (user != null) {
if (view != null) {
view.hideLoading();
view.onLoginSuccess(user);
} else {
view.hideLoading();
view.onLoginFailed();
}
}
} else {
if (view != null) {
view.hideLoading();
view.onLoginFailed();
}
}
}
}

然后对登录State的代码进行实现,如下面代码所示

class _LoginPageState extends BaseState<LoginPage, LoginPresenter, ILoginView>
implements ILoginView {

@override
void initData() {
super.initData();
}

@override
Widget buildBody(BuildContext context) {
return null;
}

@override
LoginPresenter initPresenter() {
return LoginPresenter();
}

@override
void onLoginSuccess(UserBean userBean) {
NavigatorUtil.goHome(context, userBean);
}

@override
void onLoginFailed() {
ToastUtil.showToast(‘登录失败,请重新登录’);
}
}

相关代码已经封装完毕,最后只需调用登录相关逻辑,如下面代码所示

_login() {
if (presenter != null) {
String name = _nameController.text;
String password = _passwordController.text;
presenter.login(name, password);
}
}

BloC

关于什么是BloC,可以参考[Flutter Package]状态管理之BLoC的封装Flutter | 状态管理探索篇——BLoC(三)

架构视图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

程序入口

main.dart是程序的入口,完成登录界面的启动,相关代码如下所示

void main() => runApp(BlocApp());

class BlocApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.black,
),
home: BlocProvider(
child: LoginPage(),
bloc: LoginBloc(),
),
);
}
}

上面代码跟MVCMVP有不同之处,传入home的对象是BlocProvider,且其包含了childbloc实例。如下面代码所示

class BlocProvider extends StatefulWidget {
final T bloc;
final Widget child;

BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}) : super(key: key);

@override
_BlocProviderState createState() {
return _BlocProviderState();
}

static T of(BuildContext context) {
final type = _typeOf<BlocProvider>();
BlocProvider provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}

static Type _typeOf() => T;
}

class _BlocProviderState extends State<BlocProvider> {
static final String TAG = “_BlocProviderState”;

@override
void initState() {
super.initState();
LogUtil.v('initState ’ + T.toString(), tag: TAG);
}

@override
Widget build(BuildContext context) {
LogUtil.v('build ’ + T.toString(), tag: TAG);
return widget.child;
}

@override
void dispose() {
super.dispose();
LogUtil.v('dispose ’ + T.toString(), tag: TAG);
widget.bloc.dispose();
}
}

登录流程

BLoC能够允许我们分离业务逻辑,不用考虑什么时候需要刷新屏幕,一切交给StreamBuilder和BLoC就可以完成,所以登录页面继承StatelessWidget即可。如下面代码所示

class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: bloc.stream,
initialData: initialData(),
builder: (BuildContext context,
AsyncSnapshot<LoadingBean> snapshot) {
}
);
}
}

  • stream代表了这个stream builder监听的流,这里监听的是LoginBloc的stream;
  • initData代表初始的值,因为在首次渲染的时候,还未与用户产生交互,也就不会有事件从流中流出,所以需要给首次渲染一个初始值;
  • builder函数接收一个位置参数BuildContext和一个snapshot,snapshot就是这个流输出的数据的一个快照,我们可以通过snapshot.data访问快照中的数据,StreamBuilder中的builder是一个AsyncWidgetBuilder,它能够异步构建widget,当检测到有数据从流中流出时,将会重新构建。
创建BloC

首先完成BloC基类的封装,基类需要只需要满足登录状态,如下面代码所示

class LoadingBean {
bool isLoading;
T data;

LoadingBean({this.isLoading, this.data});

@override
String toString() {
return ‘LoadingBean{isLoading: $isLoading, data: $data}’;
}
}

abstract class BaseBloc {
static final String TAG = “BaseBloc”;

BehaviorSubject _subject = BehaviorSubject();

Sink get sink => _subject.sink;

Stream get stream => _subject.stream;

void dispose() {
_subject.close();
sink.close();
}
}

创建BloC实例

在登录的BloC实例中,完成整个登录过程,我们需要监听账号、密码的输入状态,密码的是否可见状态,以及登录状态,如下面代码所示

class LoginBloc extends BaseBloc<LoadingBean> {
LoadingBean bean;

LoginBloc() {
bean = LoadingBean(
isLoading: false,
data: LoginBlocBean(
name: ‘’,
password: ‘’,
obscure: true,
),
);
}

changeObscure() {
}

changeName(String name) {
}

changePassword(String password) {
}

login(BuildContext context) async {
}

void _showLoading() {
bean.isLoading = true;
sink.add(bean);
}

void _hideLoading() {
bean.isLoading = false;
sink.add(bean);
}
}

文本监听

创建账号和密码两个TextEditingController实例,并完成其事件监听,如下面代码所示

final TextEditingController _nameController = new TextEditingController();
final TextEditingController _passwordController = new TextEditingController();

LoginBloc bloc = BlocProvider.of(context);

_nameController.addListener(() {
bloc.changeName(_nameController.text);
});
_passwordController.addListener(() {
bloc.changePassword(_passwordController.text);
});

当文本发生改变时,会调用LoginBloc里相应的改变方法,并对相应的文本进行重新复杂,在通过sink.add()更新界面,如下面代码所示

changeName(String name) {
bean.data.name = name;
sink.add(bean);
}

changePassword(String password) {
bean.data.password = password;
sink.add(bean);
}

清空账号输入框

MVC一致,可以参考MVC

密码是否可见

需要改变可见状态,调用LoginBloc中的changeObscure方法,如下面代码所示

changeObscure() {
bean.data.obscure = !bean.data.obscure;
sink.add(bean);
}

触发登录

需要进行网络请求,控制loading的展示和隐藏,这里需要调用LoginBloc中的login方法,当登录成功后,则跳转主页展示基本信息,不成功则toast提示,如下面代码所示

login(BuildContext context) async {
_showLoading();

final login =
await LoginManager.instance.login(bean.data.name, bean.data.password);
//授权成功
if (login != null) {
final user = await LoginManager.instance.getMyUserInfo();
if (user != null) {
NavigatorUtil.goHome(context, user);
} else {
ToastUtil.showToast(‘登录失败,请重新登录’);
}
} else {
ToastUtil.showToast(‘登录失败,请重新登录’);
}

_hideLoading();
}

Redux

Redux是网页开发着广泛使用的设计模式,比如用在React.js中。关于它的介绍可以参考文章Flutter主题切换之flutter redux

架构视图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

程序入口

main.dart是程序的入口,完成登录界面的启动,相关代码如下所示

void main() {
final store = new Store(
appReducer,
initialState: AppState.initial(),
middleware: [
LoginMiddleware(),
],
);

runApp(
ReduxApp(
store: store,
),
);
}

class ReduxApp extends StatelessWidget {
final Store store;

const ReduxApp({Key key, this.store}) : super(key: key);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

img
img

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip204888 备注Android获取(资料价值较高,非无偿)
img

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~

将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。

提升架构认知不是一蹴而就的,它离不开刻意学习和思考。

**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。

希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!

出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V:vip204888 备注Android获取(资料价值较高,非无偿)
[外链图片转存中…(img-e1NqdGzG-1711573539532)]

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~

将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。

提升架构认知不是一蹴而就的,它离不开刻意学习和思考。

**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

[外链图片转存中…(img-QoRSHoa8-1711573539533)]

[外链图片转存中…(img-e9aP40yl-1711573539533)]

最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。

希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值