Ok, smart casts and nullability in single-threaded environments are the reasons why I joined this forum, so… hi all
Since Kotlin can be used now as a language of choice for Android, there is a big reason for having something like this: keeping view elements as a fields in Fragments or Activities (etc.).
Consider following example:
class PlayerComboFragment : Fragment() {
private val mScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
// ...
}
}
private var mPlayerViewModel: PlayerViewModel? = null
private var mRecyclerView: RecyclerView? = null
private var mSnapHelper: LinearSnapHelper? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mPlayerViewModel = PlayerViewModel(activity.settingsManager,
activity.messageExchangeHelper, activity.ambientModeStateProvider,
activity.musicLibraryNavigator)
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.player_combo_view, container, false)
mRecyclerView = view.findViewById(R.id.recycler_view) as RecyclerView
mRecyclerView!!.layoutManager = SmoothScrollingLinearLayoutManager(activity)
mRecyclerView!!.adapter = MainRecyclerViewAdapter(mPlayerViewModel!!)
mRecyclerView!!.scrollToPosition(1)
mRecyclerView!!.addOnScrollListener(mScrollListener)
mSnapHelper = LinearSnapHelper()
mSnapHelper!!.attachToRecyclerView(mRecyclerView)
return view
}
override fun onResume() {
super.onResume()
mPlayerViewModel!!.onResume()
}
override fun onPause() {
mPlayerViewModel!!.onPause()
super.onPause()
}
override fun onDestroyView() {
mRecyclerView!!.removeOnScrollListener(mScrollListener)
mRecyclerView!!.adapter = null
mRecyclerView!!.layoutManager = null
mSnapHelper!!.attachToRecyclerView(null)
super.onDestroyView()
}
override fun onDestroy() {
super.onDestroy()
mPlayerViewModel = null
}
}
The number of exclamation marks is just annoying. Workarounds like a local variable or using let and so on do not convince me at all. All the work is done on the UI thread, fields are private, so there’s no way that anyone could ever nullify these. Not to mention that even trying to fiddle with UI elements from another thread would cause a big mess… It is really a common practice, to find/create view and then configure it.
Going a bit further, I could also live with something like this:
override fun onDestroyView() {
mRecyclerView!!.removeOnScrollListener(mScrollListener)
mRecyclerView.adapter = null
mRecyclerView.layoutManager = null
mSnapHelper!!.attachToRecyclerView(null)
super.onDestroyView()
}
I mean it should be pretty much enough to just do “!!” on mRecyclerView once in this scope, without a need to do it two more times below - as this is still the same, single-thread fragment, it would throw NPE anyway before reaching the further code.
Actually I’d even prefer a shorter solution - a keyword that we could place next to “var”, to make compiler happy