I add leak canary to my app and I find this memory leak: https://i.imgur.com/8nFOoH4.png
I don't use at my MainActivity LinearLayout or Toast but I has this leak and I can't understand why and how. Maybe it because I use toasts and linear layout inside fragments that I use in MainActivity?
Here is my MainActivity xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/lost_connection_image_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/fullscreen_exit"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/userPhoto"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:layout_margin="8dp"
android:background="@android:color/transparent"
android:src="@drawable/account_default"
android:visibility="visible"
tools:layout_editor_absoluteX="312dp"
tools:layout_editor_absoluteY="4dp"/>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="8dp"
app:cardBackgroundColor="@android:color/background_light"
app:cardCornerRadius="1dp"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="28dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true">
<EditText
android:id="@+id/search_field"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="@null"
android:ems="10"
android:hint="@string/search_for"
android:imeOptions="actionSearch"
android:inputType="text"
android:singleLine="true"
android:textColorHint="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/search"
app:layout_constraintStart_toStartOf=" parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/search"/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</android.support.v7.widget.Toolbar>
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toTopOf="@+id/navigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
</FrameLayout>
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
app:itemIconTint="@color/bottom_nav_selected"
app:itemTextColor="@color/bottom_nav_selected"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/menu_main"/>
</android.support.constraint.ConstraintLayout>
And one of fragments that I put in FrameLayout with id "container":
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:id="@+id/home_fragment_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
android:visibility="invisible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent">
<com.bondpm.bond.customViews.WrapContentViewPager
android:id="@+id/viewPager"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/background_light"
android:focusable="true"
android:padding="0dp"
app:cardBackgroundColor="@android:color/background_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.rd.PageIndicatorView
android:id="@+id/pageIndicatorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="@id/viewPager"
app:layout_constraintEnd_toEndOf="@+id/viewPager"
app:layout_constraintStart_toStartOf="parent"
app:piv_animationType="scale"
app:piv_dynamicCount="true"
app:piv_interactiveAnimation="true"
app:piv_viewPager="@id/viewPager"/>
</android.support.constraint.ConstraintLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/home_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pageIndicatorView"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"/>
</RelativeLayout>
Here MainActivity code:
class MainActivity : BaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener, MainActivityView.View {
private val presenter = MainActivityPresenter()
private val TAG = this::class.java.simpleName
private val homeFragment = HomeFragment()
private val exploreFragment = ExploreFragment()
private val feedsFragment = FeedsFragment()
private var currentTabTag = "home"
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.home -> openFragment(homeFragment, "home")
R.id.explore -> openFragment(exploreFragment, "explore")
R.id.feeds -> openFragment(feedsFragment, "feeds")
}
return true
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter.attachView(this)
if (savedInstanceState != null || !Utils.isLogined) {
if (savedInstanceState != null) {
currentTabTag = savedInstanceState.getString("currentTab")
if (Utils.userInfo != null && Utils.userInfo?.data?.user?.photo != null) Glide.with(this).load(Utils.userInfo!!.data.user.photo).into(userPhoto)
else userPhoto.setImageResource(RBase.drawable.account_default)
}
userPhoto.setOnClickListener {
next()
}
userInterfaceInit()
} else presenter.getUserInfo()
}
private fun userInterfaceInit() {
navigationView.setOnNavigationItemSelectedListener(this)
navigationView.menu.getItem(0).isChecked = true
// search_field.text = SpannableStringBuilder("")
search.setOnClickListener{
if(search_field.text.toString() != "") {
val intent = Intent(this, SearchActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
intent.putExtra("query", search_field.text.toString())
startActivity(intent)
}
}
search_field.setOnEditorActionListener(TextView.OnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
if(search_field.text.toString() != "") {
val intent = Intent(this, SearchActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
intent.putExtra("query", search_field.text.toString())
startActivity(intent)
}
return@OnEditorActionListener true
}
false
})
Log.d(TAG, currentTabTag)
when (currentTabTag) {
"home" -> openFragment(homeFragment, "home")
"explore" -> openFragment(exploreFragment, "explore")
"feeds" -> openFragment(feedsFragment, "feeds")
}
userPhoto.setOnClickListener {
next()
}
setSupportActionBar(toolbar)
supportActionBar!!.title = ""
}
private fun openFragment(fragment: Fragment, tag: String) {
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.container, fragment, tag)
currentTabTag = tag
if (!isFinishing &&!isDestroyed) transaction.commitAllowingStateLoss()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState!!.putString("currentTab", currentTabTag)
}
override fun showUserInfo() {
if (Utils.userInfo != null && Utils.userInfo!!.data.user.photo != null) Glide.with(this).load(Utils.userInfo!!.data.user.photo).into(userPhoto)
else userPhoto.setImageResource(RBase.drawable.account_default)
userInterfaceInit()
}
override fun showMessage(resId: Int) {
//Toast.makeText(applicationContext, resId, Toast.LENGTH_LONG).show()
}
override fun onDestroy() {
super.onDestroy()
presenter.detachView()
presenter.destroy()
}
DEFINITION A memory leak is the gradual deterioration of system performance that occurs over time as the result of the fragmentation of a computer's RAM due to poorly designed or programmed applications that fail to free up memory segments when they are no longer needed.
To find a memory leak, look at how much RAM the system is using. The Resource Monitor in Windows can be used to accomplish this. In Windows 8.1 and Windows 10: To open the Run dialogue, press Windows+R, then type "resmon" and click OK.
Very dangerous. Memory leaks in the kernel level lead to serious system stability issues. Kernel memory is very limited compared to user land memory and should be handled cautiously. Memory is allocated but never freed.
Physical or permanent damage does not happen from memory leaks. Memory leaks are strictly a software issue, causing performance to slow down among applications within a given system. It should be noted a program taking up a lot of RAM space is not an indicator that memory is leaking.
Looks like your toast lived longer than parent activity. Try to use Application as a Context. Like in your commented code:
Toast.makeText(applicationContext, resId, Toast.LENGTH_LONG).show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With