我是Flutter和Bloc架构的新手,我正在尝试将Bloc用于我的登录功能。我试图在Bloc文件中调用一个函数,但是我不知道该怎么做。如果您能帮助我看看我在使用Bloc时是否还有其他问题,我也将很高兴。这是我的用户界面代码:
MaterialButton( color: Colors.deepPurple, minWidth: screenAwareSize(500, context), onPressed: () { _submitForm(authBloc, user, pass); }, void _submitForm(AuthBloc authBloc, String user, String pass) async { formKey.currentState.save(); if (formKey.currentState.validate()) { var response = await authBloc.login(user, pass); //when I print(response) it shows null } }
这是我的集团课:
class AuthBloc extends MainBloc { final Repo _repo = Repo(); PublishSubject<Future<UserModel>> _authController = new PublishSubject<Future<UserModel>>(); Observable<Future<UserModel>> get auth => _authController.stream; login(String user, String pass) async { Future<UserModel> item = await _repo.login(user, pass); _authController.sink.add(item); } dispose() { _authController.close(); } } AuthBloc authBloc = new AuthBloc();
这是我的API类:
class API{ Future<UserModel> login(String user, String pass) async { var response = await client.get(base_url + "login.php?user=${user}&pass=${pass}"); return UserModel.fromJSON(json.decode(response.body)); }}
这是我的回购类:
class Repo { final API api = new API(); login(String user, String pass) async => await api.login(user, pass);}
我将尝试首先解释BLOC组件应该做的越短越好(并且越琐碎)。
您还可以根据您的应用程序执行其他操作,例如:
现在,我建议也将BLOC模式与Dependency Injection一起使用,没有它是没有用的。使用DI,您可以模拟所有组件直到UI,并且对所有代码进行单元测试非常容易。
另外,我认为没有必要将RxDart(library)与Streams / Future(相当于RxDart lib的dat)混合使用。首先,我建议仅使用其中之一,并根据您的代码片段,建议您更好地了解如何整体使用Rx。
因此,下面有一个关于如何使用块模式进行登录的小代码片段(也可以检查代码注释:))。
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class TheUIScreen extends StatefulWidget { @override _TheUIScreenState createState() => _TheUIScreenState(); } class _TheUIScreenState extends State<TheUIScreen> { //TODO: for repo, block, networking, we used dependecy injection, here we have to create and init all the dependecies; TheAuthBlock _block; @override void initState() { super.initState(); TheAuthAPI api = TheAuthAPI(); TheAuthRepo repo = TheAuthRepo(theAuthAPI: api); // we could also do repo = TheAuthRepo(); _block = TheAuthBlock(repo: repo); // we could also do _block = TheAuthBlock(); } @override Widget build(BuildContext context) { return Container( child: RaisedButton(onPressed: () { _block.loginUser("test", "test").then((actualUser) { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return TestRoute(); // or do whatever action you need, the user is logged in })); }).catchError((error) { //show error, something went wrong at login; }); }), ); } } class TheAuthBlock { final TheAuthRepo repo; TheAuthBlock({this.repo = const TheAuthRepo()}); Future<UserModel> loginUser(String email, String password) { return repo.login(email, password).then((userModel) { //TODO: here we decide HOW to display the user, you might want to transfor the UserModel into a model that's used only for UI. //In any way, here you should do all the processing, the UI only should only display the data, not manipulate it. }); } } class TheAuthRepo { final TheAuthAPI theAuthAPI; const TheAuthRepo( {this.theAuthAPI = const TheAuthAPI()}); // THIS would be the default constructor but it will alow us to test it using unit tests. Future<UserModel> login(String email, String password) { //TODO: here you could also check if the user is already logged in and send the current user as a response if (email.isNotEmpty && password.isNotEmpty) { return theAuthAPI.login(email, password).then((userModel) { //TODO: you can do extra processing here before returning the data to the block; }); } else { return Future.error( "Well you can't login with empty ddata"); // TODO: you can return differetn errors for email or pwd; } } } class TheAuthAPI { final String url; const TheAuthAPI({this.url = "https://my.cool.api/login"}); Future<UserModel> login(String email, String pwd) { // TODO: note you return a future from this method since the login will return only once (like almost all http calls) Map<String, String> headers = Map(); // TODO: set any headers you need here Map<String, String> body = { "email": email, "pwd": pwd }; // TODO: change the body acordingly return http.post("THE URL", headers: headers, body: body).then((response) { //TODO: parse response here and return it return UserModel("test", "test"); // this should be generated from the response not like this }); } } class UserModel { final String email; UserModel(this.email, this.pass); final String pass; }