为什么会发生内存泄漏 - android - LeakCanary

时间:2015-10-04 20:13:00

标签: android android-fragments memory-leaks leakcanary

我开始使用Leak Canary并且在使用MapView旋转片段之后我得到了这个内存泄漏。

10-04 22:01:51.530 17969-18044/cz.united121.android.revizori I/art: hprof: heap dump "/storage/emulated/0/Download/leakcanary/suspected_leak_heapdump.hprof" starting...
10-04 22:02:30.872 17969-20755/cz.united121.android.revizori D/LeakCanary: In cz.united121.android.revizori:1.0:1.
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * cz.united121.android.revizori.activity.MapActivity has leaked:
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * GC ROOT com.google.android.gms.location.internal.f.a
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.android.gms.location.internal.e.h
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.d.w.e
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.d.ak.b
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.gmm6.c.p.a
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.maps.api.android.lib6.gmm6.c.y.mParent
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references android.widget.FrameLayout.mParent
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * references com.google.android.gms.maps.MapView.mContext
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * leaks cz.united121.android.revizori.activity.MapActivity instance
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Reference Key: 58a52845-81c4-4562-a45c-c831a92629c3
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Device: motorola motorola XT1032 falcon_tescogbsl
10-04 22:02:30.880 17969-20755/cz.united121.android.revizori D/LeakCanary: * Android Version: 5.0.2 API: 21 LeakCanary: 1.3.1

这就是我将片段添加到活动中的方式(我在活动中的onCreate中调用它并在选择导航菜单中的项目后)它只使用片段未被破坏但仅覆盖地图片段的原则 - 我不必采取关心保留状态:

public void changeFragment(String toFragment, Bundle args){
    Log.d(TAG, "changeFragment");
    Util.hideSoftKeyboard(this);
    Fragment fragment = null;
    String backStateName =  toFragment;

    Fragment mCurrentFragment = getFragmentManager().findFragmentById(R.id
            .fragment_place);

    if(mCurrentFragment == null){
        fragment = instantiateFragment(toFragment,args);
        getFragmentManager().beginTransaction()
                .setCustomAnimations(
                        R.animator.fragment_slide_in, R.animator.fragment_slide_out, 0, 0)
                .add(R.id.fragment_place, fragment, backStateName)
                .addToBackStack(backStateName)
                .commit();
        return;
    }

    if(mCurrentFragment.getClass().getName().equals(toFragment)){
        return;
    }

    boolean fragmentPopped = getFragmentManager().popBackStackImmediate(backStateName, 0);

    if (!fragmentPopped && getFragmentManager().findFragmentByTag(backStateName) == null){ //fragment not in back stack, create it.
        fragment = instantiateFragment(toFragment,args);
        getFragmentManager().beginTransaction()
                .setCustomAnimations(
                        R.animator.fragment_slide_in, R.animator.fragment_slide_out, 0, 0)
                .add(R.id.fragment_place, fragment, backStateName)
                .addToBackStack(backStateName)
                .commit();
    }
}

和片段代码

public static final String KEY_POINTS = "points";
private final static String BUNDLE_KEY_MAP_STATE = "mapData";

@Bind(R.id.map)
MapView mMapView;
GoogleMap mMap;

private static int PERIOD_BETWEEN_REPORTING = 10 * 1000; // ms
private static boolean isTimeValid = true;
private static MyCountingThread mThread;

public static TestMapFragment newInstance() {
    TestMapFragment fragment = new TestMapFragment();

    return fragment;
}

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

@Override
public View onCreateView(LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView");
    View mapLayout = inflater.inflate(R.layout.fragment_map, container, false);
    ButterKnife.bind(this, mapLayout);

    Bundle mapState = null;
    if (savedInstanceState != null) {
        // Load the map state bundle from the main savedInstanceState
        mapState = savedInstanceState.getBundle(BUNDLE_KEY_MAP_STATE);
    }

    mMapView.onCreate(mapState);


    return mapLayout;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    Log.d(TAG, "onSaveInstanceState");
    // Save the map state to it's own bundle
    Bundle mapState = new Bundle();
    mMapView.onSaveInstanceState(mapState);
    // Put the map bundle in the main outState
    outState.putBundle(BUNDLE_KEY_MAP_STATE, mapState);
    super.onSaveInstanceState(outState);
}


@Override
public void onActivityCreated(Bundle savedInstanceState) {
    Log.d(TAG, "onActivityCreated");
    super.onActivityCreated(savedInstanceState);
}

@Override
public void onPause() {
    Log.d(TAG, "onPause");
    mMapView.onPause();
    super.onPause();
    //mMap = null;
}

@Override
public void onResume() {
    Log.d(TAG, "onResume");
    super.onResume();
    setUpMapIfNeeded();
    mMapView.onResume();
}

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

    Log.d(TAG, "onDestroyView");
}

@Override
public void onStop() {
    super.onStop();
    if (BuildConfig.DEBUG) {
        Log.d(TAG, "onStop");
    }
}

@Override
public void onDestroy() {
    Log.d(TAG, "onDestroy");
    mMapView.onDestroy();
    mMap = null;
    ButterKnife.unbind(this);
    super.onDestroy();
}

public void onLowMemory() {
    Log.d(TAG, "onLowMemory");
    super.onLowMemory();
    mMapView.onLowMemory();
}

;

private void setUpMapIfNeeded() {
    Log.d(TAG, "setUpMapIfNeeded");
    if (mMap == null) {
        mMapView.getMapAsync(this);
    }
}


@Override
public void onMapReady(GoogleMap googleMap) {
    Log.d(TAG, "onMapReady");
    mMap = googleMap;

    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setZoomControlsEnabled(true);

    mMap.setOnMapClickListener(this);
    mMap.setOnCameraChangeListener(this);

    refreshMap();

    CameraPosition lastCameraPosition = TestGetterLocation.getCameraPosition();
    if(lastCameraPosition != null){
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(lastCameraPosition.target, lastCameraPosition.zoom));
    }
}

@Override
public void onMapClick(LatLng latLng) {
    Log.d(TAG, "onMapClick");
    //mMap.addMarker(new MarkerOptions().position(latLng));
    //TestGetterLocation.addLocationMarker(latLng);

    LocationGetter.addReport(new ReportInspector(ParseUser.getCurrentUser(), new ParseGeoPoint(latLng.latitude,latLng.longitude), TypeOfVehicle.BUS.name()));
}

@Override
public void onCameraChange(CameraPosition cameraPosition) {
    Log.d(TAG, "onCameraChange");
    TestGetterLocation.setCameraPosition(cameraPosition);
}

@OnClick(R.id.reporting_insperctor)
public void OnReportinInspectorClick(View view){
    refreshMap();
}

private void refreshMap(){
    mMap.clear();

    for (ReportInspector report : LocationGetter.getReports()) {
        mMap.addMarker(new MarkerOptions()
                .position(report.getLocation())
                .icon(BitmapDescriptorFactory.fromResource(report
                        .getTypeOfVehicle()
                        .getMarkerImageResource())));
    }
}

任何想法为什么会发生内存泄漏?

1 个答案:

答案 0 :(得分:0)

经过一段时间的争吵之后,我发现这是已知问题并尝试从此页面https://code.google.com/p/gmaps-api-issues/issues/detail?id=8111解决问题,LeakCanary不再报告内存泄漏。