【问题标题】:App crash by "back" to maps fragment应用程序崩溃“返回”到地图片段
【发布时间】:2016-07-21 07:33:49
【问题描述】:

我在开发我的第一个应用程序时遇到了“返回”功能的问题。

当我打开应用程序时,单击菜单中的另一个片段(2,3 或 4)并按下后退按钮应用程序崩溃。当我启动应用程序并单击菜单中的2 > 3 > 4(按此顺序)并按下后退按钮时,我会返回3 > 2 > crash。当我返回包含谷歌地图的 mainFragment 时,应用程序崩溃。

我认为我的问题与此片段中的 googlemap(要导航回的片段)有关,因为当我在该视图的 xml 中的错误行之前设置 2 输入并再次运行时,错误行号是+2。当我注释掉这个片段时,后退按钮可以正常工作。

通过导航到我调用的新片段:

fragmentTransaction.replace(R.id.fr_content_container, new NewsFragment()).addToBackStack(null).commit();

我得到的错误是

04-01 14:26:39.679 19054-19054/aaeu.app E/AndroidRuntime: FATAL EXCEPTION: main
                                                          Process: aaeu.app, PID: 19054
                                                          android.view.InflateException: Binary XML file line #7: Binary XML file line #7: Error inflating class fragment
                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
                                                              at aaeu.app.presentationlayer.tab_AlertMapsOverview.onCreateView(mapsFragment.java:52)
                                                          .....................

mapsFragment 的 XML 是:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <fragment
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:id="@+id/mapwhere" />
    </RelativeLayout>

地图片段的代码为:

    private SupportMapFragment mMapFragment;
    private AlertManager mAlertManager;
    private GoogleMap mGoogleMap;
    HashMap<Marker, Alert> mMarkerMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlertManager = new AlertManager(getContext());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.overview_maps_alert_tab, container, false);
        ButterKnife.bind(this, view);

        loadMap();

        return view;
    }

    private void loadMap() {
        mMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapwhere);
        if (mMapFragment == null) {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            mMapFragment = SupportMapFragment.newInstance();
            fragmentTransaction.replace(R.id.mapwhere, mMapFragment).commit();
        }

        if (mMapFragment != null) {
            mMapFragment.getMapAsync(new OnMapReadyCallback() {
                @Override
                public void onMapReady(GoogleMap googleMap) {
                    if (googleMap != null) {
                        googleMap.getUiSettings().setAllGesturesEnabled(true);

                        LatLng marker_latlng = new LatLng(55.042684, 14.125549);

                        CameraPosition cameraPosition = new CameraPosition.Builder().target(marker_latlng).zoom(3.0f).build();
                        CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
                        googleMap.moveCamera(cameraUpdate);

                        setGoogleMap(googleMap);
                    }
                }
            });
        }
    }

    private void setGoogleMap(GoogleMap googleMap) {
        this.mGoogleMap = googleMap;
    }


    // This method is called by the asynctask who downloads the alerts
    @Override
    public void UpdateAlerts(List<Alert> alerts) {

        mMarkerMap = new HashMap<Marker, Alert>();
        try {
        for (Alert alert : alerts) {
            MarkerOptions marker = new MarkerOptions();
            marker.position(alert.Location.get(0));
            marker.title(alert.GetFullName());

            Marker m = mGoogleMap.addMarker(marker);
            mMarkerMap.put(m, alert);
        }


            mGoogleMap.setOnMarkerClickListener(
                    new GoogleMap.OnMarkerClickListener() {
                        @Override
                        public boolean onMarkerClick(Marker marker) {
                            startDetailView(marker);
                            return false;
                        }
                    }
            );
        }
        catch (NullPointerException e)
        {
            Log.i("tab_AlertMapsOverview","No missings to create markers for or set clicklisteners on. Are there missings in the configured Areas?");
        }
    }

在这个问题附近我也有一个小问题。当我有 3 个片段时,1、2 和 3。当我(例如)从活动 1 开始并导航到 2 > 3 > 2 > 3 时,我需要推回 4 次才能在 1 中返回。是否可以使用一种用于向后导航的“树”系统。所以我总是升一级?也许这清楚了我的意思。

我认为目前的情况还远非最佳,因为这些片段仍然在 RAM 中处于活动状态?还是我错了?

【问题讨论】:

    标签: android google-maps android-fragments fragment-backstack


    【解决方案1】:

    我也有同样的问题。在浪费了大量时间寻找解决方案之后,我最终做的是,我从 xml 中删除了片段标签。在那里放置一个 FrameLayout,每当我想添加该片段时,我都会使用片段事务添加它。这对我有用。

    问题的原因是,每当调用该片段的 onCreateView() 时,xml 文件将被膨胀,这将使片段膨胀。这将导致多个具有相同 id 的片段导致此异常。

    【讨论】:

    • 我不明白这 100%。您删除了哪个标签?,整个Frament 标签?还是只有 `android:name="com.google.android.gms.maps.SupportMapFragment"` 部分? “放在那里”是什么意思?我知道onCreate 会膨胀 XML,但为什么我的 xml 应该再次膨胀片段? (或者它会膨胀另一个片段?)
    • 您应该删除 标记并将其替换为 并使用普通片段事务添加地图片段,就像您为 NewsFragment 所做的那样。实际上,如果你再次回到片段,它的 onCreateView() 将再次被调用,这将再次膨胀片段并且两个片段将具有相同的 ids
    • 后退按钮效果很好,但是当我返回地图活动时,有时地图会显示,但大多数情况下不会显示。当我通过菜单导航到地图活动时,地图总是显示。你也有解决这个问题的办法吗?
    • fragmenttransaction 的代码是用什么方法写的? onCreate() 或 orActivityStarted() 或 onStart() 还是其他地方?
    • 如果您从另一个片段添加地图片段,请使用 getChildFragmentManager() 而不是 getFragmentManager()
    【解决方案2】:

    用这个替换你的 onBackPressed...

     @Override
        public void onBackPressed() {
            // if there is a fragment and the back stack of this fragment is not empty,
            // then emulate 'onBackPressed' behaviour, because in default, it is not working
            FragmentManager fm = getSupportFragmentManager();
            for (Fragment frag : fm.getFragments()) {
                if (frag.isVisible()) {
                    FragmentManager childFm = frag.getChildFragmentManager();
                    if (childFm.getBackStackEntryCount() > 0) {
                        childFm.popBackStack();
                        return;
                    }
                }
            }
            super.onBackPressed();
        }
    

    【讨论】:

      猜你喜欢
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      相关资源
      最近更新 更多