如何在旋转设备(纵向/横向)后在MapFragment上保留/重新绑定事件监听器?

问题描述:

我正在用Xamarin(版本7.1)开发一个Android应用程序。它显示为地图并绘制PolyLines,在OnCameraIdle()中这样做。如何在旋转设备(纵向/横向)后在MapFragment上保留/重新绑定事件监听器?

MapFragment以编程方式在OnCreate中生成。我通过GetMapAsync获取GoogleMapOnResume并绑定了听众OnMapReady
他们工作正常,但只在一开始。一旦设备旋转(纵向 - >横向或反之亦然),摄像机的移动不会再触发听众。
但是地图起作用 - 我(用户)仍然可以移动相机。我(应用程序)无法使用它了。

这是裸码,只有地图的创建和处理。其他一切(实际绘图)被删除:

public class MapActivity : Activity, IOnMapReadyCallback, 
    GoogleMap.IOnCameraIdleListener, GoogleMap.IOnCameraMoveStartedListener 
{ 
    private GoogleMap _map; 
    private MapFragment _mapFragment; 

    private void InitializeMap() 
    { 
     _mapFragment = MapFragment.NewInstance(); 
     var tx = FragmentManager.BeginTransaction(); 
     tx.Add(Resource.Id.map_placeholder, _mapFragment); 
     tx.Commit(); 
    } 

    private void SetMapListeners() 
    { 
     Log.Debug("MyApp/ Map", "SetMapListeners"); 
     _map.SetOnCameraIdleListener(this); 
     _map.SetOnCameraMoveStartedListener(this); 
    } 

    /* Activity */ 

    protected override void OnCreate(Bundle savedInstanceState) 
    { 
     base.OnCreate(savedInstanceState); 
     Log.Debug("MyApp/Map", "OnCreate"); 
     SetContentView(Resource.Layout.Map); 
     InitializeMap(); 
    } 

    protected override void OnStart() 
    { 
     base.OnStart(); 
     Log.Debug("MyApp/Map", "OnStart"); 
    } 

    protected override void OnResume() 
    { 
     base.OnResume(); 
     if (_map == null) 
      _mapFragment.GetMapAsync(this); 
     Log.Debug("MyApp/Map", "OnResume"); 
    } 

    protected override void OnPause() 
    { 
     base.OnPause(); 
     Log.Debug("MyApp/Map", "OnPause"); 
    } 

    protected override void OnStop() 
    { 
     base.OnStop(); 
     Log.Debug("MyApp/Map", "OnStop"); 
    } 

    protected override void OnDestroy() 
    { 
     base.OnStop(); 
     Log.Debug("MyApp/ Map", "OnDestroy"); 
    } 


    /* IOnMapReadyCallback */ 

    public void OnMapReady(GoogleMap googleMap) 
    { 
     Log.Debug("MyApp/Map", "Map is ready!"); 
     _map = googleMap;  
     SetMapListeners(); 
    } 


    /* IOnCameraIdleListener */ 

    public void OnCameraIdle() 
    { 
     Log.Debug("MyApp/Map", "Camera is idle."); 
     // Drawing routine is called here 
    } 


    /* IOnCameraMoveStartedListener */ 

    public void OnCameraMoveStarted(int reason) 
    { 
     Log.Debug("MyApp/Map", "Camera move started."); 
    } 
} 

正如你可以在下面的日志摘录看到,听众都在开始工作,但一旦设备被旋转(至少)一次,他们都不见了。
我也尝试在生命周期中只呼叫SetMapListeners一次,第一次调用OnMapReady,但这并没有改变任何东西。

04-03 20:29:06.486 D/MyApp/Map(7446): OnCreate 
04-03 20:29:06.688 I/Google Maps Android API(7446): Google Play services client version: 10084000 
04-03 20:29:06.695 I/Google Maps Android API(7446): Google Play services package version: 10298438 
04-03 20:29:07.394 D/MyApp/Map(7446): OnStart 
04-03 20:29:07.399 D/MyApp/Map(7446): OnResume 
04-03 20:29:07.432 D/MyApp/Map(7446): Map is ready! 
04-03 20:29:07.438 D/MyApp/Map(7446): SetMapListeners 
04-03 20:29:07.568 D/MyApp/Map(7446): Camera is idle. 
04-03 20:29:09.231 D/MyApp/Map(7446): Camera move started. 
04-03 20:29:09.590 D/MyApp/Map(7446): Camera is idle. 
04-03 20:29:12.350 D/MyApp/Map(7446): Camera move started. 
04-03 20:29:12.751 D/MyApp/Map(7446): Camera is idle. 

## Listeners are responding, now rotating the device. 

