Утечка активности в Android
Я новичок в утечке канарейки и пытаюсь исправить несколько утечек памяти в моем приложении. В большинстве случаев у меня возникает утечка, когда я перехожу с экрана входа в систему с помощью булавки на любой другой экран в приложении. Вот канализационная свалка:
In com.exampleapp:4.5.0 (debug):62.
* com.exampleapp.activities.login.PinLoginActivity has leaked:
* GC ROOT thread java.lang.Thread.<Java Local> (named 'Thread-3')
* references com.android.tools.profiler.support.event.InputConnectionWrapper.mTarget
* references com.android.internal.widget.EditableInputConnection.mTextView
* references com.exampleapp.views.edittexts.PinEditText.mContext
* leaks com.exampleapp.activities.login.PinLoginActivity instance
* Retaining: 7.8 KB.
* Reference Key: 1036c14d-398c-45e5-a37f-55d9cd74d761
* Device: Google google Android SDK built for x86 sdk_google_phone_x86
* Android Version: 7.0 API: 24 LeakCanary: 1.5 00f37f5
* Durations: watch=5030ms, gc=133ms, heap dump=4614ms, analysis=127621ms
* Details:
* Instance of java.lang.Thread
| static threadInitNumber = 1993
| static threadSeqNumber = 2558
| static NORM_PRIORITY = 5
| static defaultUncaughtExceptionHandler = com.mixpanel.android.mpmetrics.ExceptionHandler@318432752 (0x12fae5f0)
| static EMPTY_STACK_TRACE = java.lang.StackTraceElement[0]@1883982632 (0x704b4b28)
| static $classOverhead = byte[476]@1884630209 (0x70552cc1)
| static MIN_PRIORITY = 1
| static SUBCLASS_IMPLEMENTATION_PERMISSION = java.lang.RuntimePermission@1883949688 (0x704aca78)
| static NANOS_PER_MILLI = 1000000
| static MAX_PRIORITY = 10
| blocker = null
| blockerLock = java.lang.Object@315005680 (0x12c69af0)
| contextClassLoader = dalvik.system.PathClassLoader@315129136 (0x12c87d30)
| daemon = false
| eetop = 0
| group = java.lang.ThreadGroup@1883966680 (0x704b0cd8)
| inheritableThreadLocals = null
| inheritedAccessControlContext = java.security.AccessControlContext@315005672 (0x12c69ae8)
| lock = java.lang.Object@315005688 (0x12c69af8)
| name = java.lang.String@315084256 (0x12c7cde0)
| nativeParkEventPointer = 0
| nativePeer = 2638205696
| parkBlocker = null
| parkState = 1
| priority = 5
| single_step = false
| stackSize = 0
| started = true
| stillborn = false
| target = com.android.tools.profiler.support.profilers.EventProfiler$InputConnectionHandler@314593072 (0x12c04f30)
| threadLocalRandomProbe = 0
| threadLocalRandomSecondarySeed = 0
| threadLocalRandomSeed = 0
| threadLocals = java.lang.ThreadLocal$ThreadLocalMap@320435344 (0x13197490)
| threadQ = null
| threadStatus = 0
| tid = 467
| uncaughtExceptionHandler = null
| shadow$_klass_ = java.lang.Thread
| shadow$_monitor_ = -2095673992
* Instance of com.android.tools.profiler.support.event.InputConnectionWrapper
| static $classOverhead = byte[412]@315423745 (0x12ccfc01)
| mMissingMethodFlags = 0
| mMutable = false
| mTarget = com.android.internal.widget.EditableInputConnection@325300400 (0x1363b0b0)
| shadow$_klass_ = com.android.tools.profiler.support.event.InputConnectionWrapper
| shadow$_monitor_ = 0
* Instance of com.android.internal.widget.EditableInputConnection
| static TAG = java.lang.String@1887857896 (0x70866ce8)
| static DEBUG = false
| static $classOverhead = byte[413]@1890892489 (0x70b4bac9)
| mBatchEditNesting = -1
| mTextView = com.exampleapp.views.edittexts.PinEditText@323648512 (0x134a7c00)
| mDefaultComposingSpans = null
| mDummyMode = false
| mEditable = null
| mIMM = android.view.inputmethod.InputMethodManager@315217152 (0x12c9d500)
| mKeyCharacterMap = null
| mTargetView = com.exampleapp.views.edittexts.PinEditText@323648512 (0x134a7c00)
| shadow$_klass_ = com.android.internal.widget.EditableInputConnection
| shadow$_monitor_ = 0
* Instance of com.exampleapp.views.edittexts.PinEditText
| static DEFAULT_CHARACTER_VERTICAL_PADDING = 10
| static $change = null
| static serialVersionUID = -9167688277854484912
| static $classOverhead = byte[4216]@318918657 (0x13025001)
| static PIN_CODE_LENGTH = 5
| static DEFAULT_CHARACTER_HORIZONTAL_PADDING = 10
| bounds = android.graphics.Rect@324427936 (0x135660a0)
| characterBackgroundHeight = 33
| characterBackgroundWidth = 54
| characterCircleRadius = 16
| characterHorizontalPadding = 11
| characterPaint = android.graphics.Paint[5]@322122560 (0x13333340)
| characterVerticalPadding = 11
| emptyCharacterPaint = android.graphics.Paint@324343568 (0x13551710)
| mBackgroundTintHelper = android.support.v7.widget.AppCompatBackgroundHelper@322122496 (0x13333300)
| mTextHelper = android.support.v7.widget.AppCompatTextHelperV17@323529296 (0x1348aa50)
| mAllowTransformationLengthChange = false
| mAutoLinkMask = 0
| mBoring = null
| mBreakStrategy = 0
| mBufferType = android.widget.TextView$BufferType@1890670224 (0x70b15690)
| mChangeWatcher = android.widget.TextView$ChangeWatcher@320740464 (0x131e1c70)
| mCharWrapper = null
| mCurHintTextColor = 1627389952
| mCurTextColor = -11246992
| mCurrentSpellCheckerLocaleCache = null
| mCursorDrawableRes = 17303397
| mDeferScroll = -1
| mDesiredHeightAtMeasure = -1
| mDeviceProvisionedState = 0
| mDrawables = null
| mEditableFactory = android.text.Editable$Factory@1890661520 (0x70b13490)
| mEditor = android.widget.Editor@323545568 (0x1348e9e0)
| mEllipsize = null
| mFilters = android.text.InputFilter[1]@320756400 (0x131e5ab0)
| mFreezesText = false
| mGravity = 8388627
| mHighlightColor = 1716109245
| mHighlightPaint = android.graphics.Paint@324343656 (0x13551768)
| mHighlightPath = null
| mHighlightPathBogus = true
| mHint = null
| mHintBoring = null
| mHintLayout = null
| mHintTextColor = android.content.res.ColorStateList@318855216 (0x13015830)
| mHorizontallyScrolling = true
| mHyphenationFrequency = 1
| mIncludePad = true
| mLastLayoutDirection = -1
| mLastScroll = 0
| mLayout = android.text.DynamicLayout@325012776 (0x135f4d28)
| mLinkTextColor = android.content.res.ColorStateList@316287464 (0x12da29e8)
| mLinksClickable = true
| mListeners = java.util.ArrayList@325388080 (0x13650730)
| mLocalesChanged = false
| mMarquee = null
| mMarqueeFadeMode = 0
| mMarqueeRepeatLimit = 3
| mMaxMode = 1
| mMaxWidth = 2147483647
| mMaxWidthMode = 2
| mMaximum = 1
| mMinMode = 1
| mMinWidth = 0
| mMinWidthMode = 2
| mMinimum = 1
| mMovement = android.text.method.ArrowKeyMovementMethod@315004712 (0x12c69728)
| mOldMaxMode = 1
| mOldMaximum = 1
| mPreDrawListenerDetached = true
| mPreDrawRegistered = true
| mPreventDefaultMovement = false
| mRestartMarquee = false
| mSavedHintLayout = null
| mSavedLayout = null
| mSavedMarqueeModeLayout = null
| mScroller = null
| mShadowColor = 0
| mShadowDx = 0.0
| mShadowDy = 0.0
| mShadowRadius = 0.0
| mSingleLine = true
| mSpacingAdd = 21.0
| mSpacingMult = 1.0
| mSpannableFactory = android.text.Spannable$Factory@1890661544 (0x70b134a8)
| mTempRect = android.graphics.Rect@325601120 (0x13684760)
| mText = android.text.SpannableStringBuilder@320953008 (0x13215ab0)
| mTextColor = android.content.res.ColorStateList@318854976 (0x13015740)
| mTextDir = android.text.TextDirectionHeuristics$TextDirectionHeuristicInternal@1890669624 (0x70b15438)
| mTextEditSuggestionContainerLayout = 17367285
| mTextEditSuggestionHighlightStyle = 16974923
| mTextEditSuggestionItemLayout = 17367287
| mTextPaint = android.text.TextPaint@324249968 (0x1353a970)
| mTextSelectHandleLeftRes = 17303401
| mTextSelectHandleRes = 17303403
| mTextSelectHandleRightRes = 17303405
| mTransformation = android.text.method.SingleLineTransformationMethod@315004736 (0x12c69740)
| mTransformed = android.text.method.ReplacementTransformationMethod$SpannedReplacementCharSequence@325388032 (0x13650700)
| mUserSetTextScaleX = false
| mAccessibilityCursorPosition = -1
| mAccessibilityDelegate = null
| mAccessibilityTraversalAfterId = -1
| mAccessibilityTraversalBeforeId = -1
| mAccessibilityViewId = -1
| mAnimator = null
| mAttachInfo = null
| mAttributes = null
| mBackground = android.graphics.drawable.ColorDrawable@321007872 (0x13223100)
| mBackgroundRenderNode = android.view.RenderNode@325599800 (0x13684238)
| mBackgroundResource = 0
| mBackgroundSizeChanged = true
| mBackgroundTint = null
| mBottom = 533
| mCachingFailed = false
| mClipBounds = null
| mContentDescription = null
| mContext = com.exampleapp.activities.login.PinLoginActivity@322213504 (0x13349680)
| mCurrentAnimation = null
| mDrawableState = int[2]@1884589496 (0x70548db8)
| mDrawingCache = null
| mDrawingCacheBackgroundColor = 0
| mFloatingTreeObserver = null
| mForegroundInfo = null
| mFrameMetricsObservers = null
| mGhostView = null
| mHasPerformedLongPress = false
| mID = 2131231080
| mIgnoreNextUpEvent = false
| mInContextButtonPress = false
| mInputEventConsistencyVerifier = null
| mKeyedTags = null
| mLabelForId = -1
| mLastIsOpaque = false
| mLayerPaint = null
| mLayerType = 0
| mLayoutInsets = null
| mLayoutParams = android.widget.LinearLayout$LayoutParams@323529688 (0x1348abd8)
| mLeft = 382
| mLeftPaddingDefined = false
| mListenerInfo = android.view.View$ListenerInfo@324981952 (0x135ed4c0)
| mLongClickX = NaN
| mLongClickY = NaN
| mMatchIdPredicate = null
| mMatchLabelForPredicate = null
| mMeasureCache = android.util.LongSparseLongArray@325575968 (0x1367e520)
| mMeasuredHeight = 55
| mMeasuredWidth = 315
| mMinHeight = 0
| mMinWidth = 0
| mNestedScrollingParent = null
| mNextFocusDownId = -1
| mNextFocusForwardId = -1
| mNextFocusLeftId = -1
| mNextFocusRightId = -1
| mNextFocusUpId = -1
| mOldHeightMeasureSpec = 1073741879
| mOldWidthMeasureSpec = 1073742139
| mOutlineProvider = android.view.ViewOutlineProvider$1@1890661768 (0x70b13588)
| mOverScrollMode = 1
| mOverlay = null
| mPaddingBottom = 21
| mPaddingLeft = 0
| mPaddingRight = 0
| mPaddingTop = 21
| mParent = android.widget.LinearLayout@323649536 (0x134a8000)
| mPendingCheckForLongPress = null
| mPendingCheckForTap = null
| mPerformClick = null
| mPointerIcon = null
| mPrivateFlags = -2128607184
| mPrivateFlags2 = 538125864
| mPrivateFlags3 = 16
| mRecreateDisplayList = false
| mRenderNode = android.view.RenderNode@324265128 (0x1353e4a8)
| mResources = android.content.res.Resources@324764064 (0x135b81a0)
| mRight = 697
| mRightPaddingDefined = false
| mRunQueue = android.view.HandlerActionQueue@320958560 (0x13217060)
| mScrollCache = null
| mScrollIndicatorDrawable = null
| mScrollX = 0
| mScrollY = 50
| mSendViewScrolledAccessibilityEvent = null
| mSendViewStateChangedAccessibilityEvent = null
| mSendingHoverAccessibilityEvents = false
| mStartActivityRequestWho = null
| mStateListAnimator = null
| mSystemUiVisibility = 0
| mTag = null
| mTempNestedScrollConsumed = null
| mTop = 478
| mTouchDelegate = null
| mTouchSlop = 21
| mTransformationInfo = android.view.View$TransformationInfo@325602056 (0x13684b08)
| mTransientStateCount = 0
| mTransitionName = null
| mUnscaledDrawingCache = null
| mUnsetPressedState = null
| mUserPaddingBottom = 21
| mUserPaddingEnd = -2147483648
| mUserPaddingLeft = 0
| mUserPaddingLeftInitial = 0
| mUserPaddingRight = 0
| mUserPaddingRightInitial = 0
| mUserPaddingStart = -2147483648
| mVerticalScrollFactor = 0.0
| mVerticalScrollbarPosition = 0
| mViewFlags = 402931717
| mWindowAttachCount = 1
| shadow$_klass_ = com.exampleapp.views.edittexts.PinEditText
| shadow$_monitor_ = 0
* Instance of com.exampleapp.activities.login.PinLoginActivity
| static $change = null
| static serialVersionUID = 2228880800337302055
| static $classOverhead = byte[2336]@319320065 (0x13087001)
| emailLogin = android.support.v7.widget.AppCompatButton@323791872 (0x134cac00)
| pinEditText = com.exampleapp.views.edittexts.PinEditText@323648512 (0x134a7c00)
| progress = com.exampleapp.views.layouts.custom.LoadingSpinner@323647488 (0x134a7800)
| secureNumericKeyboard = com.exampleapp.views.layouts.login.SecureNumericKeyboard@323790848 (0x134ca800)
| presenter = com.exampleapp.mvp.presenters.PinLoginPresenter@324839424 (0x135ca800)
| changeApiAvailable = true
| changeApiDialogShowing = false
| chatMenuState = com.exampleapp.models.enums.ChatMenuState@314590224 (0x12c04410)
| lastCallTimestamp = 0
| loading = false
| progressDialog = null
| sd = com.squareup.seismic.ShakeDetector@321739136 (0x132d5980)
| sensorManager = android.hardware.SystemSensorManager@320114328 (0x13148e98)
| mDelegate = android.support.v7.app.AppCompatDelegateImplN@323260768 (0x13449160)
| mResources = null
| mThemeId = 2131755396
| mCreated = true
| mFragments = android.support.v4.app.FragmentController@320703600 (0x131d8c70)
| mHandler = android.support.v4.app.FragmentActivity$1@321738912 (0x132d58a0)
| mNextCandidateRequestIndex = 0
| mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@324123376 (0x1351baf0)
| mReallyStopped = true
| mRequestedPermissionsFromFragment = false
| mResumed = false
| mRetaining = false
| mStopped = true
| mStartedActivityFromFragment = false
| mStartedIntentSenderFromFragment = false
| mExtraDataMap = android.support.v4.util.SimpleArrayMap@324121816 (0x1351b4d8)
| mLifecycleRegistry = android.arch.lifecycle.LifecycleRegistry@321737536 (0x132d5340)
| mActionBar = null
| mActionModeTypeStarting = 0
| mActivityInfo = android.content.pm.ActivityInfo@323228576 (0x134413a0)
| mActivityTransitionState = android.app.ActivityTransitionState@322946824 (0x133fc708)
| mApplication = com.exampleapp.ExampleApplication@315388256 (0x12cc7160)
| mCalled = true
| mChangeCanvasToTranslucent = false
| mChangingConfigurations = false
| mComponent = android.content.ComponentName@320713504 (0x131db320)
| mConfigChangeFlags = 0
| mCurrentConfig = android.content.res.Configuration@324787808 (0x135bde60)
| mDecor = null
| mDefaultKeyMode = 0
| mDefaultKeySsb = null
| mDestroyed = true
| mDoReportFullyDrawn = false
| mEatKeyUpEvent = false
| mEmbeddedID = null
| mEnableDefaultActionBarUp = false
| mEnterTransitionListener = android.app.SharedElementCallback$1@1890667400 (0x70b14b88)
| mExitTransitionListener = android.app.SharedElementCallback$1@1890667400 (0x70b14b88)
| mFinished = true
| mFragments = android.app.FragmentController@320703728 (0x131d8cf0)
| mHandler = android.os.Handler@321737408 (0x132d52c0)
| mHasCurrentPermissionsRequest = false
| mIdent = 126901483
| mInstanceTracker = android.os.StrictMode$InstanceTracker@320703712 (0x131d8ce0)
| mInstrumentation = android.app.Instrumentation@315145952 (0x12c8bee0)
| mIntent = android.content.Intent@322967864 (0x13401938)
| mLastNonConfigurationInstances = null
| mMainThread = android.app.ActivityThread@315146496 (0x12c8c100)
| mManagedCursors = java.util.ArrayList@324121696 (0x1351b460)
| mManagedDialogs = null
| mMenuInflater = null
| mParent = null
| mReferrer = java.lang.String@320922528 (0x1320e3a0)
| mResultCode = 0
| mResultData = null
| mResumed = false
| mSearchEvent = null
| mSearchManager = null
| mStartedActivity = false
| mStopped = true
| mTaskDescription = android.app.ActivityManager$TaskDescription@321737440 (0x132d52e0)
| mTemporaryPause = false
| mTitle = java.lang.String@315092928 (0x12c7efc0)
| mTitleColor = 0
| mTitleReady = true
| mToken = android.os.BinderProxy@321696960 (0x132cb4c0)
| mTranslucentCallback = null
| mUiThread = java.lang.Thread@1963345648 (0x750646f0)
| mVisibleBehind = false
| mVisibleFromClient = true
| mVisibleFromServer = true
| mVoiceInteractor = null
| mWindow = com.android.internal.policy.PhoneWindow@314831776 (0x12c3f3a0)
| mWindowAdded = true
| mWindowManager = android.view.WindowManagerImpl@324122368 (0x1351b700)
| mInflater = com.android.internal.policy.PhoneLayoutInflater@320850096 (0x131fc8b0)
| mOverrideConfiguration = null
| mResources = android.content.res.Resources@324764064 (0x135b81a0)
| mTheme = android.content.res.Resources$Theme@320703104 (0x131d8a80)
| mThemeResource = 2131755396
| mBase = android.app.ContextImpl@324729344 (0x135afa00)
| shadow$_klass_ = com.exampleapp.activities.login.PinLoginActivity
| shadow$_monitor_ = -2097918190
* Excluded Refs:
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)
Я читал об утечках памяти, и большинство из них, кажется, происходят из статических ссылок и потоков, которые превышают жизненный цикл действия, но используя эти знания, я все еще не могу понять, в чем проблема. Вот код активности:
public class PinLoginActivity extends ExampleActivity<PinLogin.Presenter> implements PinLogin.View {
@BindView(R.id.et_pin)
EditText pinEditText;
@BindView(R.id.keyboard)
SecureNumericKeyboard secureNumericKeyboard;
@BindView(R.id.progress)
LoadingSpinner progress;
@BindView(R.id.btn_email_login)
Button emailLogin;
/**
* Creates intent for starting a new instance of this activity.
*
* @param context activity that will trigger this Intent
* @return Intent for starting a new instance of this activity
*/
public static Intent buildIntent(@NonNull Context context) {
Intent intent = new Intent(context, PinLoginActivity.class);
return intent;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
changeApiAvailable = true;
setContentView(R.layout.activity_pin_login);
ButterKnife.bind(this);
injectDependencies();
secureNumericKeyboard.registerEditText(pinEditText);
}
/**
* Helper method that injects Activity dependencies.
*/
private void injectDependencies() {
ExampleApplication.getUserComponent()
.plus(new PinLoginModule(this))
.inject(this);
}
@OnTextChanged(R.id.et_pin)
public void onPinChange(CharSequence pin) {
}
@OnClick(R.id.btn_email_login)
public void onEmailLoginClicked() {
presenter.onEmailLogin();
}
//region PinLogin.View implementation.
@Override
public void clearPin() {
pinEditText.setText(null);
}
@Override
public void navigateToEmailLogin() {
startActivity(EmailLoginActivity.buildIntent(this, false));
}
@Override
public void navigateToHome(@NonNull UserData userData, @NonNull SessionService sessionService) {
startActivity(IntentUtils.buildHomeIntent(this, userData, sessionService));
}
@Override
public void navigateToVerifyEmail(String emailToVerify, String userId) {
startActivity(VerifyEmailActivity.buildIntent(this, emailToVerify, userId, true));
finish();
}
@Override
public void showLoading(LoadingState state, View otherView) {
switch (state) {
case LOADING:
pinEditText.setVisibility(View.INVISIBLE);
emailLogin.setVisibility(View.INVISIBLE);
secureNumericKeyboard.setVisibility(View.INVISIBLE);
progress.setVisibility(View.VISIBLE);
break;
case FAILED:
pinEditText.setVisibility(View.VISIBLE);
emailLogin.setVisibility(View.VISIBLE);
secureNumericKeyboard.setVisibility(View.VISIBLE);
progress.setVisibility(View.INVISIBLE);
break;
case COMPLETE:
pinEditText.setVisibility(View.INVISIBLE);
emailLogin.setVisibility(View.INVISIBLE);
secureNumericKeyboard.setVisibility(View.INVISIBLE);
progress.setVisibility(View.VISIBLE);
break;
default:
}
}
@Override
public void onStop() {
super.onStop();
secureNumericKeyboard.unregisterEditText(pinEditText);
}
public boolean shouldClearActivities() {
return true;
}
//endregion
}
Пожалуйста, кто-нибудь может указать мне правильное направление, чтобы исправить эту утечку памяти? Я могу опубликовать больше кода, если это необходимо.