2

我有一个应用程序在平板电脑上使用一段时间后崩溃OutOfMemoryError。我的应用程序使用带有Fragments. 经过大量调试后,我得出的结论是,大量内存消耗是由详细视图中使用的映射引起的。

我创建了一个尽可能简单的示例,它可能缺少许多重要功能,但演示了问题。

测试地图活动:

public class TestMapActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test_map_activity);
}

public void newMap(View view) {
    getSupportFragmentManager().beginTransaction().replace(R.id.mapFrame, new TestMapFragment()).addToBackStack(null).commit();
}
}

Activity的布局文件:

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

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="newMap"
    android:text="new map" />

<FrameLayout
    android:id="@+id/mapFrame"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

</LinearLayout>

测试地图片段:

public class TestMapFragment extends Fragment {

protected MapView mMapView;
protected GoogleMap mMap;

@Override
public void onSaveInstanceState(Bundle outState) {
    mMapView.onSaveInstanceState(outState);
    super.onSaveInstanceState(outState);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mMapView = new MapView(REdroid.sContext);
    mMapView.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    View v = inflater.inflate(R.layout.test_map_fragment, container, false);
    ((FrameLayout) v.findViewById(R.id.mapFrame)).addView(mMapView);

    return v;
}

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

@Override
public void onResume() {
    super.onResume();
    mMapView.onResume();
}

@Override
public void onPause() {
    mMapView.onPause();
    super.onPause();
}

@Override
public void onDestroy() {
    mMapView.onDestroy();
    super.onDestroy();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    mMapView.onLowMemory();
};

private final void setUpMapIfNeeded() {
    if (mMap == null) {
        mMap = mMapView.getMap();
        if (mMap != null) {
            setUpMap();
        }
    }
}

protected void setUpMap() {
    try {
        MapsInitializer.initialize(getActivity());
    } catch (GooglePlayServicesNotAvailableException e) {
    }
}

}

片段的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFrame"
android:layout_width="match_parent"
android:layout_height="match_parent" >

</FrameLayout>

我正在启动活动并按下按钮以显示地图。当我使用 DDMS 检查内存消耗时,我可以看到每次按“新地图”时,“已分配”内存都会增长约 0.5MB。正如你可以想象的那样,当用户观看许多项目(这在我的应用程序中是很正常的行为)并且应用程序每 10 个项目占用 5MB(实际上在实际应用程序中每个视图占用 1MB)时,这确实是一个问题。

这是正常的吗?我能做些什么来阻止应用程序使用这么多内存?我在这里读到谷歌地图有一些内存泄漏,但它们会这么大吗?

编辑

我更正了 TestMapActivity.newMap() 函数。我在堆栈中添加了添加事务,因为如果我不将操作放入后台堆栈,则不会发生内存“泄漏”。

4

2 回答 2

3

当我在两个片段之间切换时,我遇到了类似的问题,每个片段都有 MapView。

将此添加到我的代码中解决了巨大的内存消耗问题:

@Override
public void onDestroyView() {
    mMapView.clear()
    mMapView.onDestroy();
    super.onDestroyView();
}
于 2018-02-08T22:40:32.010 回答
2

首先,如果 LogCat 中的 GC 对您来说很烦人(我认为是),那么您可以通过消息过滤器将其删除:^(?!.*(GC_)|(Cache)).*$。

其次,您应该重用 MapFragment,或者至少删除它并重新创建它。

就像是:

    public class TestMapActivity extends FragmentActivity {

        GoogleMapFragment map;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.test_map_activity);

            if (savedInstanceState != null) {
                // to handle orientation change
                map = getSupportFragmentManager().findFragmentByTag("map");
            }
        }

        public void newMap(View view) {
            if (map == null)
                 map = new TestMapFragment();

            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.mapFrame, map, "map").commit();
        }
    }

编辑:

在您对您使用 MapView 发表评论后,我在 MapView 上搜索了 API,并来自:http: //developer.android.com/reference/com/google/android/gms/maps/MapView.html

onDestroy()
    You must call this method from the parent Activity/Fragment's corresponding method.

你在做这个吗?

编辑2

刚刚注意到您在片段的 onCreate 中执行以下操作:

mMapView = new MapView(REdroid.sContext);

如何删除该行,而不是在 setupMapIfNeeded 中:

private final void setUpMapIfNeeded() {
if (mMapView == null) {
    mMapView = new MapView(context);
}
if (mMap == null) {
    mMap = mMapView.getMap();
    if (mMap != null) {
        setUpMap();
    }
}

}

另外我想我还会在片段的 onCreate 中做一个 setRetainInstance(true) 。

于 2013-10-21T22:44:24.600 回答