B4A Library FusedLocationProvider

FusedLocationProvider is Android's latest attempt to improve the location services available to your applications.

Official documentation can be found here: https://developer.android.com/google/play-services/location.html.

This library depends on the Google Play Services library, android-support-v4 library and the GPS library.
The GPS library is required in order to use it's Location object.

FusedLocationProvider
Events:

  • ConnectionFailed (ConnectionResult1 As Int)
  • ConnectionSuccess
  • ConnectionSuspended (SuspendedCause1 As Int)
  • LocationChanged (Location1 As Location)
  • LocationSettingsChecked (LocationSettingsResult1 As LocationSettingsResult)
Fields:
  • ConnectionResult As ConnectionResult
    Contains the various ConnectionResult constants.
  • SuspendedCause As SuspendedCause
    Contains the various SuspendedCause constants.
Methods:
  • CheckLocationSettings (LocationSettingsRequest1 As LocationSettingsRequest)
    Checks if the relevant system settings are enabled on the device to carry out the desired location requests.
    Raises the event:
    LocationSettingsChecked(LocationSettingsResult1 As LocationSettingsResult)
  • Connect
    Attempt to connect to the Location Services.
    Will raise either event:
    ConnectionFailed(ConnectionResult1 As Int)
    ConnectionSuccess
  • Disconnect
    Disconnect from the Location Services.
  • GetLastKnownLocation As Location
    Returns the best most recent location currently available.
    Can only be called if the FusedLocationProvider is connected.
    The returned Location object will not be initialized if no last known location is available.
  • Initialize (EventName As String)
    Initialize the FusedLocationProvider object.
  • IsConnected As Boolean
    Returns whether the FusedLocationProvider is connected to the Location Services.
  • IsConnecting As Boolean
    Returns whether the FusedLocationProvider is trying to connect to the Location Services.
  • IsInitialized As Boolean
  • RemoveLocationUpdates
    Remove all requests for location updates.
  • RequestLocationUpdates (LocationRequest1 As LocationRequest)
    Request for location updates.
    The LocationRequest object defines the criteria for which location updates are requested.

This is the main library object.
You call the FusedLocationProvider Initialize method and then it's Connect method.
It will then raise the ConnectionFailed event or the ConnectionSuccess event.
Assuming the ConnectionSuccess event is raised you can now call:
  • GetLastKnownLocation As Location
  • RequestLocationUpdates (LocationRequest1 As LocationRequest)

So you could connect, get the last known location and then disconnect.
There is no requirement to request location updates.
This is a quick and simple way to get the device location.

Or you could connect then initialize and configure a LocationRequest object and then request location updates.
The LocationRequest object has various methods you can call to configure the request for location updates:

LocationRequest
Fields:

  • Priority As Priority
    Contains the various priority constants.
Methods:
  • GetExpirationTime As Long
    Get the request expiration time, in milliseconds since boot.
  • GetFastestInterval As Long
    Get the fastest interval of this request, in milliseconds.
  • GetInterval As Long
    Get the desired interval of this request, in milliseconds.
  • GetNumUpdates As Int
    Get the number of updates requested.
  • GetPriority As Int
    Get the quality of the request.
  • GetSmallestDisplacement As Float
    Get the minimum displacement between location updates in meters.
    By default this is 0.
  • Initialize
    Initialize the LocationRequest with default parameters.
    Default parameters are for a block accuracy, slowly updated location.
  • IsInitialized As Boolean
  • SetExpirationDuration (Millis As Long) As LocationRequest
    Set the duration of this request, in milliseconds.
  • SetExpirationTime (Millis As Long) As LocationRequest
    Set the request expiration time, in millisecond since boot.
  • SetFastestInterval (Millis As Long) As LocationRequest
    Explicitly set the fastest interval for location updates, in milliseconds.
  • SetInterval (Millis As Long) As LocationRequest
    Set the desired interval for active location updates, in milliseconds.
  • SetNumUpdates (NumUpdates As Int) As LocationRequest
    Set the number of location updates.
  • SetPriority (Priority As Int) As LocationRequest
    Set the priority of the request.
  • SetSmallestDisplacement (SmallestDisplacementMeters As Float) As LocationRequest
    Set the minimum displacement between location updates in meters.
    By default this is 0.

