【问题标题】:Android Fragment Life Cycle and Google MapsAndroid 片段生命周期和谷歌地图
【发布时间】:2015-10-17 18:23:27
【问题描述】:

我有一个应该显示 Google 地图的嵌套片段。首次创建活动时,会添加主片段,然后实例化嵌套的地图片段。这可以正常工作。

但是,如果用户离开应用程序(将其置于后台),然后再返回应用程序,则不再显示嵌套的地图片段。就好像有人在上面调用了 map.setVisibility(View.INVISIBLE)(不是 View.GONE)(只是没有调用它——我只是为了把问题放在上下文中)。

这是第一个片段的相关代码(请注意,我遗漏了很多代码,因此请不要担心您在此处看到的任何变量未初始化):

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        Log.d("resume", "today onCreateView");
        view = inflater.inflate(R.layout.fragment_today, container, false);    
        fragmentManager = getFragmentManager();
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        addMapFragment(new LatLng(location.getLatitude(), location.getLongitude()), location.getLocationName());
    }

    private void addMapFragment(LatLng latLng, String marker_name) {

        Log.d("resume", Double.toString(latLng.latitude));

        Bundle mapBundle = new Bundle();
        mapBundle.putDouble("lat", latLng.latitude);
        mapBundle.putDouble("lng", latLng.longitude);
        mapBundle.putString("marker_title", marker_name);

        // capture this for use in getting directions if requested
        destinationLatLng = new LatLng(latLng.latitude, latLng.longitude);

        mMapFragment = new MapFragment();
        mMapFragment.setArguments(mapBundle);

        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.map_today, mMapFragment);
        fragmentTransaction.commitAllowingStateLoss();

        Log.d("resume", "map added");
    }

fragment_today.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.mysite.myapp.Activities.ViewControllers.TodayFragment"
    android:id="@+id/today_background"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/title_frame_today"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

        <FrameLayout
            android:id="@+id/map_today"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:paddingLeft="15dp"
            android:paddingRight="15dp" />

       <!-- lots of other textviews follow. omitted for brevity-->

    </LinearLayout>

</RelativeLayout>

fragment_map.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/fragment_map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    map:mapType="normal"
    map:uiCompass="true"
    map:uiRotateGestures="true"
    map:uiScrollGestures="true"
    map:uiTiltGestures="true"
    map:uiZoomControls="true"
    map:uiZoomGestures="true" />

然后,最后,在地图片段中,我有这段代码。我已经尝试过放置代码以生成地图的位置(在 onCreateView 和 onResume 之间切换)。我将尽可能多的代码放在 onResume 中。请注意,在用户将应用置于后台和返回到后台之间,这些值都不会发生变化,因此这不是问题:

MapFragment.java

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        Log.d("resume", "map oncreateview");

        view = inflater.inflate(R.layout.fragment_map, container, false);

        // set the title text (if given by parent fragment)
        Bundle bundle = getArguments();

        if (bundle != null) {

            if (bundle.containsKey("lat") && bundle.containsKey("lng")) {    
                myLocation = new LatLng(bundle.getDouble("lat"), bundle.getDouble("lng"));
            }

            if (bundle.containsKey("marker_title"))
                markerTitle = bundle.getString("marker_title");

        }

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d("resume", "map onResume");

        if (myLocation != null && markerTitle != null) {
            CameraPosition cameraPosition = new CameraPosition.Builder()
                    .target(workoutLocation)
                    .zoom(12)
                    .tilt(30)
                    .build();

            GoogleMap map = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.fragment_map)).getMap();

            Marker marker = map.addMarker(new MarkerOptions()
                            .position(workoutLocation)
                            .title(markerTitle)
            );
            marker.showInfoWindow();

            map.setBuildingsEnabled(true);
            map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
        }
    }

在运行时,这一切都会产生以下输出:

关于初始实例化

今天 onResume
当前
44.915647
添加地图
map oncreateview
map onResume

当应用进入后台时

今天暂停
暂停

当应用回到前台时 今天 onCreateView


地图 oncreateview
今天 onCreateView
Activity.onPostResume() 调用
今天 onResume
当前
44.915647
添加地图
地图 onResume
今天 onResume
当前
44.915647
添加地图
地图 oncreateview
地图 onResume
map oncreateview
map onResume

我认为这一切看起来都不错,虽然奇怪的是“map oncreateview”和“map onResume”出现了两次(我认为这不是问题)。

很长的帖子,但一个有趣的困境。感谢所有能走到这一步的人!

【问题讨论】:

    标签: android google-maps android-fragments


    【解决方案1】:

    尝试使用异步获取地图的新 API。

    引用您的 Google 地图对象。在 onResume() 中,检查它是否为空,然后获取您的地图。

    我还建议像添加常规片段一样添加您的子地图。也就是说,不要在布局中使用片段,而是使用 FrameLayout 并向其添加 (Support)MapFragment。在我的片段中使用嵌套子片段时,我发现了很多问题。

    所以,我建议这样:

    private GoogleMap googleMap;
    
    private void setUpMapIfNeeded(){
        if(googleMap == null){
            SupportMapFragment mapFragment = SupportMapFragment.newInstance();
            // mapContainerLayout would be some FrameLayout to replace the <fragment> you use for map
            getChildFragmentManager.beginTransaction.replace(R.id.mapContainerLayout, mapFragment, "MapTag").commit;
            mapFragment.getMapAsync(this);
        }
    }
    
    @Override
    public void onMapReady(GoogleMap map) {
        this.googleMap = map;
        // Do other stuff as needed
    }
    

    然后只需在 onResume() 中调用 setUpMapIfNeeded()。

    编辑:将您的 fragmentManager 更改为 getChildFragmentManager();

    【讨论】:

    • 好建议。甚至不知道getMapAsync() 方法。不幸的是,我修改了我的 MapFragment 类来实现它,但我仍然得到完全相同的结果。我无法更改嵌套片段,因为它是整个应用程序架构决策的一部分,会在其他地方产生重大影响。我宁愿让这个问题保持原样。
    • 尝试将您的 fragmentManager 更改为 getChildFragmentManager()。不知道还有什么可能。此外,您总是在 onResume() 中添加新的地图片段。上面的代码适用于您的主要片段。我没有意识到你有一个单独的 MapFragment 类。
    • 就是这样。无非就是打电话给getChildFragmentManager()。哇,我不敢相信我花了多少时间在这上面。请将其发布为答案,我会接受。非常感谢!
    • 编辑了原始答案。很高兴能帮上忙。
    猜你喜欢
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多