LeakCanaryを使用すると、MapBoxを使用してマップを表示するアクティビティを終了するときにメモリリークが発生していると表示されます。 以下のヒープ情報とコード。私は何も見ませんが、私は何を探しているのか分かりません。あなたは原因を見ることができますか?MapBoxを使用したメモリリーク
com.myapp.debug:1.0:1。 * com.myapp.DirectionsActivityが漏れた: を* GCのROOT静的android.app.ActivityManager.mContext は* com.myapp.DirectionsActivityインスタンスをリーク
- 参照キー:b0fc445c-fe16-46e8-aff4-71acd3924d52
- デバイス:5.0.2 API::21 LeakCanary:1.3.1
デュレーション:見= 5272ms、GC = 189ms、ヒープダンプ= 6599ms、分析= 75048ms
サムスンサムスンSM-T530NUが- Androidのバージョンをmatissewifiue
詳細:
- クラスandroid.app.ActivityManager | static $ staticOverhead = byte [] [id = 0x70bc2699; length = 504; size = 520] | static AMS_POLICY_ENFORCING = java.lang.String [id = 0x701edfb0] | static META_HOME_ALTERNATE = java.lang.String [id = 0x70584898] |静的TAG = java.lang.String [id = 0x704a96a0] | static mContext = com.myapp。DirectionsActivity [id = 0x13061da0] | static BROADCAST_STICKY_CANT_HAVE_PERMISSION = -1 | static BROADCAST_SUCCESS = 0 |静的COMPAT_MODE_ALWAYS = -1 | static COMPAT_MODE_DISABLED = 0 |静的COMPAT_MODE_ENABLED = 1 | static COMPAT_MODE_NEVER = -2 |静的COMPAT_MODE_TOGGLE = 2 | static COMPAT_MODE_UNKNOWN = -3 |静的INTENT_SENDER_ACTIVITY = 2 |
静的INTENT_SENDER_ACTIVITY_RESULT = 3 | static INTENT_SENDER_BROADCAST = 1 |静的INTENT_SENDER_SERVICE = 4 |
static MOVE_TASK_NO_USER_ACTION = 2 | static MOVE_TASK_WITH_HOME = 1 |静的PROCESS_STATE_BACKUP = 5 | static PROCESS_STATE_CACHED_ACTIVITY = 11 | static PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12 |静的 PROCESS_STATE_CACHED_EMPTY = 13 |静的PROCESS_STATE_HEAVY_WEIGHT = 6 |静的PROCESS_STATE_HOME = 9 |静的PROCESS_STATE_IMPORTANT_BACKGROUND = 4 | static PROCESS_STATE_IMPORTANT_FOREGROUND = 3 | static PROCESS_STATE_LAST_ACTIVITY = 10 |静的PROCESS_STATE_PERSISTENT = 0 |静的PROCESS_STATE_PERSISTENT_UI = 1 | static PROCESS_STATE_RECEIVER = 8 |静的PROCESS_STATE_SERVICE = 7 |
静的PROCESS_STATE_TOP = 2 |静的RECENT_IGNORE_HOME_STACK_TASKS = 8 |静的RECENT_IGNORE_UNAVAILABLE = 2 |静的RECENT_INCLUDE_PROFILES = 4 |静的RECENT_WITH_EXCLUDED = 1 |
static REMOVE_ALL_RECENT_TASKS = 8 |静的REMOVE_ALL_TASKS = 2 |
スタティックREMOVE_TASK_EXCEPT_RECENTS = 16 | static REMOVE_TASK_IMMEDIATELY = 4 |静的REMOVE_TASK_KILL_PROCESS = 1 | static START_CANCELED = -6 |静的START_CANCELED_BY_TEMPERATURE = -8 |静的START_CLASS_NOT_FOUND = -2 | static START_DELIVERED_TO_TOP = 3 |静的START_FLAG_DEBUG = 2 | static START_FLAG_ONLY_IF_NEEDED = 1 |静的START_FLAG_OPENGL_TRACES = 4 |静的START_FORWARD_AND_REQUEST_CONFLICT = -3 | static START_INTENT_NOT_RESOLVED = -1 |静的START_NOT_ACTIVITY = -5 |
static START_NOT_VOICE_COMPATIBLE = -7 | static START_PERMISSION_DENIED = -4 |静的START_RETURN_INTENT_TO_CALLER = 1 |静的START_RETURN_LOCK_TASK_MODE_VIOLATION = 5 | static START_SUCCESS = 0 |静的START_SWITCHES_CANCELED = 4 | static START_TASK_TO_FRONT = 2 |静的USER_OP_IS_CURRENT = -2 | static USER_OP_SUCCESS = 0 |静的USER_OP_UNKNOWN_USER = -1 |静的 gMaxRecentTasks = -1 | static localLOGV = false- com.myapp.DirectionsActivityのインスタンス| TAG = java.lang.String [id = 0x1347b5c0] |クライアント= com.mapbox.services.directions.v5.MapboxDirections [id = 0x1351f4c0] |
currentRoute = com.mapbox.services.directions.v5.models.DirectionsRoute [id = 0x136c94e0] | map = com.mapbox.mapboxsdk.maps.MapboxMap [id = 0x12c94600] | mapView = com.mapbox.mapboxsdk.maps.MapView [id = 0x13422400] | mDelegate = android.support.v7.app.AppCompatDelegateImplV14 [id = 0x12c30fc0] |
mResources = null | mEatKeyUpEvent = false | mThemeId = 2131361951 | mFragments = android.support.v4.app.FragmentController [id = 0x13473ac0] | mHandler = android.support.v4.app.FragmentActivity $ 1 [id = 0x1347b5a0] |
mMediaController = null | mPendingFragmentActivityResults = android.support.v4.util。SparseArrayCompat [id = 0x13482080] | mCreated = true | mNextCandidateRequestIndex = 0 | mOptionsMenuInvalidated = false | mReallyStopped = true | mRequestedPermissionsFromFragment = false | mResumed = false | 012R00000000000000 mStopped = true |
mStartedActivityFromFragment = false |
mStartedIntentSenderFromFragment = false | mActionBar = null |
mActivityInfo = android.content.pm.ActivityInfo [id = 0x12f34340] |
mActivityTransitionState = android.app.ActivityTransitionState [id = 0x1347a280] | mAllLoaderManagers = android.util.ArrayMap [id = 0x134b4d80] | mApplication = android.app.Application [id = 0x12c95a80] | mComponent = android.content.ComponentName [id = 0x12c920b0] | mContainer = android.app.Activity $ 1 [id = 0x13473a90] | mCurrentConfig = android.content.res.Configuration [id = 0x13475a20] | mDecor = null | mDefaultKeySsb = null |
mEmbeddedID = null | mEnterTransitionListener = android.app.SharedElementCallback $ 1 [id = 0x724871f0] |
mExitTransitionListener = android.app.SharedElementCallback $ 1 [id = 0x724871f0] | mFeatureContextMenuListener = android.app.Activity $ FeatureContextMenuListener [id = 0x13473a60] |
mFragments = android.app.FragmentManagerImpl [id = 0x134757f0] |
mHandler = android.os.Handler [id = 0x1347b580] | mInjectionManager = null | mInstanceTracker = android.os.StrictMode $ InstanceTracker [id = 0x13473aa0] | mInstrumentation = android.app.Instrumentation [id = 0x12c2cd90] | mIntent = android.content.Intent [id = 0x133fb390] | mLastNonConfigurationInstances = null | mLauncherBooster = null |
mLoaderManager = null | mMainThread = android.app.ActivityThread [id = 0x12c42100] | mManagedCursors = java.util.ArrayList [id = 0x1347b540] | mManagedDialogs = null | mMenuInflater = null | mMultiWindowStyle = com.samsung.android.multiwindow.MultiWindowStyle [id = 0x13478790] | mParent = null | mResultData = null |
mSearchManager = null | mSubDecor = null | mSubWindow = null |
mSubWindowDummpy = null | mTitle = java.lang.String [id = 0x134a3dc0] | mToken = android.os.BinderProxy [id = 0x12c82fa0] |
mTranslucentCallback = null | mUiThread = java.lang.Thread [id = 0x8736cfb0] | mVoiceInteractor = null | mWindow = com.android.internal.policy.impl.PhoneWindow [id = 0x12db0110] |
mWindowManager = android.view.WindowManagerImpl [id = 0x1347ba00] |
myName = java.lang。String [id = 0x1347b260] | DEBUG_ELASTIC = false | isElasticEnabled = false | mCalled = true |
mChangeCanvasToTranslucent = false | mChangingConfigurations = false | mCheckedForLoaderManager = true | mConfigChangeFlags = 0 |
mDefaultKeyMode = 0 | mDestroyed = true | mDoReportFullyDrawn = false | mEnableDefaultActionBarUp = false | mFinished = true |
mFlipfont = 0 | mIdent = 254734993 | mLoadersStarted = false |
mPreventEmbeddedTabs = false | mResultCode = 0 | mResumed = false | mStackedHeight = -1 | mStartedActivity = false | mStopped = true | mSubWindowAdded = false | mTemporaryPause = false |
mTitleColor = 0 | mTitleReady = true | mVisibleBehind = false |
mVisibleFromClient = true | mVisibleFromServer = true |
mWindowAdded = true | mInflater = com.android.internal.policy.impl.PhoneLayoutInflater [id = 0x134789a0] | mOverrideConfiguration = null | mResources = android.content.res.Resources [id = 0x12c24700] | mTheme = android.content.res.Resources $テーマ[id = 0x1347ba20] | mThemeResource = 2131361951 | mBase = android.app.ContextImpl [ID = 0x12e06b20]
public class DirectionsActivity extends AppCompatActivity {
private final String TAG = "DirectionsActivity";
private MapView mapView;
private MapboxMap map;
private DirectionsRoute currentRoute;
private MapboxDirections client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// employee location is destination
Intent intent = getIntent();
double employeeLatitude = intent.getDoubleExtra("latitude", new Double(getString(R.string.state_capital_latitude)));
double employeeLongitude = intent.getDoubleExtra("longitude", new Double(getString(R.string.state_capital_longitude)));
// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
MapboxAccountManager.start(this, getString(R.string.access_token));
// This contains the MapView in XML and needs to be called after the account manager
setContentView(R.layout.activity_mas_directions);
// get current location from preferences for use as origin
Location currentLocation = PreferencesUtilities.getCurrentLocation(this.getApplicationContext());
final Position origin = Position.fromCoordinates(currentLocation.getLongitude(), currentLocation.getLatitude());
final Position destination = Position.fromCoordinates(employeeLongitude, employeeLatitude); // yes, long,lat - strange
this.setTitle("Origin: (" + origin.getLatitude() + ", " + origin.getLongitude() + ") >> Destination: (" + destination.getLatitude() + ", " + destination.getLongitude() + ")");
// Create Icon objects for the marker to use
IconFactory iconFactory = IconFactory.getInstance(this);
Drawable iconDrawable = ContextCompat.getDrawable(this, R.drawable.green_pin); // pin png is 125x125
final Icon greenPinIcon = iconFactory.fromDrawable(iconDrawable);
iconDrawable = ContextCompat.getDrawable(this, R.drawable.red_pin); // pin png is 125x125
final Icon redPinIcon = iconFactory.fromDrawable(iconDrawable);
// Setup the MapView
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(MapboxMap mapboxMap) {
map = mapboxMap;
// Add origin and destination to the map
LatLng originLatLng = (new LatLng(origin.getLatitude(), origin.getLongitude()));
mapboxMap.addMarker(new MarkerViewOptions()
.position(originLatLng)
.anchor((float)0.5, (float)1.0) // bottom, middle I think
//.anchor(1, (float)0.5) // (0,0) is top left
.title("Origin")
.snippet("current location: (" + origin.getLatitude() + ", " + origin.getLongitude() + ")")
.icon(greenPinIcon));
LatLng destinationLatLng = (new LatLng(destination.getLatitude(), destination.getLongitude()));
mapboxMap.addMarker(new MarkerViewOptions()
.position(destinationLatLng)
.anchor((float)0.5, (float)1.0) // bottom, middle I think
//.anchor(1, (float)0.5) // (0,0) is top left
.title("Destination")
.snippet("destination: (" + destination.getLatitude() + ", " + destination.getLongitude() + ")")
.icon(redPinIcon));
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(originLatLng) // Northeast
.include(destinationLatLng) // Southwest
.build();
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 50), 5000);
// Get route from API
try {
getRoute(origin, destination);
}
catch (ServicesException servicesException) {
Log.e(TAG, servicesException.toString());
servicesException.printStackTrace();
}
}
});
}
private void getRoute(Position origin, Position destination) throws ServicesException {
client = new MapboxDirections.Builder()
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_CYCLING)
.setAccessToken(MapboxAccountManager.getInstance().getAccessToken())
.build();
client.enqueueCall(new Callback<DirectionsResponse>() {
@Override
public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
//Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().getRoutes().size() < 1) {
Log.e(TAG, "No routes found");
return;
}
// Print some info about the route
currentRoute = response.body().getRoutes().get(0);
//Log.d(TAG, "Distance: " + currentRoute.getDistance());
Double km = currentRoute.getDistance()/1000;
// there are 4 digits to the right of the decimal, make it 2
String kilometers = km.toString();
int index = kilometers.lastIndexOf(".");
kilometers = kilometers.substring(0, index + 3);
Toast.makeText(
DirectionsActivity.this,
"Route is " + kilometers + " kilometers",
Toast.LENGTH_SHORT).show();
// Draw the route on the map
drawRoute(currentRoute);
}
@Override
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
Log.e(TAG, "Error: " + throwable.getMessage());
Toast.makeText(DirectionsActivity.this, "Error: " + throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void drawRoute(DirectionsRoute route) {
// Convert LineString coordinates into LatLng[]
LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
List<Position> coordinates = lineString.getCoordinates();
LatLng[] points = new LatLng[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
points[i] = new LatLng(
coordinates.get(i).getLatitude(),
coordinates.get(i).getLongitude());
}
// Draw Points on MapView
map.addPolyline(new PolylineOptions()
.add(points)
.color(Color.parseColor("#009688"))
.width(5));
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Cancel the directions API request
if (client != null) {
client.cancelCall();
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
編集:@cammaceに応答して情報を追加
。これは私がユーザーの場所を取得する方法です。リークは、アプリケーションがフォアグラウンドにいる間に発生します(かつ、バックグラウンドにいたことはありませんでした)。
MainActivity
private Observable<Location> locationUpdateObservable;
private Subscription locationUpdateSubscription;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Location Observable
final LocationRequest locationRequest = LocationRequest.create()
//.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(30000); // milliseconds
// net.kjulio.rxlocation
locationUpdateObservable = RxLocation.locationUpdates(mActivity, locationRequest);
locationUpdateSubscription = locationUpdateObservable.subscribe(new Action1<Location>() {
@Override
public void call(Location location) {
// save current location to preferences
PreferencesUtilities.setCurrentLocation(mActivity.getApplicationContext(), location);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Toast.makeText(mActivity, "Can't get location Throwable: " + throwable.toString(), Toast.LENGTH_SHORT).show();
}
});