google maps for android crashes in xamarin.forms - google-maps

I am rendering the google maps for android
The first time I load a page with google maps it works, but when I close the page and reopen it, I get the exception:
System.NotSupportedException: Unable to activate instance of type SmartScout.Droid.CustomMapRenderer from native handle 0xcc700019 (key_handle 0x433fb7f8).
I see that the OnElementChanged in the MapRenderer is called twice and the second time it crashes with the exception above.
my code is:
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
return;
//map.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
//customPins = formsMap.CustomPins;
((MapView)Control).GetMapAsync(this);
}
}
Any solutions?

Change this
((MapView)Control).GetMapAsync(this);
and add this code
var androidMapView = (MapView)Control;
My full working code is following
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
var formsMap = (ExtendedMap)e.NewElement;
var androidMapView = (MapView)Control;
if (androidMapView != null && androidMapView.Map != null)
{
androidMapView.Map.InfoWindowClick += MapOnInfoWindowClick;
}
if (formsMap != null)
{
//code for run first time only
}
}

Related

Xamarin Forms - custom map marker not visible

I am following article on MS page about Custom map renderer and I can not get it to work for android. Map shows but pins (Markers) are not there. I did not found what I did different from official documents (as in previous link). When I debug, there are 3 markers in customPins collection. And custom renderer works in UWP. So issue is only in Android code.
Here is my CustomRender code for Android which does not shows pins.
using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using iVanApp;
using iVanApp.Android.CustomMapRenderers;
using iVanApp.Droid;
using iVanApp.Model;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(NightMap), typeof(MapRenderers))]
namespace iVanApp.Android.CustomMapRenderers
{
public class MapRenderers : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<NightPin> customPins;
public MapRenderers(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (NightMap)e.NewElement;
customPins = formsMap.NightPins;
}
}
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
protected override MarkerOptions CreateMarker(Pin pin)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Name))
{
}
}
NightPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
public global::Android.Views.View GetInfoContents(Marker marker)
{
var inflater = global::Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as global::Android.Views.LayoutInflater;
if (inflater != null)
{
global::Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
view = inflater.Inflate(Resource.Layout.mtrl_layout_snackbar_include, null);
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public global::Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
}
}
DOes anyone have idea why this would not work?
Note: I had to modify official MS code because I got errors. Wherever is Android.Views.View I had to modify it to global::Android.Views.View otherwise I got following error
"'MapRenderers' does not implement interface member
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)'.
'MapRenderers.GetInfoContents(Marker)' cannot implement
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)' because it does
not have the matching return type of 'View'.".
and
The type or namespace name 'Views' does not exist in the namespace
'iVanApp.Android' (are you missing an assembly reference?)
Hope this did not break my code.
After investigating and reading about custom map issues (and mostly solutions) from others I got a workaround solution how to get pins on map but does not show info window when I click on pin(marker). Here I found workaround. If I modify OnMapReday and call&add method SetMapMarkers then pins are visible but as I said no info window is shown when I click on pin
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
SetMapMarkers();
}
private void SetMapMarkers()
{
NativeMap.Clear();
foreach (var pin in customPins)
{
NativeMap.AddMarker(CreateMarker(pin));
}
}
Although this is solution, I would prefer if I could get it to work without this workaround. Hence I did not put much effort why info window is not shown when you click on pin. In case there would be no solution without this workaround then I will be interested in solution with workaround but as I said I do not prefer to go this way.
As FreakyAli said that adding a custom pin and positions for CustomMap.
<local:CustomMap x:Name="customMap" MapType="Street" />
Adding a custom pin and positions the map's view with the MoveToRegion method
public MainPage()
{
InitializeComponent();
var pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA",
Id = "Xamarin",
Url = "http://xamarin.com/about/"
};
customMap.CustomPins = new List<CustomPin> { pin };
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
I can get InfoWindow by clicking map pin, having no problem.

How can I create an PhpStorm hotkey to switch between controller and view/template in custom framework

The framework layout is like the following
/modules/module_name/controller_name.php
/modules/module_name/templates/controller_name.php
The controller and (view / template) always has the same name.
Is there anyway to create a hotkey to switch between the two?
I created a plugin with the following action and its working well.
#Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
VirtualFile vFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
String fileName = vFile != null ? vFile.getName() : null;
if(fileName == null){
return;
}
String filePath = vFile.getPath();
String fileDirectory = filePath.replace(fileName,"");
String newPath;
if(fileDirectory.contains(File.separator+"templates"+File.separator)){
newPath = filePath.replace("templates"+File.separator+fileName,fileName);
}else{
newPath = filePath.replace(fileName,"templates"+File.separator+fileName);
}
VirtualFile newVFile = com.intellij.openapi.vfs.LocalFileSystem.getInstance().findFileByPath(newPath);
if (newVFile == null) {
return;
}
FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
fileEditorManager.openFile(newVFile,true,true);
}

