以下为flutter的最基础使用版本,内容为点击按键增加数字.
这里提供一个Provider
的使用教程:
https://flutterbyexample.com/lesson/proxy-provider
一、第一种写法
//Provider的基础用法
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
//数据类
//如果需要进行通知的话需要混入ChangeNotifier,如果不需要则不用,比如使用Provider、FutureProvider、StreamProvider就不需要
class Model with ChangeNotifier {
int _value = 1;
int get value => _value;
void increment() {
_value++;
notifyListeners();
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Home(),
),
);
}
}
class Home extends StatelessWidget {
Widget build(BuildContext context) {
// Model model = context.watch<Model>();//如果写在这里的话外部也需要被Provide包裹
return Center(
child: ChangeNotifierProvider<Model>(
//需要注意ChangeNotifierProvider是可以在改变数据的时候进行通知,所以对象需要实现ChangeNotifier接口,倘若不是的话则不需要。
//这里不能直接使用Provider<Model>,
// 这个监听对象会刷新包含的UI,另外注意要写泛型
create: (_) => Model(),
//1、注意build函数,UI需要包裹在这个build里面,或者在child属性里面使用
//2、在child属性里面使用时候注意获取不到BuildContext的问题(该问题涉及到BuildContext的原理),针对该问题有以下两种方式,(如果可以获取的话就不需要以下解决方法了)
//1)、将UI视图重新创建新的一个Widget属性。
//2)、使用Build进行包裹,如下:
// child: Builder(
// builder: (context){
// return Text('值:${context.watch<Model>().value}');
// }
// ),
builder: (context, child) {
Model model = context.watch<Model>();//注意这一句的范围,需要被Provider包裹
return Column(
children: [
// 以下三种写法相同
Text('计数:${model.value}'), //第一种写法
// Text('计数:${context.watch<Model>().value}'), //第二种写法
// Text('计数:${Provider.of<Model>(context,listen: true).value}'),//第三种写法
// listen默认值为true
// listen为true时候相当于watch监听数据
// listen为false时候相当于read读取数据
// read不能在 StatelessWidget.build/State.build 内调用.
// 换句话说, 它可以在除了这两个方法以外的任意之处调用,所以对于赋值的地方都可以使用read。
// watch则相反
RaisedButton(
onPressed: () {
// 以下三种写法相同
model.increment(); //第一种写法
// context.read<Model>().increment(); //第二种写法
// Provider.of<Model>(context,listen: false).increment();//第三种写法
//这里不能监听数据改变,因此不可以使用watch及其类似的函数
//如果使用watch则会报错,错误含义大致为尝试监听一个来自于永远不会再次被调用的生命周期的provider。
},
child: Text('增加数'),
)
],
);
}),
);
}
}
二、第二种写法
这个写法相比上一个简单一些,主要用于当使用routes路由进行跳转时候,这时候MaterialApp
不能使用home
属性时候可以使用这种方式
void main() {
final userModel = UserModel();
final size = 1;
runApp(
Provider<int>.value(
value: size,
child: ChangeNotifierProvider.value(
value: userModel,
child: MyApp(),
),
),
);
}