从 firebase 检索用户数据时出现意外的空值

Mah*_*oon 5 dart flutter

我正在尝试从 fire store 获取用户数据,但收到此错误:

Error: Assertion failed: file:///Users/mac/Developer/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-2.5.4/lib/src/collection_reference.dart:116:14
path.isNotEmpty
"a document path must be a non-empty string"
    at Object.throw_ [as throw] (http://localhost:53075/dart_sdk.js:5041:11)
    at Object.assertFailed (http://localhost:53075/dart_sdk.js:4980:15)
    at cloud_firestore._JsonCollectionReference.new.doc (http://localhost:53075/packages/cloud_firestore/cloud_firestore.dart.lib.js:579:38)
    at home_view_model.HomeViewModel.new.getUserData (http://localhost:53075/packages/haroonpf/presentation/screens/home/viewmodel/home_view_model.dart.lib.js:35:78)
    at getUserData.next (<anonymous>)
    at runBody (http://localhost:53075/dart_sdk.js:37422:34)
    at Object._async [as async] (http://localhost:53075/dart_sdk.js:37453:7)
    at home_view_model.HomeViewModel.new.getUserData (http://localhost:53075/packages/haroonpf/presentation/screens/home/viewmodel/home_view_model.dart.lib.js:34:20)
    at http://localhost:53075/packages/haroonpf/presentation/screens/home/view/widgets/common/personal_details/user_info.dart.lib.js:334:25
    at http://localhost:53075/packages/haroonpf/presentation/screens/base_screen.dart.lib.js:166:73
    at binding$5.WidgetsFlutterBinding.new.[_invokeFrameCallback] (http://localhost:53075/packages/flutter/src/scheduler/binding.dart.lib.js:717:9)
    at binding$5.WidgetsFlutterBinding.new.handleDrawFrame (http://localhost:53075/packages/flutter/src/scheduler/binding.dart.lib.js:694:37)
    at http://localhost:53075/packages/flutter/src/scheduler/binding.dart.lib.js:603:14
    at internalCallback (http://localhost:53075/dart_sdk.js:24253:11)

======== Exception caught by widgets library =======================================================
The following TypeErrorImpl was thrown building Consumer<HomeViewModel>(dirty, dependencies: [_InheritedProviderScope<HomeViewModel>]):
Unexpected null value.

The relevant error-causing widget was: 
  Consumer<HomeViewModel> file:///Users/mac/Desktop/My%20Portfolio/haroonpf/lib/presentation/screens/base_screen.dart:37:16
When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49                           throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 518:63                       nullCheck
packages/haroonpf/presentation/screens/home/view/widgets/common/personal_details/user_info.dart 33:44  <fn>
packages/provider/src/consumer.dart 180:19                                                             buildWithChild
packages/nested/nested.dart 259:41                                                                     build
...
NoSuchMethodError: '[]'
Dynamic call of null.
Receiver: null
Arguments: ["user_image"]
Run Code Online (Sandbox Code Playgroud)

因为这是我的 ViewModel 类:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:haroonpf/enums/screen_state.dart';
import 'package:haroonpf/presentation/screens/home/models/user_info.dart';
import 'package:haroonpf/utils/constants.dart';
import '../../base_view_model.dart';

class HomeViewModel extends BaseViewModel {
  UserInfoModel? userModel;
  void getUserData() async {

    await FirebaseFirestore.instance.collection('users').doc(uId).get().then((value) {
      userModel = UserInfoModel.fromJson(value.data());
      setState(ViewState.Idle);
    }).catchError((error) {
      print(error.toString());
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

这是视图类:

import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:haroonpf/presentation/screens/base_screen.dart';
import 'package:haroonpf/presentation/screens/home/viewmodel/home_view_model.dart';

class MyInfo extends StatelessWidget {
  const MyInfo({
    Key? key,
  }) : super(key: key);


  @override
  Widget build(BuildContext context) {
    return BaseScreen<HomeViewModel>(
      onModelReady: (homeViewModel) {
        homeViewModel.getUserData();
      },
      builder: (context, homeViewModel, _) {
        return AspectRatio(
          aspectRatio: 1.23,
          child: Container(
            color: Color(0xFF242430),
            child: Column(
              children: [
                Spacer(flex: 2),
                CircleAvatar(
                  radius: 50,
                  backgroundImage: AssetImage("assets/images/IMG_7344.jpg"),
                  //   backgroundImage: Image.network(url);
                ),
                Spacer(),
                Text(
                  homeViewModel.userModel!.name!,
                  style: Theme.of(context).textTheme.subtitle2,
                ),
                Text(
                  "Software Engineer and Founder at AirForce",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontWeight: FontWeight.w200,
                    height: 1.5,
                  ),
                ),
                Spacer(flex: 2),
              ],
            ),
          ),
        );
      }
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

因为 BaseViewModel 看起来像下面的代码:

import 'package:flutter/widgets.dart';
import 'package:haroonpf/enums/screen_state.dart';
import 'package:haroonpf/utils/context_extentions.dart';

class BaseViewModel extends ChangeNotifier {
  ViewState _state = ViewState.Idle;

  ViewState get state => _state;

  SwitchState _switchState = SwitchState.CLOSE;

  SwitchState get switchState => _switchState;

  void setState(ViewState viewState) {
    _state = viewState;
    notifyListeners();
  }

  void switchLanguage(bool state, BuildContext context) async {
    state == true
        ? _switchState = SwitchState.OPEN
        : _switchState = SwitchState.CLOSE;

    notifyListeners();

    if (context.locale == const Locale('ar', 'EG')) {
      context.setLocale(const Locale('en', 'US'));
    } else {
      context.setLocale(const Locale('ar', 'EG'));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的基本屏幕:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../locator.dart';
import 'base_view_model.dart';

class BaseScreen<T extends BaseViewModel> extends StatefulWidget {
  final Widget Function(BuildContext context, T model, Widget? child)? builder;
  final Function(T)? onModelReady;
  final Function()? onFinish;

  BaseScreen({this.builder, this.onModelReady, this.onFinish});

  @override
  _BaseScreenState<T> createState() => _BaseScreenState<T>();
}

class _BaseScreenState<T extends BaseViewModel> extends State<BaseScreen<T>> {
  T model = locator<T>();

  @override
  void initState() {
    super.initState();
    if (WidgetsBinding.instance != null) {
      WidgetsBinding.instance!.addPostFrameCallback((_) {
        if (widget.onModelReady != null) {
          widget.onModelReady!(model);
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>(
        create: (context) => model,
        child: Consumer<T>(builder: widget.builder!));
  }

  @override
  void dispose() {
    if (widget.onFinish != null) {
      widget.onFinish!;
    }
    super.dispose();
  }
}
Run Code Online (Sandbox Code Playgroud)

我有一个枚举类,其中包含屏幕状态,如下代码:

enum ViewState { Idle, Busy }

enum SwitchState { OPEN, CLOSE }
Run Code Online (Sandbox Code Playgroud)

我有一个用户模型如下:

class UserInfoModel {
  String? image;
  String? name;
  String? country;
  String? city;
  UserInfoModel(
      {this.image,
        this.name,
        this.country,
        this.city,});

  UserInfoModel.fromJson(dynamic json) {
    image = json['user_image'];
    name = json['name'];
    country = json['country'];
    city = json['city'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['user_image'] = this.image;
    data['name'] = this.name;
    data['country'] = this.country;
    data['city'] = this.city;
    return data;
  }
}
Run Code Online (Sandbox Code Playgroud)

数据库如下图所示: 在此输入图像描述

因为我需要从 firestore 读取特定的用户数据,如下面的代码,类似于 MyInfo 类中的代码:

                Text(
                  homeViewModel.userModel!.name!,
                  style: Theme.of(context).textTheme.subtitle2,
                ),
Run Code Online (Sandbox Code Playgroud)