Xamarin Forms - Highlight route for WinPhone 8.1 part

Since a long time, I'm trying to make work a polyline for crossplateform using.
I did it and it works well, I followed the Map Control tutorial in first, and then Highlight a Route on a Map tutorial.
I then update the code to make it reloads if a any changes comes, however, I'm getting an issue and I couldn't figure it out... It does works for Android & iOS.
polyline.Path = new Geopath(coordinates); throws Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
The problem is that my two others renderer (Android & iOS) works.. Maybe something isn't possible because I work with WinPhone8.1 unlike the tutorial, which is UWP.
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (nativeMap != null)
{
var coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
var polyline = new MapPolyline();
polyline.StrokeColor = Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polyline);
}
}
}
I also read that a key is needed, so maybe I doesn't use this key in a good way.. I tried with UWP Public Key and WinPhone8.X and earlier Key, but without success too..
Does someone has an idea? This part a really big problem in my app..
Thank in advance !
After a long time, I found why it didn't works...
If you're doing like me, if you do a HttpRequest to something as Google Direction API, then the result will comes after the first passage in the OnElementChanged().
Because formsMap.RouteCoordinates isn't null but empty, the Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) is thrown..
This is the good CustomMapRenderer for PolyLine use
using PROJECT;
using PROJECT.UWP;
using System.Collections.Generic;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.UWP;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (formsMap != null && formsMap.RouteCoordinates.Count > 0)
{
List<BasicGeoposition> coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
Geopath path = new Geopath(coordinates);
MapPolyline polyline = new MapPolyline();
polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = path;
nativeMap.MapElements.Add(polyline);
}
}
}
}

Windows phone 8, Check if wifi is on?

I'm trying to make a joke app for windows phone. The app gets jokes from the internet so, I want it to be able to check if wifi signal or is able to connect to the internet. How will I go about creating that?
In WP8.1 runtime you can query most of this stuff from NetworkInformation class like so:
// need this namespace
using Windows.Networking.Connectivity;
bool is_wifi_connected = false;
ConnectionProfile current_connection_for_internet = NetworkInformation.GetInternetConnectionProfile();
if (current_connection_for_internet.IsWlanConnectionProfile)
{
if (current_connection_for_internet.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess)
{
is_wifi_connected = true;
}
}
WP8.0 You can query most of this stuff from the NetworkInterfaceList like so:
// see is wifi is ON and connected
using Microsoft.Phone.Net.NetworkInformation;
bool is_wifi_connected = false;
if (NetworkInterface.GetIsNetworkAvailable())
{
NetworkInterfaceList nif = new NetworkInterfaceList();
foreach(NetworkInterfaceInfo item in nif)
{
if (item.InterfaceSubtype == NetworkInterfaceSubType.WiFi && item.InterfaceState == ConnectState.Connected)
{
is_wifi_connected = true;
}
}
}
Now to see if it can connect to the website just open a connection. You can use any web connection you like. Just going to do this with a WebClient and an event handler when the file is done downloading.
using System.Net;
// check network and is_wifi_connected
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() && is_wifi_connected)
{
WebClient downloader = new WebClient();
Uri uri = new Uri("http://www.google.com", UriKind.Absolute);
downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(DownloadDone);
downloader.DownloadStringAsync(uri);
}
void DownloadDone(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Result == null || e.Error != null)
{
MessageBox.Show("There was an error downloading the site.");
}
else
{
// your html file or what not is stored here
string content = e.Result;
}
}

securityexception was unhandled

I am simply trying to parse json using the foursquare venues API and make make some location visible in a list box in my windowphone application but I keep getting the error securityexception was unhandled when I run this line of code.
var providerResult = (Venues.RootObject)dataContractJsonSerializer.ReadObject(stream);
in
private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
if (e.Error == null) {
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(e.Result))) {
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Venues.RootObject));
var providerResult = (Venues.RootObject)dataContractJsonSerializer.ReadObject(stream);
if (providerResult == null) {
MessageBox.Show("No location were found");
}
else {
locations.ItemsSource = providerResult.response.venues;
}
}
}
else {
MessageBox.Show(e.Error.Message);
}
}