自定义 MapBox Android 渲染器 - 更改选项卡时崩溃

Custom MapBox Android Renderer - crash when change tabs

我正在尝试使用 naxam 库在 Xamarin Forms 中为 Android 创建一个 MapBox 渲染器。 地图作为选项卡中视图的内容显示良好,但是当我多次更改选项卡时,它会在 android 模拟器上崩溃。我想问题出在渲染器上,但不知道出在哪里。

这是我的部分代码:

public class MapViewRenderer : ViewRenderer<ContentView, Android.Views.View>,
    IOnMapReadyCallback, Com.Mapbox.Mapboxsdk.Maps.Style.IOnStyleLoaded
{
    private MapView _mapView = null;
    private MapboxMap _mapBox = null;
    public MapViewRenderer(Context context) : base(context)
    {
        Mapbox.GetInstance(Context, "pk.###");
    }


    public void OnMapReady(MapboxMap p0)
    {
        _mapBox = p0;
        [...]
    }
    public void OnStyleLoaded(Com.Mapbox.Mapboxsdk.Maps.Style p0)
    {
        [...]
    }
    protected override void OnElementChanged(ElementChangedEventArgs<ContentView> e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            _mapView = new MapView(Context);
            _mapView.GetMapAsync(this);
            view.Content = _mapView.ToView();
        }
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _mapView.Dispose();
        }
        base.Dispose(disposing);
    }
}

我在网上阅读的所有示例都是关于在主 activity 中使用 OnCreate、OnStart、OnResume 创建 MapView 的...我还没有找到任何关于在自定义渲染中创建地图的信息。

请帮忙。

编辑:

--------------------------------解决方案------------ ----------------------

问题已在自定义渲染器中使用以下代码修复。此外,渲染器使用了一个 Mapview 实例,该实例已根据 ToolmakerSteve 的评论移入主 activity。

MapViewRenderer.cs :

public class MapViewRenderer : ViewRenderer<ContentView, Android.Views.View>
{
    public MapViewRenderer(Context context) : base(context)
    {}

    protected override void OnElementChanged(ElementChangedEventArgs<ContentView> e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            var view = e.NewElement as Views.Map;
            if (Control == null)
            {
                SetNativeControl(MainActivity.MainActivityInstance.MapView);
            }
        }
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            MainActivity.MainActivityInstance.MapView.RemoveFromParent();
        }
        base.Dispose(disposing);
    }
}

MainActivity.cs :

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IOnMapReadyCallback, Style.IOnStyleLoaded
{
    public MapView MapView { get; private set; } = null;
    public MapboxMap MapboxMap { get; private set; } = null;
    public static MainActivity MainActivityInstance { get; private set; }
    protected override void OnCreate(Bundle savedInstanceState)
    {
        [...]
        MainActivityInstance = this;
        Mapbox.GetInstance(this, "pk.###");
        MapView = new MapView(this);
        MapView.GetMapAsync(this);
        MapView.OnCreate(savedInstanceState);
    }
    protected override void OnStart()
    {
        base.OnStart();
        MapView.OnStart();
        [...]
    }
    protected override void OnResume()
    {
        base.OnResume();
        MapView.OnResume();
    }
    protected override void OnPause()
    {
        MapView.OnPause();
        base.OnPause();
    }
    protected override void OnSaveInstanceState(Bundle outState)
    {
        base.OnSaveInstanceState(outState);
        MapView.OnSaveInstanceState(outState);
    }
    protected override void OnStop()
    {
        base.OnStop();
        MapView.OnStop();
    }
    protected override void OnDestroy()
    {
        MapView.OnDestroy();
        base.OnDestroy();
    }
    public override void OnLowMemory()
    {
        base.OnLowMemory();
        MapView.OnLowMemory();
    }
    public void OnMapReady(MapboxMap p0)
    {
        MapboxMap = p0;
        [...] 
    }
    public void OnStyleLoaded(Com.Mapbox.Mapboxsdk.Maps.Style p0)
    {
        [...]
    }
}
  1. 将每个方法的内容包裹在try-catch,中并写入Debug输出任何异常(希望不是崩溃)。

  2. 您可能需要找出导致崩溃的确切原因,以便任何人帮助您。

通过在整个自定义渲染器中添加 Debug.WriteLine 语句来做到这一点。

  1. 我还建议验证是否确实是导致问题的自定义渲染器。

通过注释掉大部分自定义代码来做到这一点。使其显示为空视图。


  1. 您需要向 MainActivity 方法添加代码。这不会修复此崩溃,但会避免以后崩溃,例如当应用程序进入后台时。

Naxam library install guide 说:

The MapView contains its own lifecycle methods for managing Android's OpenGL lifecycle, which must be called directly from the containing Activity. In order for your app to correctly call the MapView's lifecycle methods, you must override the following lifecycle methods in the Activity that contains the MapView and call the respective MapView method.

Android 来自 link:

的代码
// Set this from your custom renderer.
public MapView mapView;

override fun onStart() {
    super.onStart()
    mapView?.onStart()
}
 
override fun onStop() {
    super.onStop()
    mapView?.onStop()
}
 
override fun onLowMemory() {
    super.onLowMemory()
    mapView?.onLowMemory()
}
 
override fun onDestroy() {
    super.onDestroy()
    mapView?.onDestroy()
}

将其翻译成等效的 C#。


  1. 在您的自定义渲染器中,设置活动 mapView 变量:

    Xamarin Essentials.Platform.CurrentActivity.mapView = ...;

您还应该将该变量设置为空:

  • 在 OnElementChanged / e.newElement == null
  • 在处置中。

  1. 根据我的经验,在 Android 上,OpenGL 视图不喜欢被隐藏 - 这就是切换到不同选项卡时发生的情况。 (MapBox 使用 OpenGL 视图。)

不幸的是,结果是“硬崩溃”——不会被 try/catch 捕获。不会提供有关崩溃原因的有用信息。

如果这是原因,上述 none 将解决问题。

您可能必须执行自定义逻辑,在选项卡隐藏时处理地图,在选项卡返回时重新创建它。

请参阅 ,了解您需要添加代码的事件。