flutter 延迟初始化错误:字段'apiURL'尚未初始化

r1zhe5dt  于 2022-11-25  发布在  Flutter
关注(0)|答案(1)|浏览(225)

当我尝试连接到我在GCP上部署的后端API时,出现以下错误。

延迟初始化错误:字段'apiURL'尚未初始化

跟踪显示以下内容:

I/flutter (20883): LateInitializationError: Field 'apiURL' has not been initialized.
I/flutter (20883): #0      AuthApiService.apiURL (package:Myapp/services/auth_api.dart)
I/flutter (20883): #1      AuthApiService.loginWithCredentials (package:Myapp/services/auth_api.dart:335:41)
I/flutter (20883): #2      UserService.loginWithCredentials (package:Myapp/services/user.dart:338:53)
I/flutter (20883): #3      KNAuthLoginPageState._login (package:Myapp/pages/auth/login.dart:145:26)
I/flutter (20883): #4      KNAuthLoginPageState._submitForm (package:Myapp/pages/auth/login.dart:136:13)
I/flutter (20883): #5      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24)
I/flutter (20883): #6      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11)
I/flutter (20883): #7      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:306:5)
I/flutter (20883): #8      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:239:7)
I/flutter (20883): #9      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:615:9)
I/flutter (20883): #10     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12)
I/flutter (20883): #11     PointerRouter._dispatchEventToRoutes
I/flutter (20883): In dev mode. Not sending report to Sentry.io.

我的验证API日期(_A):

import 'dart:io';

import 'package:Myapp/models/language.dart';
import 'package:Myapp/services/httpie.dart';
import 'package:Myapp/services/string_template.dart';
import 'package:meta/meta.dart';

class AuthApiService {
  late HttpieService _httpService;
  late StringTemplateService _stringTemplateService;

  late String apiURL;

  static const CHECK_USERNAME_PATH = 'api/auth/username-check/';
  static const CHECK_EMAIL_PATH = 'api/auth/email-check/';
  static const UPDATE_EMAIL_PATH = 'api/auth/user/settings/';
  static const VERIFY_EMAIL_TOKEN = 'api/auth/email/verify/';
  static const ACCEPT_GUIDELINES = 'api/auth/user/accept-guidelines/';
  static const SET_NEW_LANGUAGE = 'api/auth/user/languages/';
  static const GET_NEW_LANGUAGE = 'api/auth/user/languages/';
  static const UPDATE_PASSWORD_PATH = 'api/auth/user/settings/';
  static const CREATE_ACCOUNT_PATH = 'api/auth/register/';
  static const VERIFY_REGISTER_TOKEN = 'api/auth/register/verify-token/';
  static const DELETE_ACCOUNT_PATH = 'api/auth/user/delete/';
  static const GET_AUTHENTICATED_USER_PATH = 'api/auth/user/';
  static const UPDATE_AUTHENTICATED_USER_PATH = 'api/auth/user/';
  static const GET_USERS_PATH = 'api/auth/users/';
  static const REPORT_USER_PATH = 'api/auth/users/{userUsername}/report/';
  static const GET_LINKED_USERS_PATH = 'api/auth/linked-users/';
  static const SEARCH_LINKED_USERS_PATH = 'api/auth/linked-users/search/';
  static const GET_BLOCKED_USERS_PATH = 'api/auth/blocked-users/';
  static const SEARCH_BLOCKED_USERS_PATH = 'api/auth/blocked-users/search/';
  static const ENABLE_NEW_POST_NOTIFICATIONS_FOR_USER_PATH =
      'api/auth/users/{userUsername}/notifications/subscribe/new-post/';
  static const BLOCK_USER_PATH = 'api/auth/users/{userUsername}/block/';
  static const UNBLOCK_USER_PATH = 'api/auth/users/{userUsername}/unblock/';
  static const GET_FOLLOWERS_PATH = 'api/auth/followers/';
  static const SEARCH_FOLLOWERS_PATH = 'api/auth/followers/search/';
  static const GET_FOLLOWINGS_PATH = 'api/auth/followings/';
  static const SEARCH_FOLLOWINGS_PATH = 'api/auth/followings/search/';
  static const LOGIN_PATH = 'api/auth/login/';
  static const REQUEST_RESET_PASSWORD_PATH = 'api/auth/password/reset/';
  static const VERIFY_RESET_PASSWORD_PATH = 'api/auth/password/verify/';
  static const AUTHENTICATED_USER_NOTIFICATIONS_SETTINGS_PATH =
      'api/auth/user/notifications-settings/';

