https://kotlinlang.org logo
#android
Title
# android
g

gsala

04/04/2019, 11:08 AM
Is getting references to views in an Activity like this considered a bad practice ?
Copy code
val button : Button by lazy {
    findViewById(R.id.button)
}
r

ribesg

04/04/2019, 11:13 AM
Well if you put that code inside an Activity directly, then yes, it’s very bad.
s

sindrenm

04/04/2019, 11:14 AM
I've had issues with this in the past with navigating back to fragments, at least. Remember that the fragment/activity might be destroyed while the actual object might still exist.
👍 1
g

gsala

04/04/2019, 11:20 AM
@ribesg why do you think so? @sindrenm what do you mean with "the actual object?" the fragment/activity? or the view? or the lazy?
r

ribesg

04/04/2019, 11:22 AM
Well inside a
Fragment
it’s wrong, but inside an
Activity
it may be ok
g

gsala

04/04/2019, 11:23 AM
@ribesg what's the reason
r

ribesg

04/04/2019, 11:23 AM
Look at the Fragment lifecycle

https://developer.android.com/images/fragment_lifecycle.png

See how the view can be destroyed then re-created in the same Fragment instance. You then have (in your case) a reference to a Button that is no longer attached to anything, and which is NOT the Button displayed on screen.
👍 3
g

ghosalmartin

04/04/2019, 11:26 AM
maybe just easier to use synthetics and not bother with onCreateView or only use onCreateView to inflate your fragment and use synthetics in onViewCreated
👍 1
s

sindrenm

04/04/2019, 11:28 AM
I use synthetic imports myself and haven't had problems with them. Although I tend to also keep references to them in the activity/fragment as well, but through “virtual” properties with a getter:
Copy code
private val button: Button
  get() = the_button_in_the_layout // synthetically imported
g

gsala

04/04/2019, 11:29 AM
@ribesg Makes sense, thanks 👍
What if I was to keep a reference to the whole View like so
Copy code
private val rootView : View by lazy { inflateView() }

override fun onCreateView(): View{
    return rootView
}
Would this be bad practice ?
r

ribesg

04/04/2019, 11:34 AM
Or just don’t use XML views 😛
@gsala don’t start to work around the android lifecycle, it’s a very dark path. Just deal with it
g

gsala

04/04/2019, 11:36 AM
I'm not doing any of these things. But I needed to understand the reason behind why it's not a good idea
r

ribesg

04/04/2019, 11:37 AM
You can safely do that
Copy code
val button : Button
    get() = findViewById(R.id.button)
But in this case you may end up calling
button
multiple times in the same function like it’s nothing. Well, it’s not huge, but it’s better to have a local var and call
findViewById
only once if you can
g

gsala