It is important to note that part of the criteria that defines your request for a location is the location permission that you (manually) set in the manifest file.
This library does not automatically add any permission to your manifest and this library will fail to work if you do not manually add a required permission to your manifest file.

You can add one of two permissions to your manifest:
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION

See: https://developer.android.com/training/location/retrieve-current.html
Apps that use location services must request location permissions.
Android offers two location permissions: ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION.
The permission you choose determines the accuracy of the location returned by the API.
If you specify ACCESS_COARSE_LOCATION, the API returns a location with an accuracy approximately equivalent to a city block.

Also note that as this library uses the Google Play Services library, you must also add this entry to your manifest:

B4X:
AddApplicationText(<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />)

Two versions of the library are attached.
  • If you're using a version of Google Play Services older than version 27 then you need to use FusedLocationProvider version 1.10.
  • If you're using Google Play Services version 27 or newer then you need to use FusedLocationProvider version 1.30 or newer

Martin.

Edit by Erel:
Add these two lines if using with B4A v6+:
B4X:
#AdditionalJar: com.android.support:support-v4
#AdditionalJar: com.google.android.gms:play-services-location
New example where FLP is managed from the starter service: https://www.b4x.com/android/forum/threads/fusedlocationprovider.50614/post-717726
 

Attachments

  • FusedLocationProvider_library_files_v1.10.zip
    19.3 KB · Views: 2,043
  • FusedLocationProvider_library_files_v1.31.zip
    20 KB · Views: 3,066
Last edited by a moderator:

warwound

Expert
Licensed User
Longtime User
A common mistake is to download the latest version of Google Play Services using the SDK Manager but forget to copy the downloaded (latest version) google-play-services.jar file from the android SDK folder to your b4a additional libraries folder.
 

leongcc

Member
Licensed User
Longtime User
I am trying out this library and FusedLocationProviderExample but it is not working.
It compiles (debug and release build) and run without error but the connection always fail with ConnectionResult1=2 (meaning 'service version update required') at function:
Sub FusedLocationProvider1_ConnectionFailed(ConnectionResult1 As Int)

I have already ensured Google Service jar is updated in AddLibraries.
Any advice is appreciated, thanks.
 

iz0ndg

Active Member
Licensed User
Longtime User
Hi
I have updated Google Play Services to version 27 and my app now crashes with the error :

B4X:
** Service (locationmonitor) Create **
locationmonitor_service_create (java line: 249)
java.lang.NoSuchMethodError: com.google.android.gms.common.api.GoogleApiClient.connect
   at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Connect(FusedLocationProviderWrapper.java:147)
   at com.idranti_mod.giordanif.locationmonitor._service_create(locationmonitor.java:249)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
   at com.idranti_mod.giordanif.locationmonitor.onCreate(locationmonitor.java:53)
   at android.app.ActivityThread.handleCreateService(ActivityThread.java:2857)
   at android.app.ActivityThread.access$1900(ActivityThread.java:172)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1390)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:146)
   at android.app.ActivityThread.main(ActivityThread.java:5692)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
   at dalvik.system.NativeStart.main(Native Method)

Any idea ?
 

warwound

Expert
Licensed User
Longtime User
Hi
I have updated Google Play Services to version 27 and my app now crashes with the error :

B4X:
** Service (locationmonitor) Create **
locationmonitor_service_create (java line: 249)
java.lang.NoSuchMethodError: com.google.android.gms.common.api.GoogleApiClient.connect
   at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Connect(FusedLocationProviderWrapper.java:147)
   at com.idranti_mod.giordanif.locationmonitor._service_create(locationmonitor.java:249)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
   at com.idranti_mod.giordanif.locationmonitor.onCreate(locationmonitor.java:53)
   at android.app.ActivityThread.handleCreateService(ActivityThread.java:2857)
   at android.app.ActivityThread.access$1900(ActivityThread.java:172)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1390)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:146)
   at android.app.ActivityThread.main(ActivityThread.java:5692)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
   at dalvik.system.NativeStart.main(Native Method)