  void setHttpService(HttpieService httpService) {
    _httpService = httpService;
  }

  void setStringTemplateService(StringTemplateService stringTemplateService) {
    _stringTemplateService = stringTemplateService;
  }

  void setApiURL(String newApiURL) {
    apiURL = newApiURL;
  }

  Future<HttpieResponse> deleteUser({required String password}) {
    Map<String, dynamic> body = {'password': password};
    return _httpService.post('$apiURL$DELETE_ACCOUNT_PATH',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> checkUsernameIsAvailable({required String username}) {
    return _httpService
        .postJSON('$apiURL$CHECK_USERNAME_PATH', body: {'username': username});
  }

  Future<HttpieResponse> checkEmailIsAvailable({required String email}) {
    return _httpService
        .postJSON('$apiURL$CHECK_EMAIL_PATH', body: {'email': email});
  }

  Future<HttpieStreamedResponse> updateUserEmail({required String email}) {
    Map<String, dynamic> body = {};
    body['email'] = email;
    return _httpService.patchMultiform('$apiURL$UPDATE_EMAIL_PATH',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieStreamedResponse> updateUserPassword(
      {required String currentPassword, required String newPassword}) {
    Map<String, dynamic> body = {};
    body['current_password'] = currentPassword;
    body['new_password'] = newPassword;
    return _httpService.patchMultiform('$apiURL$UPDATE_PASSWORD_PATH',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> verifyEmailWithToken(String token) {
    Map<String, dynamic> body = {'token': token};
    return _httpService.postJSON('$apiURL$VERIFY_EMAIL_TOKEN',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieStreamedResponse> updateUser({
    dynamic avatar,
    dynamic cover,
    String? name,
    String? username,
    String? url,
    bool? followersCountVisible,
    bool? communityPostsVisible,
    String? bio,
    String? location,
    String? visibility,
  }) {
    Map<String, dynamic> body = {};

    if (avatar is File) {
      body['avatar'] = avatar;
    } else if (avatar is String && avatar.isEmpty) {
      // This is what deletes the avatar. Ugly af.
      body['avatar'] = avatar;
    }

    if (cover is File) {
      body['cover'] = cover;
    } else if (cover is String && cover.isEmpty) {
      // This is what deletes the cover. Ugly af.
      body['cover'] = cover;
    }

    if (name != null) body['name'] = name;

    if (username != null) body['username'] = username;

    if (url != null) body['url'] = url;

    if (bio != null) body['bio'] = bio;

    if (visibility != null) body['visibility'] = visibility;

    if (followersCountVisible != null)
      body['followers_count_visible'] = followersCountVisible;

    if (communityPostsVisible != null)
      body['community_posts_visible'] = communityPostsVisible;

    if (location != null) body['location'] = location;

    return _httpService.patchMultiform('$apiURL$UPDATE_AUTHENTICATED_USER_PATH',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieStreamedResponse> createUser(
      {required String email,
      required String token,
      required String name,
      required String username,
      required bool isOfLegalAge,
      required bool areGuidelinesAccepted,
      required String password,
      File? avatar}) {
    Map<String, dynamic> body = {
      'email': email,
      'token': token,
      'name': name,
      'username': username,
      'is_of_legal_age': isOfLegalAge,
      'are_guidelines_accepted': areGuidelinesAccepted,
      'password': password
    };

    if (avatar != null) {
      body['avatar'] = avatar;
    }

    return _httpService.postMultiform('$apiURL$CREATE_ACCOUNT_PATH',
        body: body);
  }

  Future<HttpieResponse> verifyRegisterToken({required String token}) {
    Map<String, dynamic> body = {'token': token};

    return _httpService.post('$apiURL$VERIFY_REGISTER_TOKEN', body: body);
  }

  Future<HttpieResponse> getUserWithAuthToken(String authToken) {
    Map<String, String> headers = {'Authorization': 'Token $authToken'};

    return _httpService.get('$apiURL$GET_AUTHENTICATED_USER_PATH',
        headers: headers);
  }

  Future<HttpieResponse> getUserWithUsername(String username,
      {bool authenticatedRequest = true}) {
    return _httpService.get('$apiURL$GET_USERS_PATH$username/',
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> getPostsCountForUserWithName(String username,
      {bool authenticatedRequest = true}) {
    return _httpService.get('$apiURL$GET_USERS_PATH$username/posts/count/',
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> getUsersWithQuery(String query,
      {bool authenticatedRequest = true}) {
    return _httpService.get('$apiURL$GET_USERS_PATH',
        queryParameters: {'query': query},
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> searchLinkedUsers(
      {required String query, int? count, String? withCommunity}) {
    Map<String, dynamic> queryParams = {'query': query};

    if (count != null) queryParams['count'] = count;

    if (withCommunity != null) queryParams['with_community'] = withCommunity;

    return _httpService.get('$apiURL$SEARCH_LINKED_USERS_PATH',
        queryParameters: queryParams, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> getLinkedUsers(
      {bool authenticatedRequest = true,
      int? maxId,
      int? count,
      String? withCommunity}) {
    Map<String, dynamic> queryParams = {};

    if (count != null) queryParams['count'] = count;

    if (maxId != null) queryParams['max_id'] = maxId;

    if (withCommunity != null) queryParams['with_community'] = withCommunity;

    return _httpService.get('$apiURL$GET_LINKED_USERS_PATH',
        queryParameters: queryParams,
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> searchBlockedUsers(
      {required String query, int? count}) {
    Map<String, dynamic> queryParams = {'query': query};

    if (count != null) queryParams['count'] = count;

    return _httpService.get('$apiURL$SEARCH_BLOCKED_USERS_PATH',
        queryParameters: queryParams, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> getBlockedUsers({
    bool authenticatedRequest = true,
    int? maxId,
    int? count,
  }) {
    Map<String, dynamic> queryParams = {};

    if (count != null) queryParams['count'] = count;

    if (maxId != null) queryParams['max_id'] = maxId;

    return _httpService.get('$apiURL$GET_BLOCKED_USERS_PATH',
        queryParameters: queryParams,
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> blockUserWithUsername(String userUsername) {
    String path = _makeBlockUserWithUsernamePath(userUsername);
    return _httpService.post(_makeApiUrl(path), appendAuthorizationToken: true);
  }

  Future<HttpieResponse> unblockUserWithUsername(String userUsername) {
    String path = _makeUnblockUserWithUsernamePath(userUsername);
    return _httpService.post(_makeApiUrl(path), appendAuthorizationToken: true);
  }

  Future<HttpieResponse> enableNewPostNotificationsForUserWithUsername(
      String userUsername) {
    String path =
        _makeEnableNewPostNotificationsForUserWithUsernamePath(userUsername);
    return _httpService.putJSON(_makeApiUrl(path),
        appendAuthorizationToken: true);
  }

  Future<HttpieResponse> disableNewPostNotificationsForUserWithUsername(
      String userUsername) {
    String path =
        _makeEnableNewPostNotificationsForUserWithUsernamePath(userUsername);
    return _httpService.delete(_makeApiUrl(path),
        appendAuthorizationToken: true);
  }

  Future<HttpieResponse> searchFollowers({required String query, int? count}) {
    Map<String, dynamic> queryParams = {'query': query};

    if (count != null) queryParams['count'] = count;

    return _httpService.get('$apiURL$SEARCH_FOLLOWERS_PATH',
        queryParameters: queryParams, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> getFollowers(
      {bool authenticatedRequest = true, int? maxId, int? count}) {
    Map<String, dynamic> queryParams = {};

    if (count != null) queryParams['count'] = count;

    if (maxId != null) queryParams['max_id'] = maxId;

    return _httpService.get('$apiURL$GET_FOLLOWERS_PATH',
        queryParameters: queryParams,
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> searchFollowings({required String query, int? count}) {
    Map<String, dynamic> queryParams = {'query': query};

    if (count != null) queryParams['count'] = count;

    return _httpService.get('$apiURL$SEARCH_FOLLOWINGS_PATH',
        queryParameters: queryParams, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> getFollowings({
    bool authenticatedRequest = true,
    int? maxId,
    int? count,
  }) {
    Map<String, dynamic> queryParams = {};

    if (count != null) queryParams['count'] = count;

    if (maxId != null) queryParams['max_id'] = maxId;

    return _httpService.get('$apiURL$GET_FOLLOWINGS_PATH',
        queryParameters: queryParams,
        appendAuthorizationToken: authenticatedRequest);
  }

  Future<HttpieResponse> loginWithCredentials(
      {required String username, required String password}) {
    return this._httpService.postJSON('$apiURL$LOGIN_PATH',
        body: {'username': username, 'password': password});
  }

  Future<HttpieResponse> requestPasswordReset({required String email}) {
    var body = {};
    if (email != null && email != '') {
      body['email'] = email;
    }
    return this
        ._httpService
        .postJSON('$apiURL$REQUEST_RESET_PASSWORD_PATH', body: body);
  }

  Future<HttpieResponse> verifyPasswordReset(
      {String? newPassword, String? passwordResetToken}) {
    return this._httpService.postJSON('$apiURL$VERIFY_RESET_PASSWORD_PATH',
        body: {'new_password': newPassword, 'token': passwordResetToken});
  }

  Future<HttpieResponse> getAuthenticatedUserNotificationsSettings() {
    return this._httpService.get(
        '$apiURL$AUTHENTICATED_USER_NOTIFICATIONS_SETTINGS_PATH',
        appendAuthorizationToken: true);
  }

  Future<HttpieResponse> updateAuthenticatedUserNotificationsSettings({
    bool? postCommentNotifications,
    bool? postCommentReplyNotifications,
    bool? postCommentReactionNotifications,
    bool? postCommentUserMentionNotifications,
    bool? postUserMentionNotifications,
    bool? postReactionNotifications,
    bool? followNotifications,
    bool? followRequestNotifications,
    bool? followRequestApprovedNotifications,
    bool? connectionRequestNotifications,
    bool? connectionConfirmedNotifications,
    bool? communityInviteNotifications,
    bool? communityNewPostNotifications,
    bool? userNewPostNotifications,
  }) {
    Map<String, dynamic> body = {};

    if (postCommentNotifications != null)
      body['post_comment_notifications'] = postCommentNotifications;

    if (postCommentReplyNotifications != null)
      body['post_comment_reply_notifications'] = postCommentReplyNotifications;

    if (postCommentUserMentionNotifications != null)
      body['post_comment_user_mention_notifications'] =
          postCommentUserMentionNotifications;

    if (postUserMentionNotifications != null)
      body['post_user_mention_notifications'] = postUserMentionNotifications;

    if (postCommentReactionNotifications != null)
      body['post_comment_reaction_notifications'] =
          postCommentReactionNotifications;

    if (postReactionNotifications != null)
      body['post_reaction_notifications'] = postReactionNotifications;

    if (followNotifications != null)
      body['follow_notifications'] = followNotifications;

    if (followRequestNotifications != null)
      body['follow_request_notifications'] = followRequestNotifications;

    if (followRequestApprovedNotifications != null)
      body['follow_request_approved_notifications'] =
          followRequestApprovedNotifications;

    if (connectionRequestNotifications != null)
      body['connection_request_notifications'] = connectionRequestNotifications;

    if (communityInviteNotifications != null)
      body['community_invite_notifications'] = communityInviteNotifications;

    if (communityNewPostNotifications != null)
      body['community_new_post_notifications'] = communityNewPostNotifications;

    if (userNewPostNotifications != null)
      body['user_new_post_notifications'] = userNewPostNotifications;

    if (connectionConfirmedNotifications != null)
      body['connection_confirmed_notifications'] =
          connectionConfirmedNotifications;

    return _httpService.patchJSON(
        '$apiURL$AUTHENTICATED_USER_NOTIFICATIONS_SETTINGS_PATH',
        body: body,
        appendAuthorizationToken: true);
  }

  Future<HttpieResponse> acceptGuidelines() {
    return this
        ._httpService
        .post('$apiURL$ACCEPT_GUIDELINES', appendAuthorizationToken: true);
  }

  Future<HttpieResponse> getAllLanguages() {
    String url = _makeApiUrl(GET_NEW_LANGUAGE);
    return _httpService.get(url, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> setNewLanguage(Language language) {
    Map<String, String> body = {'language_id': language.id.toString()};
    return this._httpService.post('$apiURL$SET_NEW_LANGUAGE',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> reportUserWithUsername(
      {required String userUsername,
      required int moderationCategoryId,
      String? description}) {
    String path = _makeReportUserPath(username: userUsername);

    Map<String, String> body = {'category_id': moderationCategoryId.toString()};

    if (description != null && description.isNotEmpty) {
      body['description'] = description;
    }

    return _httpService.post(_makeApiUrl(path),
        body: body, appendAuthorizationToken: true);
  }

  String _makeBlockUserWithUsernamePath(String username) {
    return _stringTemplateService
        .parse(BLOCK_USER_PATH, {'userUsername': username});
  }

  String _makeUnblockUserWithUsernamePath(String username) {
    return _stringTemplateService
        .parse(UNBLOCK_USER_PATH, {'userUsername': username});
  }

  String _makeEnableNewPostNotificationsForUserWithUsernamePath(
      String username) {
    return _stringTemplateService.parse(
        ENABLE_NEW_POST_NOTIFICATIONS_FOR_USER_PATH,
        {'userUsername': username});
  }

  String _makeReportUserPath({required username}) {
    return _stringTemplateService
        .parse(REPORT_USER_PATH, {'userUsername': username});
  }

  String _makeApiUrl(String string) {
    return '$apiURL$string';
  }
}

setApiURL用于以下provider.dart中:

authApiService.setApiURL(environment.apiUrl);
    postsApiService.setApiURL(environment.apiUrl);
    emojisApiService.setApiURL(environment.apiUrl);
    userInvitesApiService.setApiURL(environment.apiUrl);
    followsApiService.setApiURL(environment.apiUrl);
    moderationApiService.setApiURL(environment.apiUrl);
    connectionsApiService.setApiURL(environment.apiUrl);
    connectionsCirclesApiService.setApiURL(environment.apiUrl);
    followsListsApiService.setApiURL(environment.apiUrl);
    communitiesApiService.setApiURL(environment.apiUrl);
    hashtagsApiService.setApiURL(environment.apiUrl);
    categoriesApiService.setApiURL(environment.apiUrl);
    notificationsApiService.setApiURL(environment.apiUrl);
    devicesApiService.setApiURL(environment.apiUrl);
    waitlistApiService
        .setMyAppApiURL(environment.MyAppApiUrl);

编辑:我按照评论中的建议做了以下修改。在provider.dart中,setApiURL被调用:

authApiService.apiURL = ''; // Initialized apiURl(auth_api.dart) as empty String & Called authApiService(auth_api.dart) which contains the function setapiUrl
if (authApiService.apiURL.isEmpty) { authApiService.setApiURL(environment.apiUrl)};//Set a condition before using the apiUrl.

The above has no effect.

然后,我尝试了以下方法:

auth_api.dart
String? apiURL;
void setApiURL(String newApiURL) { if (apiURL == null) { apiURL = newApiURL; } } 

The error now changes to Invalid argument(s): No host specified in URI nullapi/auth/login/

I reverted to original keeping only 

String? apiURL;

and change the following in provider.dart

if (authApiService.apiURL == null) { authApiService.setApiURL(environment.apiUrl)}.

The error remians to to Invalid argument(s): No host specified in URI nullapi/auth/login/

根据Mohan的要求,我更新了以下内容:

user_invite.dart

static const  INVITE_LINK = '{apiURL}api/auth/invite?token={token}';

user_invite_detail.dart

String inviteLink = _stringTemplateService.parse(UserInvite.INVITE_LINK, {'token': token, 'apiURL': apiURL});

List<Widget> _buildActionsList() {
    if (widget.userInvite.createdUser != null) {
      return [const SizedBox()];
    }

    return [
      ListTile(
        leading: const KNIcon(KNIcons.chat),
        title: KNText(_localizationService.user__invites_share_yourself),
        subtitle: KNSecondaryText(
          _localizationService.user__invites_share_yourself_desc,
        ),
        onTap: () {
          String? apiURL = _userInvitesApiService.apiURL;
          String token = widget.userInvite.token!;
          Share.share(getShareMessageForInviteWithToken(token, apiURL));
        },
      ),
      ListTile(
        leading: const KNIcon(KNIcons.email),
        title: KNText(_localizationService.user__invites_share_email),
        subtitle: KNSecondaryText(
          _localizationService.user__invites_share_email_desc,
        ),
        onTap: () async {
          await _modalService.openSendUserInviteEmail(
              context: context, userInvite: widget.userInvite);
          Navigator.of(context).pop();
        },
      )
    ];
  }
  
  
  There are other files with this format like in connection_dart below:
  
  String?apiURL;
  
  void setApiURL(String newApiURL) {
    apiURL = newApiURL;
  }
  
  Future<HttpieResponse> connectWithUserWithUsername(String username,
      {List<int>? circlesIds}) {
    Map<String, dynamic> body = {'username': username};

    if (circlesIds != null) body['circles_ids'] = circlesIds;

    return _httpService.postJSON('$apiURL$CONNECT_WITH_USER_PATH',
        body: body, appendAuthorizationToken: true);
  }
  
  Future<HttpieResponse> confirmConnectionWithUserWithUsername(String username,
      {List<int>? circlesIds}) {
    Map<String, dynamic> body = {'username': username};

    if (circlesIds != null) body['circles_ids'] = circlesIds;

    return _httpService.postJSON('$apiURL$CONFIRM_CONNECTION_PATH',
        body: body, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> disconnectFromUserWithUsername(String username) {
    return _httpService.postJSON('$apiURL$DISCONNECT_FROM_USER_PATH',
        body: {'username': username}, appendAuthorizationToken: true);
  }

  Future<HttpieResponse> updateConnectionWithUsername(String username,
      {List<int>? circlesIds}) {
    Map<String, dynamic> body = {'username': username};

    if (circlesIds != null) body['circles_ids'] = circlesIds;

    return _httpService.postJSON('$apiURL$UPDATE_CONNECTION_PATH',
        body: body, appendAuthorizationToken: true);
  }
}
wlp8pajw

wlp8pajw1#

LateInitializationError: Field 'apiURL' has not been initialized
这意味着apiURL在使用时尚未启动。
因此,请确保在使用apiURL之前对其进行初始化,或者如果不确定,则将late String apiURL;更改为String? apiURL;,并在使用时添加空值检查。
通过使apiURL可空,我们告诉编译器它可以是空值。

相关问题