04/04/2019, 11:39 AM
KotterKnife (https://github.com/JakeWharton/kotterknife/blob/master/src/main/kotlin/kotterknife/ButterKnife.kt) appears to be implemented like the first case though
r

ribesg

04/04/2019, 11:41 AM
That’s not what I’m understanding from the link you give
g

gsala

04/04/2019, 11:44 AM
🤔 How do you understand the implementation then?
s

sindrenm

04/04/2019, 11:47 AM
@ribesg: Note that I was using a getter together with synthetic imports, which does in fact cache the views for you. Just so there's no misunderstanding. simple smile
r

ribesg

04/04/2019, 11:48 AM
@sindrenm Yes, it would be best but if you have synthetic imports you just use them directly usually
@gsala I don’t know, I don’t see anything returning a lazy val. Wait I’m not sure I read this code correctly
s

sindrenm

04/04/2019, 11:49 AM
Yeah, but some people use snake_case in IDs and some people use prefixes (e.g.
signInEmailAddressEditText
), so I prefer to keep track of them in property getters. simple smile
r

ribesg

04/04/2019, 11:52 AM
@gsala oh, I see. Nothing tells you to bind your views as property though. The given example is inside a ViewGroup
g

gsala

04/04/2019, 11:54 AM
True. I'm now reading through the conversation that spawned this reply : https://kotlinlang.slack.com/archives/C0B8M7BUY/p1532693549000239
r

ribesg

04/04/2019, 11:54 AM
In ButterKnife, you should call
ButterKnife.bind(this);
after the view has been created to replace the instances by the ones for the newly created view, which dereferences old views in the process
s

sindrenm

04/04/2019, 11:58 AM
Indeed, but that thread is so 2018. 😏
r

ribesg

04/04/2019, 11:58 AM
For me the best way is not to have XML anyway
Just have your views with direct references to what you need. Anko was great for that, now you should use Splitties View DSL instead
s

sindrenm

04/04/2019, 12:02 PM
Yeah, Anko was great for that and Splitties probably is, but I'm just so incredibly used to the preview thingymabob that I've grown quite dependent on it. Although I don't seem to need it when writing Flutter apps (a whole discussion all in its own, I guess), but then again that has proper hot reloading. 😛
r

ribesg

04/04/2019, 12:14 PM
Both Anko and Splitties support preview in IDE
I don’t use it much, as when you write Kotlin code you just know what it will look like, but it works. You can’t build your view graphically, which is a good thing because usually the graphical editor writes things you don’t want/need
s

sindrenm

04/04/2019, 12:24 PM
Yah, they do support it, but you'll have to build the code first, which is not the case for XML layouts. And while I usually know what I want, it's a whole lot easier to be able to preview my constraint layouts while writing it. And no, I don't build my layouts graphically, I prefer having full control over the resulting XML. Although, to be fair, the WYSIWYG editor does usually build decent XML.
r

ribesg

04/04/2019, 12:37 PM
It’s not like writing views with code is long, compared to XML
You start with something like
Copy code
class MainView(override val ctx: Context) : Ui {

    override val root = constraintLayout ()

}
s

sindrenm

04/04/2019, 12:40 PM
Oh, I know it's not long. I really like the idea behind it. And I did use Anko UI for a while. But complex views are a bit … complex.
But I feel like we digress from the original question. Let's leave it at that. 😛
r

ribesg

04/04/2019, 12:42 PM
Copy code
class MainView(override val ctx: Context) : Ui {

    val myTextView =
        textView {
            textResource = R.string.my_string
        }

    override val root = constraintLayout {

        add(myTextView, lParams {
            centerInParent()
        })

    }

}
Splitties is better than Anko, it works differently and fixes some general issues. And for complex views, you can very easily split them in multiple files. It’s also a lot better to just have your views there, like
myTextView
in my example. It’s just there. In my Activity/Fragment I just have
view.myTextView
. Also parsing XML is something not-trivial in terms of resources 😛
s

sindrenm

04/04/2019, 12:52 PM
As I said, I really like the concept, no need to convince me. Like, I love having stuff like
centerInParent()
, for instance. But the preview is not as good as it is with XML layouts. Also, the XML files aren't shipped as XML, it's binary. simple smile
r

ribesg

04/04/2019, 1:07 PM
Was talking about the preview 😛
s

sindrenm

04/04/2019, 1:08 PM
Oh, right. Yeah, that's definitely not for free. 😛
z

zhuinden

04/04/2019, 3:58 PM
If you can, you should most likely disable thread safety over this, it's not like you need double-check lock synchronization to get a view from your view's... views. Lately it is easier to just use Kotlin synthetics
👍 2
l

Lou Morda

04/04/2019, 10:22 PM
I'm also a big fan of Kotlin synthetics
r

rkeazor

04/05/2019, 3:11 AM
Bigger fan of databinding 😔
l

Lou Morda

06/27/2019, 11:59 PM
Came back to this 3 months later, looks like kotlin synthetics are not very performance friendly! Need to learn databinding asap. Also just found kotterknife, wondering how that will be
r

rkeazor

06/28/2019, 2:52 AM
Better off learning databinding