Any idea ?

Can you try the attached update?
I've tested the update on my Moto G (lollipop) and it works for me.
 

marcel

Active Member
Licensed User
Longtime User
Hi,

I am using this great library and used the example in my program. But I have now complains about the extreme battery use. What is the best I can do, I played with the SetSmallestDisplacement and
SetInterval but it don't help a lot. I need to have a least updates in 500 meter and every 30 seconds.
 

rboeck

Well-Known Member
Licensed User
Longtime User
Hi, i tried the 1.2 update, but currently use google play version 26.

At compile time i get:
java.lang.IncompatibleClassChangeError: The method 'void com.google.android.gms.common.api.GoogleApiClient.connect()' was expected to be of type virtual but instead was
found to be of type interface (declaration of 'java.lang.reflect.ArtMethod' appears in /system/framework/core-libart.jar)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Connect(FusedLocationProviderWrapper.java:147)
at at.rb.b4a.gmap1.adressliste._activity_resume(adressliste.java:911)

Then i replaced back the older 1.1 lib; all worked like before.
I hope, my log is usefull.
 

warwound

Expert
Licensed User
Longtime User
@rboek

That's odd.
After updating to the latest version of Google Play Services i got the same exception:

java.lang.IncompatibleClassChangeError: The method 'void com.google.android.gms.common.api.GoogleApiClient.connect()' was expected to be of type virtual but instead was
found to be of type interface (declaration of 'java.lang.reflect.ArtMethod' appears in /system/framework/core-libart.jar)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Connect(FusedLocationProviderWrapper.java:147)

A little research led me to a page that described how the latest Google Play Services had some changes made - i recompiled the b4a library and now everything worked as expected.

In theory version 1.10 of the b4a library should not work with the latest version of Google Play Services.
And version 1.20 of the b4a library should not work with versions of Google Play Services prior to the current latest version.

Let's wait and see what other users report...
 

warwound

Expert
Licensed User
Longtime User
Hi,

I am using this great library and used the example in my program. But I have now complains about the extreme battery use. What is the best I can do, I played with the SetSmallestDisplacement and
SetInterval but it don't help a lot. I need to have a least updates in 500 meter and every 30 seconds.

I'm not sure what to suggest.
Frequent updates over any significant period is obviously gonna drain the device battery to some noticeable extent.
The question is whether or not you can tweak your location listening to further reduce the battery drain.

Look at post #1 of this thread - look at the documentation for the LocationRequest object.
You can set 'fastest interval', 'interval', 'priority' and 'smallest displacement' parameters.
What values are you setting for these parameters?
 

marcel

Active Member
Licensed User
Longtime User
I'm not sure what to suggest.
Frequent updates over any significant period is obviously gonna drain the device battery to some noticeable extent.
The question is whether or not you can tweak your location listening to further reduce the battery drain.

Look at post #1 of this thread - look at the documentation for the LocationRequest object.
You can set 'fastest interval', 'interval', 'priority' and 'smallest displacement' parameters.
What values are you setting for these parameters?

I think I was not clear. For me it was not clear what function you can play with to have less battery drain, I have done now the following:

B4X:
    LocationRequest1.SetInterval(10000)    '    1000 milliseconds
    LocationRequest1.SetPriority(LocationRequest1.Priority.PRIORITY_BALANCED_POWER_ACCURACY)
    LocationRequest1.SetSmallestDisplacement(100)    '    1 meter

as I hope this will reduce the battery drain.
 

iz0ndg

Active Member
Licensed User
Longtime User
Can you try the attached update?
I've tested the update on my Moto G (lollipop) and it works for me.

Hi warwound,
Sorry for the delay, I was at work.
Tested on my Note 3 Neo (4.4.2) and OnePlus One (5.1.1)
Everything works perfectly.;)

However, as I understand it, this version works only with version 27 of Google Play Services on, right?

Tnks!
 

warwound

