Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”. This article also participated in the “Digitalstar Project” to win a creative gift package and creative incentive money

In this tutorial, I will show you how to get your position in Flutter from a service.

Getting your position in Flutter is a simple task. This tutorial will show you how to wrap location packages into services that are easy to use in your applications. Create a new Flutter project and continue.

Set up the

Provider is my default dependency Provider/state management solution, so we’ll use that as well. We add these two packages to the pubspec.yaml file.

The provider: ^ 3.0.0 location: ^ 2.3.5Copy the code

The android

Add location permissions to the manifest outside of the androidmanifest.xml application tag.

. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application android:name="io.flutter.app.FlutterApplication" android:label="The Guardian" android:icon="@mipmap/ic_launcher"> ... </application> ...Copy the code

Update your gradle.properties file to do this

android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
Copy the code

Update your build.gradle file dependencies to this

Dependencies {classpath 'com. Android. View the build: gradle: 3.3.0' classpath 'com. Google. GMS: Google - services: 4.2.0'}Copy the code

And make sure your compileSdkVersion is 28.

IOS

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>This app requires access to your location for FilledStacks tutorial.</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>This app requires access to your location for FilledStacks tutorial.</string>
Copy the code

That’s all the setup is done. If you run into problems with AndroidX, be sure to migrate or use an older version of this package if you don’t want to.

The service implementation

If there’s one thing I can recommend, it’s reading the single responsibility principle. Based on this, I developed the habit of building applications with single-purpose services that are injected/positioned as needed. Let’s create our LocationService. This service will:

  1. Provide a constant stream of updates that we can rely on
  2. Provides a function that performs a one-time request on the current location

Create a new file called location_service.dart in the Services folder. We’ll start by adding a single request function that getLocation() can use for a one-time retrieval.

import 'package:location/location.dart'; class LocationService { UserLocation _currentLocation; var location = Location(); Future<UserLocation> getLocation() async { try { var userLocation = await location.getLocation(); _currentLocation = UserLocation( latitude: userLocation.latitude, longitude: userLocation.longitude, ); } on Exception catch (e) { print('Could not get location: ${e.toString()}'); } return _currentLocation; }}Copy the code

We will also introduce our own Location model to ensure that our external code does not depend on the package representation of the model. Create a new file called user_Location.dart under the models folder

class UserLocation {
  final double latitude;
  final double longitude;
​
  UserLocation({this.latitude, this.longitude});
}
Copy the code

Now let’s add a Stream that sends us all user location updates. All of the following code is in the location service.

StreamController<UserLocation> _locationController = StreamController<UserLocation>(); Stream<UserLocation> get locationStream => _locationController.stream; LocationService() { // Request permission to use location location.requestPermission().then((granted) { if (granted) { // If granted listen to the onLocationChanged stream and emit over our controller location.onLocationChanged().listen((locationData) { if (locationData ! = null) { _locationController.add(UserLocation( latitude: locationData.latitude, longitude: locationData.longitude, )); }}); }}); }Copy the code

This service is intended to control view state and process logical objects, not the view itself. Having said that, to keep this tutorial short and in scope, I’ll just pass it on to the providers to show how we can use it. We’ll wrap the main application using StreamProvider and provide the flow to the builder from LocationService.

class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return StreamProvider<UserLocation>( builder: (context) => LocationService().locationStream, child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: HomeView(), )), ); }}Copy the code

And then HomeView we’re going to take that stream and print out the location value.

class HomeView extends StatelessWidget { const HomeView({Key key}) : super(key: key); @override Widget build(BuildContext context) { var userLocation = Provider.of<UserLocation>(context); return Center( child: Text( 'Location: Lat${userLocation? .latitude}, Long: ${userLocation? .longitude}'), ); }}Copy the code