Fragment Reload后无法修改Map Fragment

时间:2014-11-10 22:28:27

标签: android android-fragments google-maps-android-api-2

  1. 我的活动导航抽屉 HomeFragment

  2. HomeFragment 包含两个嵌套片段(子片段): SupportMapFragment ActionFragment

  3. 我在 HomeFragment 中将GoogleMap对象 sMap 声明为静态,因此可以通过嵌套片段 ActionFragment

    第一次运行时一切正常。可以在 ActionFragment 中操作地图。但是当HomeFragment被删除并在以后重新加载时,地图只能从HomeFragment(父片段)修改,而不能再从ActionFragment(嵌套片段)修改。

    我无法理解为什么在重新加载片段时,在第一个实例中起作用的东西不起作用。以下是我保持最低限度的代码,以便于理解。


    HomeFragment.java (父片段)

    public class HomeFragment extends Fragment {
    
        private static GoogleMap sMap;
        public static GoogleMap getMap() {
            return sMap;
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate layout
            return inflater.inflate(R.layout.f_home, container, false);
        }
    
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState){
            super.onActivityCreated(savedInstanceState);
    
            // Obtain the GoogleMap object
            try {
                if (sMap == null) {
                    sMap = ((SupportMapFragment) getActivity().getSupportFragmentManager()
                            .findFragmentById(R.id.home_map)).getMap();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            // Load child fragment
            if (savedInstanceState == null) {
                Fragment _actionFragment = new ActionFragment();
                FragmentTransaction _ft = getChildFragmentManager().beginTransaction();
                _ft.replace(R.id.action_container_bottom, _actionFragment);
                _ft.commit();
            }
        }
    
    
        @Override
        public void onDestroyView(){
            super.onDestroyView();
    
            // Remove the map fragment to prevent errors on the next load
            if(sMap != null){
                try {
                    getActivity().getSupportFragmentManager()
                                .beginTransaction()
                                .remove(getActivity().getSupportFragmentManager()
                                        .findFragmentById(R.id.home_map))
                                .commit();
    
                    sMap = null;
                } catch (Exception e){}
            }
        }
    }
    

    f_home.xml (父片段的布局)

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:id="@+id/home_map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <FrameLayout
            android:id="@+id/action_container_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true" />
    
    </RelativeLayout>
    

    ActionFragment.java (嵌套或子片段)

    public class ActionFragment extends Fragment {
        private static GoogleMap sMap = HomeFragment.getMap();
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
    
            return inflater.inflate(R.layout.f_action, container, false);
        }
    
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState){
            super.onActivityCreated(savedInstanceState);
    
            // check if map is created successfully or not
            if (sMap != null) {
                sMap.clear();
                sMap.setPadding(0, 0, 0, 300);
                sMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                sMap.setBuildingsEnabled(false);
                sMap.setMyLocationEnabled(false);
                sMap.getUiSettings().setRotateGesturesEnabled(false);
                sMap.getUiSettings().setTiltGesturesEnabled(false);
                sMap.getUiSettings().setZoomControlsEnabled(false);
                sMap.moveCamera(CameraUpdateFactory.zoomTo(12));
            }
        }
    }
    

    任何帮助都会受到极大的赞赏,因为我很长时间都在努力解决这个问题。谢谢!

3 个答案:

答案 0 :(得分:7)

问题

问题是类加载器只加载ActionFragment一次,这就是为什么静态字段只在第一轮初始化。

首次运行会​​发生什么:

1)HomeFragment#onActivityCreated()

  • HomeFragment#sMap为空 - &gt;通过findViewById()
  • 找到
  • HomeFragment#sMap = [1]

2)ActionFragment

的类加载器
  • ActionFragment#sMap为空 - &gt;从HomeFragment.getMap()
  • 加载
  • ActionFragment#sMap = [1]

......家被毁......

3)HomeActivity#onDestroyView()

  • HomeFragment#sMap = null

...家庭得到重建......

4)HomeFragment#onActivityCreated()

  • HomeFragment#sMap为空 - &gt;通过findViewById()
  • 找到
  • HomeFragment#sMap = [2]

由于课程ActionFragment已经加载到内存中,因此无法再次加载课程,因此静态字段ActionFragment#sMap的代码将再次执行。它仍在引用旧的(无效的)[1]实例。

解决方案

要解决此问题,您可以执行以下操作:

public class ActionFragment extends Fragment {
    private GoogleMap mMap;

    public void onAttach(Activity activity) {
        super.onAttach(activity);  
        mMap = HomeFragment.getMap();
    }


   public void onDetach() { 
       super.onDetach() {
       mMap = null;
   }
}

使用此代码,每次附加ActionFragment时,它都会请求HomeFragment的最新地图实例。

答案 1 :(得分:4)

糟糕的设计。 保持静态var以存储对地图的引用是错误的。假设您有两个HomeFragment或几个包含HomeFragment的活动。它不会起作用。

我认为您应该使用标签来查找片段。或者更好地在活动中创建一些接口来实现片段之间的通信。无论如何,你不能以你的方式使用静态字段作为地图。

您可以使用此代码:

((SupportMapFragment) getActivity().getSupportFragmentManager()
                        .findFragmentById(R.id.home_map)).getMap();

每次需要时获取地图。

答案 2 :(得分:3)

问题是您尝试将包含SupportMapFragment的布局扩展到另一个片段HomeFragment。嵌套片段仅以编程方式支持。来自docs

  

注意:在布局时,您无法将布局扩展为片段   包括一个片段。仅在添加时支持嵌套片段   一个动态的片段。

<强> f_home.xml

    <!--<fragment
        android:id="@+id/home_map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />-->

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

<强> HomeFragment

    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);

        // Obtain the GoogleMap object
        try {
            if (sMap == null) {
                /*sMap = ((SupportMapFragment) getActivity().getSupportFragmentManager()
                        .findFragmentById(R.id.home_map)).getMap();*/
                mapFragment = new SupportMapFragment();
                sMap = mapFragment.getMap();
                getChildFragmentManager()
                        .beginTransaction()
                        .replace(R.id.home_map, mapFragment)
                        .commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Load child fragment
        if (savedInstanceState == null) {
            Fragment _actionFragment = new ActionFragment();
            FragmentTransaction _ft = getChildFragmentManager().beginTransaction();
            _ft.replace(R.id.action_container_bottom, _actionFragment);
            _ft.commit();
        }
    }


    @Override
    public void onDestroyView(){
        super.onDestroyView();

        // Remove the map fragment to prevent errors on the next load
        if(sMap != null){
            try {
                /*getActivity().getSupportFragmentManager()
                        .beginTransaction()
                        .remove(getActivity().getSupportFragmentManager()
                                .findFragmentById(R.id.home_map))
                        .commit();*/

                getChildFragmentManager()
                        .beginTransaction()
                        .remove(mapFragment)
                        .commit();
                sMap = null;
                mapFragment = null;
            } catch (Exception e){}
        }
    }

ActionFragment而不是维护从GoogleMap获得的HomeFragment的静态引用,请使用findFragmentById api。