-
我有导航抽屉和HomeFragment的活动。
-
HomeFragment包含两个嵌套片段(子片段):SupportMapFragment和ActionFragment
我在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));
}
}
}
任何帮助都将不胜感激,因为我已经为此挣扎了很长一段时间。非常感谢。
问题
问题是类加载器只加载ActionFragment
一次,这就是为什么静态字段只在第一轮初始化的原因。
第一次运行时会发生什么:
1) HomeFragment#onActivityCreated()
HomeFragment#sMap
为空->通过findViewById()定位HomeFragment#sMap
=[1]
2) ActionFragment
的类加载器
ActionFragment#sMap
为空->从HomeFragment.getMap()
加载ActionFragment#sMap
=[1]
。。。家被毁了
3) HomeActivity#onDestroyView()
HomeFragment#sMap
=空
。。。家被重新创建
4) HomeFragment#onActivityCreated()
HomeFragment#sMap
为空->通过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
的最新映射实例。
糟糕的设计。保留静态var来存储对映射的引用是错误的。假设您有两个HomeFragment或多个活动,其中包含HomeFragment。这行不通。
我认为你应该使用标签来寻找碎片。或者更好地在活动中创建一些接口,实现片段之间的通信。无论如何,你不能使用静态字段的地图,你做的方式。
你可以使用这个代码:
((SupportMapFragment) getActivity().getSupportFragmentManager()
.findFragmentById(R.id.home_map)).getMap();
每次需要的时候都能得到地图。
问题是您正试图将包含SupportMapFragment
的布局扩展到另一个片段HomeFragment
中。嵌套片段仅在程序上受支持。来自文档:
注意:当布局为碎片时,不能将该布局膨胀为碎片包括片段。只有在添加时才支持嵌套片段动态地转换为片段。
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" />
主页片段
@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
中,使用findFragmentById
api,而不是维护从HomeFragment
获得的对GoogleMap
的静态引用。