04-03 20:29:15.503 D/MyApp/Map(7446): OnPause 
04-03 20:29:15.508 D/MyApp/Map(7446): OnStop 
04-03 20:29:15.572 D/MyApp/Map(7446): OnDestroy 
04-03 20:29:15.595 I/Google Maps Android API(7446): Google Play services package version: 10298438 
04-03 20:29:15.596 D/MyApp/Map(7446): OnCreate 
04-03 20:29:15.628 I/Google Maps Android API(7446): Google Play services package version: 10298438 
04-03 20:29:15.655 D/MyApp/Map(7446): OnStart 
04-03 20:29:15.655 D/MyApp/Map(7446): OnResume 
04-03 20:29:15.690 D/MyApp/Map(7446): Map is ready! 
04-03 20:29:15.691 D/MyApp/Map(7446): SetMapListeners 

## Map is rotated, camera position was preserved. 
## Now moving the camera, but no listeners are responding. 

04-03 20:29:24.436 D/MyApp/Map(7446): OnPause 
04-03 20:29:31.288 D/MyApp/Map(7446): OnStop 
04-03 20:29:31.359 D/MyApp/Map(7446): OnDestroy 

这里对我有意思的是,当我切换回上一个活动并再次打开地图时,它会重新开始并重新运行。但是,正如您在日志中看到的那样,在旋转设备时,活动也会被破坏并新创建。据我所知,片段不是,所以也许这就是暗示。我不知道。

我也尝试删除OnDestroy中的听众(通过设置null),但这也没有改变任何东西。

你有什么想法我可能做错了什么?

+1

我一分钱:在设备轮换时,活动和碎片都被销毁,然后新创建。 https://developer.android.com/guide/components/fragments.html#Lifecycle – user1506104

+1

谢谢。我有没有实实在在的印象,片段不会被重新创建,可能是因为视口被保留了,但这当然可以通过。 – Pharaoh

+0

尝试检查'savedInstanceState'来查看您的Activity是第一次构建还是只是返回它。您似乎在每次通话时都会叠加片段。 – gustavogbc

尝试检查savedInstanceState以查看您的活动是第一次构建还是只是返回它。您似乎在每次通话时都会叠加片段。

+0

谢谢 - 虽然不是100%的答案,这指出我在正确的方向。检查'savedInstanceState'并且只创建'MapFragment'如果它是'null'没有帮助,但为了避免重叠片段,我添加了'ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize'到我的活动。现在它可以工作。 – Pharaoh

尝试把InitializeMap()调用到OnCreateView()方法,而不是在OnCreate的倍率()

+1

在我看来,'OnCreateView'是类'Fragment'的一部分。你是说我应该扩展'MapFragment'? – Pharaoh

+0

不,在MapActivity上为OnCreateView创建一个覆盖(应该可用)。并且将调用放在初始化映射中,而不是OnCreate中的当前调用 –

+0

好吧,'OnCreateView'是'Activity'的一部分,我没有看到。但它没有帮助 - 相机位置和缩放被保留(像以前一样,使用'OnCreate'),但是在旋转设备后没有监听器被触发。 – Pharaoh

默认情况下,当屏幕旋转时的活动将被终止并重新启动。为了确保没有数据丢失,您需要使用生命周期方法正确保存和恢复您的数据。见SavingPersistentStatesavedInstanceState并按照此Android Developer Documentation希望今年五月可以帮助。

+0

没有数据丢失 - 唯一需要保留的就是相机的位置,但它会自动保存。这只是听众的重新安排,并不适用于上面的代码。 – Pharaoh

我有类似的问题,因为我们有MapFragment嵌套在另一个Fragment中,所以我们必须每次重新添加MapFragment。既然你已经将它直接嵌入到Activity中,@App Pack也应该可以工作,但我仍然会粘贴代码。

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); //onCreateView() or onResume() should work too 

    FragmentManager fragmentManager = ((AppCompatActivity) getContext()).getSupportFragmentManager(); 
    SupportMapFragment mapFragment = SupportMapFragment.newInstance(); 
    fragmentManager.beginTransaction() 
     .replace(R.id.mapContainer, mapFragment) 
     .commit(); 
    mapFragment.getMapAsync(this); 
} 

@Override 
public void onMapReady(GoogleMap googleMap) { 
    this.googleMap = googleMap; 

    UiSettings uiSettings = googleMap.getUiSettings(); 
    uiSettings.setZoomControlsEnabled(false); 

    //do your initialization + recreate your last map position from BundleSavedIntance: check this answer: http://stackoverflow.com/questions/16697891/google-maps-android-api-v2-restoring-map-state/16698624#16698624 
} 

并请: 功能应该开始小写!

+1

在C#/ Xamarin中,函数以大写字母开头。你的代码基本上在'OnAttachedToWindow'中调用'InitializeMap()' - 我现在试过,但行为是一样的。最后,您的评论让我感到惊讶,因为当我旋转设备时,地图位置被保留。我认为'MapFragment'会自动完成。 – Pharaoh

+0

对不起,没有看到Xamarin标签。请忽略我的评论。 – longilong