Expert
Licensed User
Longtime User
However, as I understand it, this version works only with version 27 of Google Play Services on, right?

Yes.
  • If you're using a version of Google Play Services older than version 27 then you need to use FusedLocationProvider version 1.10.
  • If you're using Google Play Services version 27 then you need to use FusedLocationProvider version 1.20.
 

iz0ndg

Active Member
Licensed User
Longtime User
Yes.
  • If you're using a version of Google Play Services older than version 27 then you need to use FusedLocationProvider version 1.10.
  • If you're using Google Play Services version 27 then you need to use FusedLocationProvider version 1.20.

Ok. Thank's ! :D
 

CMH

Member
Licensed User
Longtime User
I got the following run time error using the library version 1.2 and the sample you provided. My Google Play Services is version 27. My SDK version screenshot is included for your reference. Thanks.

BTW, I have updated both Intel x86 Atom_64 and Google APIs system images yesterday. It was working fine before.
 

Attachments

  • 111.png
    111.png
    91.8 KB · Views: 270
  • 222.png
    222.png
    47.6 KB · Views: 240
Last edited:

warwound

Expert
Licensed User
Longtime User
I got the following run time error using the library version 1.2 and the sample you provided. My Google Play Services is version 27. My SDK version screenshot is included for your reference. Thanks.

BTW, I have updated both Intel x86 Atom_64 and Google APIs system images yesterday. It was working fine before.

First thing to do is test it on a real device.
That way you can establish whether the problem is the android emulator (i think this will be the case) or a problem in the b4a code.
 

trueboss323

Active Member
Licensed User
Longtime User
My app seems to crash everytime it uses the fusedlocationprovider:

B4X:
java.lang.NoSuchMethodError: com.google.android.gms.common.api.GoogleApiClient.connect
 

imbault

Well-Known Member
Licensed User
Longtime User
Hi @warwound, ready to make you a donation, the google version of google play service is now 28, does your lib fits it, please?
And, by the way, what is the min. version of the Android SDK to use it?

Thanks and Kind regards.

Patrick
 

imbault

Well-Known Member
Licensed User
Longtime User
Using 1.20 version of FusedLocationProvider with google play service SDK V28
I've got :
** Activity (main) Create, isFirst = true **
main_activity_create (java line: 325)
java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/util/ArrayMap;
at com.google.android.gms.common.api.GoogleApiClient$Builder.<init>(Unknown Source)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProvider.<init>(FusedLocationProvider.java:36)
at uk.co.martinpearman.b4a.fusedlocationprovider.FusedLocationProviderWrapper.Initialize(FusedLocationProviderWrapper.java:172)
at uk.co.martinpearman.b4a.fusedlocationproviderexample.main._activity_create(main.java:325)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at uk.co.martinpearman.b4a.fusedlocationproviderexample.main.afterFirstLayout(main.java:102)
at uk.co.martinpearman.b4a.fusedlocationproviderexample.main.access$000(main.java:17)
at uk.co.martinpearman.b4a.fusedlocationproviderexample.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.util.ArrayMap" on path: DexPathList[[zip file "/data/app/uk.co.martinpearman.b4a.fusedlocationproviderexample-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
... 18 more
Suppressed: java.lang.ClassNotFoundException: android.support.v4.util.ArrayMap
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 19 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
 

Anser

Well-Known Member
Licensed User
Longtime User
FusedLoactionProvider 1.20 along with Google Play Service V28 is working fine for me.

Yesterday evening I updated my Google Play Service to V28. So far its working fine for me.

Regards
Anser
 

warwound

Expert
Licensed User
Longtime User
@imbault

Look at post #51, that details which version of the library is required for the version of Google Play Services you are using.
Device requirements are android api 8 and higher, see http://developer.android.com/training/location/index.html.

The exception you posted is saying that the android.support.v4.util.ArrayMap class cannot be found.
This class is not used in the FusedLocationProvider library - FusedLocationProvider does not depend on that support library.
So you must be using another library that does depend on the v4 support library.

Can you look at the other libraries used in your project and try to work out which one of them requires the v4 support library?
 
Top