【问题标题】:Custom MapBox Android Renderer - crash when change tabs自定义 MapBox Android 渲染器 - 更改选项卡时崩溃
【发布时间】:2022-01-04 03:36:55
【问题描述】:

我正在尝试使用 naxam 库在 Xamarin Forms 中为 Android 创建 MapBox Renderer。 该地图作为选项卡中的视图内容显示得很好,但是当我多次更改选项卡时,它会在 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);
    }
}

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

请帮忙。

编辑:

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

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

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)
    {
        [...]
    }
}

【问题讨论】:

    标签: xamarin.forms xamarin.android mapbox mapbox-android custom-renderer


    【解决方案1】:
    1. 将每个方法的内容包装在try-catch并将任何异常写入调试输出(希望不要崩溃)。

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

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

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

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


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

    Naxam library install guide 说:

    MapView 包含自己的生命周期方法,用于管理 Android 的 OpenGL 生命周期,必须直接从包含的 Activity 调用。为了让您的应用正确调用 MapView 的生命周期方法,您必须在包含 MapView 的 Activity 中重写以下生命周期方法并调用相应的 MapView 方法。

    来自该链接的 Android 代码:

    // 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 = ...;

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

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

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

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

    如果是这个原因,以上方法都不能解决问题。

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

    请参阅https://stackoverflow.com/a/52186885/199364,了解您需要添加代码的事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多