Flutter: Asking Location permission pauses all app execution, how to let it run asynchronously

Viewed 258

When my app requests location permission the entire app stops until the dialog is complete (e.g. if the permission dialog pops up during a page transition the transition will freeze mid transition until the dialog is resolved).

Literally it causes execution to pause.

Using: flutter_riverpod, location.

The offending code:

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/all.dart';
import 'package:location/location.dart';

class MapApiBloc extends StateNotifier<MapApiState> {
  // Instantiating a location service
  static Location _location = Location();

  // This will subscribe to the user's location
  StreamSubscription<LocationData> _streamSubscription;

  // Permissions stuff
  bool _serviceEnabled;
  PermissionStatus _permissionGranted;

  //  Initial (empty) state
  static const MapApiState _initialState = MapApiState(userLocation: null);

  MapApiBloc() : super(_initialState) {
    init();
  }

  // This runs when you initialize the class
  init() async {
    // Checks if user toggled on location service
    _serviceEnabled = await _location.serviceEnabled();
    if (!_serviceEnabled) {
      _serviceEnabled = await _location.requestService();
      if (!_serviceEnabled) {
        return;
      }
    }

    // Asks for permission
    _permissionGranted = await _location.hasPermission();
    if (_permissionGranted == PermissionStatus.denied) {
      _permissionGranted = await _location.requestPermission();
      if (_permissionGranted != PermissionStatus.granted) {
        return;
      }
    }

    // Starts the subscription
    _streamSubscription = _location.onLocationChanged.listen((event) {
      state = MapApiState(userLocation: event);
    });
  }

  @override
  void dispose() {
    _streamSubscription.cancel();
    super.dispose();
  }
}



class MapApiState {
  final LocationData userLocation;
  const MapApiState({@required this.userLocation});
}

final mapApiProvider = StateNotifierProvider<MapApiBloc>((ref) {
  return MapApiBloc();
});

UI Code:

class ViewNearbyMapPage extends StatefulWidget {
  @override
  _ViewNearbyMapPageState createState() => _ViewNearbyMapPageState();
}

class _ViewNearbyMapPageState extends State<ViewNearbyMapPage> {
  Completer<GoogleMapController> _controller = Completer();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Search Sellers")),
      body: Consumer(
        builder: (context, watch, child) {
          var location = watch(mapApiProvider.state);
          if (location.userLocation?.latitude == null) {
            return Center(child: CircularProgressIndicator());
          }
          CameraPosition _myPosition = CameraPosition(
            target: LatLng(location.userLocation.latitude,
                location.userLocation.longitude),
            zoom: 14.4746,
          );

          return GoogleMap(
            initialCameraPosition: _myPosition,
            onMapCreated: (controller) {
              _controller.complete(controller);
            },
          );
        },
      ),
    );
  }
}
0 Answers
Related