先日Google Playに趣味で作ったアプリを初リリースしたのですが、
そのアプリ開発中にメモリリークが頻発していることが分かり、メモリリークってどう直せばいいんだ?と色々調べたり試したりして解決したことを残しておこうと思います。
なぜメモリリークしていると気づいたか
アプリ開発もいよいよ終盤をむかえる頃、ふと「そういえば会社で作っているアプリにはLeakCanaryってライブラリを入れていたなあ」と思い入れてみたのでした。
LeakCanaryはメモリリークを検出してくれるライブラリですが、これを入れたところすぐにメモリリークが発生しました・・・/(^o^)\

何が原因だったか
私の場合、2つありました。
①DataBindingを開放していなかった
②変数がViewを参照している場合に開放していなかった
それぞれ詳しく書いていきます。
①DataBindingを開放していなかった

[修正前]
private lateinit var binding: FragmentEditBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentEditBinding.inflate(inflater, container, false)
binding.lifecycleOwner = this
return binding.root
}
[修正後]
private var _binding: FragmentEditBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentEditBinding.inflate(inflater, container, false)
binding.lifecycleOwner = this
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
もともとDataBindingを非オプショナル型でlateinitで保持していたのですが、
オプショナル型の_bindingを定義し、bindingでは_bindingを取得するようにしました。
また、onDestroyView()で解放するようにしたことで、LeakCanaryで検知されなくなりました。
これはViewBindingの公式サイトに載っていた方法です。
https://developer.android.com/topic/libraries/view-binding?hl=ja#fragments
以下のサイトでも紹介されていました。
②変数がViewを参照している場合に開放していなかった

以下の12-13行目を追加しました。
private var itemTouchHelper : ItemTouchHelper? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
itemTouchHelper?.attachToRecyclerView(binding.recyclerView)
}
override fun onDestroyView() {
super.onDestroyView()
binding.recyclerView.adapter = null
recyclerViewAdapter = null
itemTouchHelper?.attachToRecyclerView(null)
itemTouchHelper = null
_binding = null
}
ItemTouchHelperは、attachToRecyclerView()でRecyclerViewの参照を持ちます。
これを変数で持っていると、RecyclerViewの参照が残り続けてしまいます。
ItemTouchHelper以外にも、変数がViewを参照している場合は解放してあげる必要がありました。

コメントを残す