如何使用异步初始化 class
How to initialize a class with async
我正在使用 Dart 中的 Flutter 制作个人资料页面。用户信息存储在 Firebase Firestore 中,图像存储在 Firebase Storage 中。 Firestore 包含配置文件图像在 Firebase 存储中的路径 (profileImages/{userId}/profile.jpg
)。正如您在下面看到我的代码,可下载图像 url 已在 ProfileImage
class.
中获取
我想在初始化用户 class 时 getDownloadUrl
。不在 ProfileImage class.
class User {
final profilePathInFirebaseStorage;
User({this.profilePathInFirebaseStorage});
factory User.fromFirestore(DocumentSnapshot snapshot) {
return User(profilePathInFirebaseStorage: snapshot.data['imagePath']);
}
}
class ProfileImage extends StatelessWidget {
final String profilePathInFirebaseStorage;
const ProfileImage(
{Key key,
this.profilePathInFirebaseStorage = '',)
: super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: firebase_storage.FirebaseStorage.instance
.ref(profilePathInFirebaseStorage)
.getDownloadURL(), // Can this operation go into User class?
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
return Container(child: NetworkImage(snapshot.data));
});
}
}
听起来你想把下载URL存储在用户class中,然后只初始化一次。
像这样的东西应该可以工作:
class User {
final profilePathInFirebaseStorage;
Future<String> downloadURL
User({this.profilePathInFirebaseStorage});
factory User.fromFirestore(DocumentSnapshot snapshot) {
return User(profilePathInFirebaseStorage: snapshot.data['imagePath']);
}
Future<String> getDownloadURL() {
if (downloadURL == null) {
downloadURL = firebase_storage.FirebaseStorage.instance
.ref(profilePathInFirebaseStorage)
.getDownloadURL()
}
return downloadURL;
}
}
因此,这会在第一次请求时按需初始化下载 URL。如果你愿意,你可以在构造函数中做同样的事情。但是没有办法让它不是 Future
,因为下载 URL 是异步确定的,你需要一个 Future
来处理有人在下载之前请求 URL 的情况可用。
由于您不能拥有异步构造函数,这里有一个使用异步静态方法创建 User
class 的模式。
class User {
String userData;
User._privateConstructor();
static Future<User> createAsync() async {
var user = User._privateConstructor();
print('User.createAsync() called');
return user._initAsync();
}
/// Simulates a long-loading process such as remote DB connection or device
/// file storage access.
Future<User> _initAsync() async {
// ↓ do your Firebase call here ↓
userData = await Future.delayed(Duration(seconds: 2), () => 'Some Firebase user data');
print('User._initAsync done');
return this;
}
}
要实例化您的 User
class,请调用公开的异步方法:
User user = await User.createAsync();
当这个 returns 您的 user
实例将拥有它需要的 Firestore 数据时。
StatefulWidget
中 FutureBuilder
的示例(不使用 await
):
class ProfileImagePage extends StatefulWidget {
@override
_ProfileImagePageState createState() => _ProfileImagePageState();
}
class _ProfileImagePageState extends State<ProfileImagePage> {
Future<User> user;
@override
void initState() {
super.initState();
user = User.createAsync();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: FutureBuilder<User>(
future: user,
builder: (context, snapshot) {
if (snapshot.hasData)
return Center(child: Text(snapshot.data.userData),);
else
return Center(child: Text('Loading...'));
}),
),
);
}
}
我正在使用 Dart 中的 Flutter 制作个人资料页面。用户信息存储在 Firebase Firestore 中,图像存储在 Firebase Storage 中。 Firestore 包含配置文件图像在 Firebase 存储中的路径 (profileImages/{userId}/profile.jpg
)。正如您在下面看到我的代码,可下载图像 url 已在 ProfileImage
class.
我想在初始化用户 class 时 getDownloadUrl
。不在 ProfileImage class.
class User {
final profilePathInFirebaseStorage;
User({this.profilePathInFirebaseStorage});
factory User.fromFirestore(DocumentSnapshot snapshot) {
return User(profilePathInFirebaseStorage: snapshot.data['imagePath']);
}
}
class ProfileImage extends StatelessWidget {
final String profilePathInFirebaseStorage;
const ProfileImage(
{Key key,
this.profilePathInFirebaseStorage = '',)
: super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: firebase_storage.FirebaseStorage.instance
.ref(profilePathInFirebaseStorage)
.getDownloadURL(), // Can this operation go into User class?
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
return Container(child: NetworkImage(snapshot.data));
});
}
}
听起来你想把下载URL存储在用户class中,然后只初始化一次。
像这样的东西应该可以工作:
class User {
final profilePathInFirebaseStorage;
Future<String> downloadURL
User({this.profilePathInFirebaseStorage});
factory User.fromFirestore(DocumentSnapshot snapshot) {
return User(profilePathInFirebaseStorage: snapshot.data['imagePath']);
}
Future<String> getDownloadURL() {
if (downloadURL == null) {
downloadURL = firebase_storage.FirebaseStorage.instance
.ref(profilePathInFirebaseStorage)
.getDownloadURL()
}
return downloadURL;
}
}
因此,这会在第一次请求时按需初始化下载 URL。如果你愿意,你可以在构造函数中做同样的事情。但是没有办法让它不是 Future
,因为下载 URL 是异步确定的,你需要一个 Future
来处理有人在下载之前请求 URL 的情况可用。
由于您不能拥有异步构造函数,这里有一个使用异步静态方法创建 User
class 的模式。
class User {
String userData;
User._privateConstructor();
static Future<User> createAsync() async {
var user = User._privateConstructor();
print('User.createAsync() called');
return user._initAsync();
}
/// Simulates a long-loading process such as remote DB connection or device
/// file storage access.
Future<User> _initAsync() async {
// ↓ do your Firebase call here ↓
userData = await Future.delayed(Duration(seconds: 2), () => 'Some Firebase user data');
print('User._initAsync done');
return this;
}
}
要实例化您的 User
class,请调用公开的异步方法:
User user = await User.createAsync();
当这个 returns 您的 user
实例将拥有它需要的 Firestore 数据时。
StatefulWidget
中 FutureBuilder
的示例(不使用 await
):
class ProfileImagePage extends StatefulWidget {
@override
_ProfileImagePageState createState() => _ProfileImagePageState();
}
class _ProfileImagePageState extends State<ProfileImagePage> {
Future<User> user;
@override
void initState() {
super.initState();
user = User.createAsync();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: FutureBuilder<User>(
future: user,
builder: (context, snapshot) {
if (snapshot.hasData)
return Center(child: Text(snapshot.data.userData),);
else
return Center(child: Text('Loading...'));
}),
),
);
}
}