1

I' have a very strange issue with Xamarin.Forms.Maps. I'm trying to implement a page with a map that get current location and move to region at page start.

All is working fine in IOS, but in Android, Geocoder & MoveToRegion are not working at all. Only the map is displayed.

I retrieve the location correctly (Long & Lat ) in the emulators & device. MoveToRegion do nothing & GetAddressesForPositionAsync retrive nothing.

Here the information in my manifest :

<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="mykey" />
        <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Here the code :

map.MoveToRegion(MapSpan.FromCenterAndRadius(
                new Xamarin.Forms.Maps.Position(coordinates.Lat.Value, coordinates.Lng.Value), Distance.FromMiles(1))
            );

        var possibleAddresses = await locator.GetAddressesForPositionAsync(position);

I tried in Genymotion, Emulator from AVD. I'm not able to test in real device ( The deployment fail in my tablet )

Edit :

global::Xamarin.Forms.Forms.Init(this, bundle);

Was correctly set but still not working.

I force geocoder usage and it thrown this error :

[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] Java.IO.IOException: grpc failed
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <6cd960837cc24c26bab2a0a29b597627>:0 
[MonoDroid]   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeAbstractObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <6cd960837cc24c26bab2a0a29b597627>:0 
[MonoDroid]   at Android.Locations.Geocoder.GetFromLocationName (System.String locationName, System.Int32 maxResults) [0x0003c] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Android.Locations.Geocoder+<>c__DisplayClass17_0.<GetFromLocationNameAsync>b__0 () [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Threading.Tasks.Task.Execute () [0x00010] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Xamarin.Forms.Maps.Android.GeocoderBackend+<GetPositionsForAddressAsync>d__1.MoveNext () [0x0006b] in <39c694c022be4f7b8a39897d372b2d00>:0 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Picaplant.Views.GeolocationPage+<HandleAdressCompleted>d__8.MoveNext () [0x00047] in /Users/OrcusZ/Documents/AutoEntrepreneur/Picaplant/Source/Picaplant/Views/GeolocationPage.xaml.cs:158 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at (wrapper dynamic-method) System.Object:6621ff63-14b8-4291-a222-45bff630bddc (intptr,intptr)
[MonoDroid]   --- End of managed Java.IO.IOException stack trace ---
[MonoDroid] java.io.IOException: grpc failed
[MonoDroid]     at android.location.Geocoder.getFromLocationName(Geocoder.java:178)
[MonoDroid] 

EDIT 2 :

Same error with Xamarin Form Working with maps sample

Any idea ?

OrcusZ
  • 3,555
  • 2
  • 31
  • 48
  • `mykey` means you have add the key? And I think we'd likely need to see some code to help you pinpoint the problem. – York Shen Aug 22 '17 at 06:57
  • Yes, I hide the true key with the work mykey to do not display it. The map display correctly, i'm able to interact with it. – OrcusZ Aug 22 '17 at 07:48
  • Try to deploy on a real deice, if there is any problem, please feel free to ask. – York Shen Aug 22 '17 at 08:47
  • Ok, I will try on a tablet. – OrcusZ Aug 22 '17 at 09:24
  • @YorkShen-MSFT Same issue in the tablet – OrcusZ Aug 23 '17 at 16:20
  • Have you checked with breakpoints to see if any error happens and they just pass something? – Jordy Dieltjens Aug 24 '17 at 13:07
  • Do you have location tracking enabled on the device that you test with? – Jordy Dieltjens Aug 24 '17 at 13:08
  • no errors are throwns, juste nothing happens. I can have a look to the output console. – OrcusZ Aug 24 '17 at 14:05
  • Both `Geocoder` and `MoveToRegion` worked just fine in a **Samsung Android** device. This is for a portable cross-platform app. – jsanalytics Aug 25 '17 at 00:13
  • That possible that my Google map API is bad configurer ? Should I need Google Places for geocoder ? – OrcusZ Aug 25 '17 at 05:19
  • I did remove an IP restriction I had in my Maps API key, setting it to none. I do have Maps Geocoding and Google Places APIs, but the dashboard shows no traffic for these, so it doesn't seem they are being used. Neither do I have any related assembly in my project. – jsanalytics Aug 25 '17 at 11:54
  • 1
    One piece of boilerplate code I had to "manually" add to my **App.Android** project, in the `OnCreate` method for `MainActivity.cs` : `global::Xamarin.FormsMaps.Init(this, bundle);`. – jsanalytics Aug 25 '17 at 11:58
  • 1
    `MoveToRegion` also works in my **KitKat 4.4 API Level 19** emulator. [THIS ARTICLE](http://www.alteridem.net/2017/02/02/installing-google-play-gapps-visual-studio-android-emulators/) is helpful setting it up. – jsanalytics Aug 25 '17 at 16:05
  • 1
    `Geocoder` returns an empty address list in the same emulator though. Look at [THIS POST](https://stackoverflow.com/questions/21061175/does-the-geocoder-work-on-emulators). – jsanalytics Aug 25 '17 at 16:07
  • I will have a look to this. thanks – OrcusZ Aug 25 '17 at 18:27

1 Answers1

2

Here's a working cross-platform sample app. It runs in a KitKat 4.4 API Level 19 emulator and also in a Samsung Android device. We also present a custom Geocoder implementation using HTTP requests given that the standard one works fine for an actual Android device but returns an empty response for the emulator.

enter image description here

XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:Maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps.dll"
             xmlns:local="clr-namespace:App20"
             x:Class="App20.MainPage">
    <ContentPage.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="8*"></RowDefinition>
                <RowDefinition Height="4*"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>

            <Maps:Map x:Name="map1" Grid.Row="0"></Maps:Map>
            <ListView ItemsSource="{Binding AddressList}" Grid.Row="1" />
            <Button Text="Move To Region" Grid.Row="2" Clicked="Button_Clicked_Move"></Button>
            <Button Text="Get Address" Grid.Row="3" Clicked="Button_Clicked_Address"></Button>
        </Grid>
    </ContentPage.Content>
</ContentPage>

CS:

public partial class MainPage : ContentPage
{
    MyViewModel vm;

    public MainPage()
    {
        InitializeComponent();

        vm = new MyViewModel();
        BindingContext = vm;
    }

    private void Button_Clicked_Move(object sender, EventArgs e)
    {
        map1.MoveToRegion(MapSpan.FromCenterAndRadius(
            new Position(vm.Lat, vm.Lon), Distance.FromMiles(vm.Distance)));
    }

    private async void Button_Clicked_Address(object sender, EventArgs e)
    {
        Geocoder gc = new Geocoder();

        var list = await gc.GetAddressesForPositionAsync(new Position(vm.Lat, vm.Lon));

        if (list.Count() > 0)
        {
            foreach (string s in list)
                vm.AddressList.Add(s);
        }
        else
        {
            MyGeocoder mgc = new MyGeocoder();

            var mylist = await mgc.GetAddressesForPositionAsync(vm.Lat, vm.Lon, vm.Key);

            foreach (string s in mylist)
                vm.AddressList.Add(s);
        }
    }
}

View Model:

public class MyViewModel
{
    public string Key { get; }
    public double Lat { get; set; }
    public double Lon { get; set; }
    public double Distance { get; set; }
    public ObservableCollection<string> AddressList { get; set; }

    public MyViewModel()
    {
        Lat = 40.706501;
        Lon = -74.011340;
        Distance = 0.5;
        Key = "YOUR_API_KEY";
        AddressList = new ObservableCollection<string>();
    }
}

Custom Geocoder:

public class MyGeocoder
{
    public async Task<IEnumerable<string>> GetAddressesForPositionAsync(double lat, double lon, string key)
    {
        HttpClient client = new HttpClient();

        var request = string.Format(@"https://maps.googleapis.com/maps/api/geocode/json?latlng={0},{1}&key={2}", lat, lon, key);

        var json = await client.GetStringAsync(request);

        var result = JObject.Parse(json)["results"];

        List<string> list = new List<string>();

        foreach (JToken jt in result)
            list.Add((string)jt["formatted_address"]);

        return list.AsEnumerable<string>();
    }
}
jsanalytics
  • 13,058
  • 4
  • 22
  • 43
  • Thanks to you, I find that the issue comes from my map Custom Renderer to implement a Tap event. Now I can find a solution ^^ – OrcusZ Aug 26 '17 at 07:21
  • If by _not working_ you mean an _empty response_, that's more likely due to the fact that Google Play for emulators don't come with the necessary backing service, as pointed out in the articles linked before. If you're still getting an exception though, you should post an [MCVE](https://stackoverflow.com/help/mcve) and for sure you would get help much faster with more people willing to help. – jsanalytics Aug 26 '17 at 11:25
  • If i put a breakpoint, it never go to next step. You can have a look to this fresh post about my geocode error https://stackoverflow.com/questions/45894719/xamarin-forms-geocode-android – OrcusZ Aug 26 '17 at 12:06
  • 1
    Does it work without wrapping it in a `Task`? You need to take incremental troubleshooting steps to isolate the problem. – jsanalytics Aug 26 '17 at 12:15
  • Same thing without the Task. Your implementation will work but I will have a request limitation :/ – OrcusZ Aug 26 '17 at 14:22
  • I'm not even sure you would benefit from spawning a new `Task` here... Take a look at [THIS ARTICLE](https://msdn.microsoft.com/library/hh191443(vs.110).aspx#Threads), in particular, **IO-bound** and **CPU-bound** work. Here's an excerpt of interest from the article: _You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available._ `Geocoder` methods are clearly **IO-Bound**, given that it will make HTTP calls to the corresponding google APIs. – jsanalytics Aug 26 '17 at 23:45
  • Thanks for the article. I will have a look and try to find why is not working. Thanks a lot for your time – OrcusZ Aug 27 '17 at 05:26