Skip to content

Commit 72b77aa

Browse files
committed
Replace findViewById and Kotlin synthetics with ViewBinding
ViewBinding is a common tool and it's an official best practice recommended by Google.
1 parent 637d8fb commit 72b77aa

File tree

7 files changed

+91
-71
lines changed

7 files changed

+91
-71
lines changed

samplekotlin/build.gradle

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
21
apply plugin: 'com.android.application'
32
apply plugin: 'kotlin-android'
4-
apply plugin: 'kotlin-android-extensions'
53

64
android {
7-
compileSdkVersion 29
5+
compileSdkVersion 30
86
defaultConfig {
97
applicationId "com.example.chattutorial"
108
minSdkVersion 21
@@ -23,13 +21,18 @@ android {
2321
}
2422

2523
compileOptions {
24+
sourceCompatibility JavaVersion.VERSION_1_8
2625
targetCompatibility JavaVersion.VERSION_1_8
2726
}
2827

2928
kotlinOptions {
3029
jvmTarget = JavaVersion.VERSION_1_8.toString()
3130
}
3231

32+
buildFeatures {
33+
viewBinding true
34+
}
35+
3336
packagingOptions {
3437
exclude 'META-INF/*.kotlin_module'
3538
}
@@ -42,6 +45,6 @@ dependencies {
4245

4346
implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.0-beta1"
4447
implementation "androidx.appcompat:appcompat:1.2.0"
45-
implementation "androidx.constraintlayout:constraintlayout:2.0.3"
48+
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
4649
implementation 'androidx.activity:activity-ktx:1.1.0'
4750
}

samplekotlin/src/main/java/com/example/chattutorial/AttachmentViewHolderImgur.kt

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@ package com.example.chattutorial
33
import android.view.LayoutInflater
44
import android.view.ViewGroup
55
import coil.load
6+
import com.example.chattutorial.databinding.ListItemAttachImgurBinding
67
import com.getstream.sdk.chat.adapter.AttachmentListItem
78
import com.getstream.sdk.chat.adapter.MessageListItem
89
import com.getstream.sdk.chat.adapter.viewholder.attachment.BaseAttachmentViewHolder
9-
import com.getstream.sdk.chat.utils.roundedImageView.PorterShapeImageView
1010
import com.getstream.sdk.chat.view.MessageListView
11-
import kotlinx.android.synthetic.main.list_item_attach_imgur.view.*
1211

1312
class AttachmentViewHolderImgur(
1413
parent: ViewGroup,
1514
private val bubbleHelper: MessageListView.BubbleHelper,
16-
private val messageItem: MessageListItem.MessageItem
17-
) : BaseAttachmentViewHolder(
18-
LayoutInflater.from(parent.context)
19-
.inflate(R.layout.list_item_attach_imgur, parent, false)
20-
) {
21-
22-
private val ivMediaThumb: PorterShapeImageView = itemView.iv_media_thumb
15+
private val messageItem: MessageListItem.MessageItem,
16+
private val binding: ListItemAttachImgurBinding = ListItemAttachImgurBinding.inflate(
17+
LayoutInflater.from(parent.context), parent, false
18+
)
19+
) : BaseAttachmentViewHolder(binding.root) {
2320

2421
override fun bind(attachmentListItem: AttachmentListItem) {
2522
val background = bubbleHelper.getDrawableForAttachment(
@@ -28,9 +25,9 @@ class AttachmentViewHolderImgur(
2825
messageItem.positions,
2926
attachmentListItem.attachment
3027
)
31-
ivMediaThumb.setShape(context, background)
28+
binding.ivMediaThumb.setShape(context, background)
3229

33-
ivMediaThumb.load(attachmentListItem.attachment.thumbUrl) {
30+
binding.ivMediaThumb.load(attachmentListItem.attachment.thumbUrl) {
3431
allowHardware(false)
3532
}
3633
}

samplekotlin/src/main/java/com/example/chattutorial/ChannelActivity.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import android.os.Bundle
66
import androidx.activity.addCallback
77
import androidx.activity.viewModels
88
import androidx.appcompat.app.AppCompatActivity
9-
import com.getstream.sdk.chat.view.ChannelHeaderView
10-
import com.getstream.sdk.chat.view.MessageListView
9+
import com.example.chattutorial.databinding.ActivityChannelBinding
1110
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModel
1211
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel
1312
import com.getstream.sdk.chat.viewmodel.bindView
@@ -19,11 +18,16 @@ import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.Navi
1918
import com.getstream.sdk.chat.viewmodel.messages.bindView
2019
import io.getstream.chat.android.client.models.Channel
2120

21+
class ChannelActivity : AppCompatActivity() {
2222

23-
class ChannelActivity : AppCompatActivity(R.layout.activity_channel) {
23+
private lateinit var binding: ActivityChannelBinding
2424

2525
override fun onCreate(savedInstanceState: Bundle?) {
2626
super.onCreate(savedInstanceState)
27+
28+
binding = ActivityChannelBinding.inflate(layoutInflater)
29+
setContentView(binding.root)
30+
2731
val cid = checkNotNull(intent.getStringExtra(CID_KEY)) {
2832
"Specifying a channel id is required when starting ChannelActivity"
2933
}
@@ -37,11 +41,9 @@ class ChannelActivity : AppCompatActivity(R.layout.activity_channel) {
3741
// TODO set custom AttachmentViewHolderFactory
3842

3943
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
40-
val channelHeaderView: ChannelHeaderView = findViewById(R.id.channelHeaderView)
41-
val messageListView: MessageListView = findViewById(R.id.messageListView)
42-
channelHeaderViewModel.bindView(channelHeaderView, this)
43-
messageListViewModel.bindView(messageListView, this)
44-
messageInputViewModel.bindView(findViewById(R.id.messageInputView), this)
44+
channelHeaderViewModel.bindView(binding.channelHeaderView, this)
45+
messageListViewModel.bindView(binding.messageListView, this)
46+
messageInputViewModel.bindView(binding.messageInputView, this)
4547

4648
// Step 3 - Let the message input know when we open a thread
4749
messageListViewModel.mode.observe(this) { mode ->
@@ -52,7 +54,7 @@ class ChannelActivity : AppCompatActivity(R.layout.activity_channel) {
5254
}
5355

5456
// Step 4 - Let the message input know when we are editing a message
55-
messageListView.setOnMessageEditHandler {
57+
binding.messageListView.setOnMessageEditHandler {
5658
messageInputViewModel.editMessage.postValue(it)
5759
}
5860

@@ -64,11 +66,11 @@ class ChannelActivity : AppCompatActivity(R.layout.activity_channel) {
6466
}
6567

6668
// Step 6 - Handle back button behaviour correctly when you're in a thread
67-
channelHeaderView.onBackClick = {
69+
binding.channelHeaderView.onBackClick = {
6870
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
6971
}
7072
onBackPressedDispatcher.addCallback(this) {
71-
channelHeaderView.onBackClick()
73+
binding.channelHeaderView.onBackClick()
7274
}
7375
}
7476

samplekotlin/src/main/java/com/example/chattutorial/ChannelActivity2.kt

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.os.Bundle
66
import androidx.activity.addCallback
77
import androidx.activity.viewModels
88
import androidx.appcompat.app.AppCompatActivity
9+
import com.example.chattutorial.databinding.ActivityChannel2Binding
910
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModel
1011
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel
1112
import com.getstream.sdk.chat.viewmodel.bindView
@@ -16,14 +17,17 @@ import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Threa
1617
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp
1718
import com.getstream.sdk.chat.viewmodel.messages.bindView
1819
import io.getstream.chat.android.client.models.Channel
19-
import kotlinx.android.synthetic.main.activity_channel.channelHeaderView
20-
import kotlinx.android.synthetic.main.activity_channel.messageInputView
21-
import kotlinx.android.synthetic.main.activity_channel.messageListView
2220

23-
class ChannelActivity2 : AppCompatActivity(R.layout.activity_channel_2) {
21+
class ChannelActivity2 : AppCompatActivity() {
22+
23+
private lateinit var binding: ActivityChannel2Binding
2424

2525
override fun onCreate(savedInstanceState: Bundle?) {
2626
super.onCreate(savedInstanceState)
27+
28+
binding = ActivityChannel2Binding.inflate(layoutInflater)
29+
setContentView(binding.root)
30+
2731
val cid = checkNotNull(intent.getStringExtra(CID_KEY)) {
2832
"Specifying a channel id is required when starting ChannelActivity2"
2933
}
@@ -35,12 +39,12 @@ class ChannelActivity2 : AppCompatActivity(R.layout.activity_channel_2) {
3539
val messageInputViewModel: MessageInputViewModel by viewModels { factory }
3640

3741
// Set custom AttachmentViewHolderFactory
38-
messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
42+
binding.messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
3943

4044
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
41-
channelHeaderViewModel.bindView(channelHeaderView, this)
42-
messageListViewModel.bindView(messageListView, this)
43-
messageInputViewModel.bindView(messageInputView, this)
45+
channelHeaderViewModel.bindView(binding.channelHeaderView, this)
46+
messageListViewModel.bindView(binding.messageListView, this)
47+
messageInputViewModel.bindView(binding.messageInputView, this)
4448

4549
// Step 3 - Let the message input know when we open a thread
4650
messageListViewModel.mode.observe(this) { mode ->
@@ -58,16 +62,16 @@ class ChannelActivity2 : AppCompatActivity(R.layout.activity_channel_2) {
5862
}
5963

6064
// Step 5 - Let the message input know when we are editing a message
61-
messageListView.setOnMessageEditHandler {
65+
binding.messageListView.setOnMessageEditHandler {
6266
messageInputViewModel.editMessage.postValue(it)
6367
}
6468

6569
// Step 6 - Handle back button behaviour correctly when you're in a thread
66-
channelHeaderView.onBackClick = {
70+
binding.channelHeaderView.onBackClick = {
6771
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
6872
}
6973
onBackPressedDispatcher.addCallback(this) {
70-
channelHeaderView.onBackClick()
74+
binding.channelHeaderView.onBackClick()
7175
}
7276
}
7377

samplekotlin/src/main/java/com/example/chattutorial/ChannelActivity3.kt

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.os.Bundle
66
import androidx.activity.addCallback
77
import androidx.activity.viewModels
88
import androidx.appcompat.app.AppCompatActivity
9+
import com.example.chattutorial.databinding.ActivityChannel3Binding
910
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModel
1011
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel
1112
import com.getstream.sdk.chat.viewmodel.bindView
@@ -18,16 +19,17 @@ import com.getstream.sdk.chat.viewmodel.messages.bindView
1819
import io.getstream.chat.android.client.models.Channel
1920
import io.getstream.chat.android.client.models.name
2021
import io.getstream.chat.android.livedata.ChatDomain
21-
import io.getstream.chat.android.livedata.controller.ChannelController
22-
import kotlinx.android.synthetic.main.activity_channel.channelHeaderView
23-
import kotlinx.android.synthetic.main.activity_channel.messageInputView
24-
import kotlinx.android.synthetic.main.activity_channel.messageListView
25-
import kotlinx.android.synthetic.main.activity_channel_3.typingHeader
2622

27-
class ChannelActivity3 : AppCompatActivity(R.layout.activity_channel_3) {
23+
class ChannelActivity3 : AppCompatActivity() {
24+
25+
private lateinit var binding: ActivityChannel3Binding
2826

2927
override fun onCreate(savedInstanceState: Bundle?) {
3028
super.onCreate(savedInstanceState)
29+
30+
binding = ActivityChannel3Binding.inflate(layoutInflater)
31+
setContentView(binding.root)
32+
3133
val cid = checkNotNull(intent.getStringExtra(CID_KEY)) {
3234
"Specifying a channel id is required when starting ChannelActivity3"
3335
}
@@ -39,12 +41,12 @@ class ChannelActivity3 : AppCompatActivity(R.layout.activity_channel_3) {
3941
val messageInputViewModel: MessageInputViewModel by viewModels { factory }
4042

4143
// Set custom AttachmentViewHolderFactory
42-
messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
44+
binding.messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
4345

4446
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
45-
channelHeaderViewModel.bindView(channelHeaderView, this)
46-
messageListViewModel.bindView(messageListView, this)
47-
messageInputViewModel.bindView(messageInputView, this)
47+
channelHeaderViewModel.bindView(binding.channelHeaderView, this)
48+
messageListViewModel.bindView(binding.messageListView, this)
49+
messageInputViewModel.bindView(binding.messageInputView, this)
4850

4951
// Step 3 - Let the message input know when we open a thread
5052
messageListViewModel.mode.observe(this) { mode ->
@@ -62,28 +64,29 @@ class ChannelActivity3 : AppCompatActivity(R.layout.activity_channel_3) {
6264
}
6365

6466
// Step 5 - Let the message input know when we are editing a message
65-
messageListView.setOnMessageEditHandler {
67+
binding.messageListView.setOnMessageEditHandler {
6668
messageInputViewModel.editMessage.postValue(it)
6769
}
6870

6971
// Step 6 - Handle back button behaviour correctly when you're in a thread
70-
channelHeaderView.onBackClick = {
72+
binding.channelHeaderView.onBackClick = {
7173
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
7274
}
7375
onBackPressedDispatcher.addCallback(this) {
74-
channelHeaderView.onBackClick()
76+
binding.channelHeaderView.onBackClick()
7577
}
7678

7779
// Custom typing info header bar
7880
val nobodyTyping = "nobody is typing"
79-
typingHeader.text = nobodyTyping
81+
binding.typingHeader.text = nobodyTyping
8082

8183
// Obtain a ChannelController
82-
val channelController = ChatDomain.instance().useCases.getChannelController(cid).execute().data()
84+
val channelController =
85+
ChatDomain.instance().useCases.getChannelController(cid).execute().data()
8386

8487
// Observe typing users
8588
channelController.typing.observe(this) { users ->
86-
typingHeader.text = when {
89+
binding.typingHeader.text = when {
8790
users.isNotEmpty() -> users.joinToString(prefix = "typing: ") { user -> user.name }
8891
else -> nobodyTyping
8992
}

samplekotlin/src/main/java/com/example/chattutorial/ChannelActivity4.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.os.Bundle
66
import androidx.activity.addCallback
77
import androidx.activity.viewModels
88
import androidx.appcompat.app.AppCompatActivity
9+
import com.example.chattutorial.databinding.ActivityChannel4Binding
910
import com.getstream.sdk.chat.viewmodel.ChannelHeaderViewModel
1011
import com.getstream.sdk.chat.viewmodel.MessageInputViewModel
1112
import com.getstream.sdk.chat.viewmodel.bindView
@@ -16,15 +17,17 @@ import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.Mode.Threa
1617
import com.getstream.sdk.chat.viewmodel.messages.MessageListViewModel.State.NavigateUp
1718
import com.getstream.sdk.chat.viewmodel.messages.bindView
1819
import io.getstream.chat.android.client.models.Channel
19-
import kotlinx.android.synthetic.main.activity_channel.channelHeaderView
20-
import kotlinx.android.synthetic.main.activity_channel.messageInputView
21-
import kotlinx.android.synthetic.main.activity_channel.messageListView
22-
import kotlinx.android.synthetic.main.activity_channel_3.typingHeader
2320

24-
class ChannelActivity4 : AppCompatActivity(R.layout.activity_channel_4) {
21+
class ChannelActivity4 : AppCompatActivity() {
22+
23+
private lateinit var binding: ActivityChannel4Binding
2524

2625
override fun onCreate(savedInstanceState: Bundle?) {
2726
super.onCreate(savedInstanceState)
27+
28+
binding = ActivityChannel4Binding.inflate(layoutInflater)
29+
setContentView(binding.root)
30+
2831
val cid = checkNotNull(intent.getStringExtra(CID_KEY)) {
2932
"Specifying a channel id is required when starting ChannelActivity"
3033
}
@@ -36,12 +39,12 @@ class ChannelActivity4 : AppCompatActivity(R.layout.activity_channel_4) {
3639
val messageInputViewModel: MessageInputViewModel by viewModels { factory }
3740

3841
// Set custom AttachmentViewHolderFactory
39-
messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
42+
binding.messageListView.setAttachmentViewHolderFactory(MyAttachmentViewHolderFactory())
4043

4144
// Step 2 - Bind the view and ViewModels, they are loosely coupled so it's easy to customize
42-
channelHeaderViewModel.bindView(channelHeaderView, this)
43-
messageListViewModel.bindView(messageListView, this)
44-
messageInputViewModel.bindView(messageInputView, this)
45+
channelHeaderViewModel.bindView(binding.channelHeaderView, this)
46+
messageListViewModel.bindView(binding.messageListView, this)
47+
messageInputViewModel.bindView(binding.messageInputView, this)
4548

4649
// Step 3 - Let the message input know when we open a thread
4750
messageListViewModel.mode.observe(this) { mode ->
@@ -59,21 +62,21 @@ class ChannelActivity4 : AppCompatActivity(R.layout.activity_channel_4) {
5962
}
6063

6164
// Step 5 - Let the message input know when we are editing a message
62-
messageListView.setOnMessageEditHandler {
65+
binding.messageListView.setOnMessageEditHandler {
6366
messageInputViewModel.editMessage.postValue(it)
6467
}
6568

6669
// Step 6 - Handle back button behaviour correctly when you're in a thread
67-
channelHeaderView.onBackClick = {
70+
binding.channelHeaderView.onBackClick = {
6871
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
6972
}
7073
onBackPressedDispatcher.addCallback(this) {
71-
channelHeaderView.onBackClick()
74+
binding.channelHeaderView.onBackClick()
7275
}
7376

7477
// Custom typing info header bar
7578
val nobodyTyping = "nobody is typing"
76-
typingHeader.text = nobodyTyping
79+
binding.typingHeader.text = nobodyTyping
7780

7881
val currentlyTyping = mutableSetOf<String>()
7982
// TODO update when new SDK version is out
@@ -90,7 +93,7 @@ class ChannelActivity4 : AppCompatActivity(R.layout.activity_channel_4) {
9093
is TypingStopEvent -> currentlyTyping.remove(event.user.name)
9194
}
9295
93-
typingHeader.text = when {
96+
binding.typingHeader.text = when {
9497
currentlyTyping.isNotEmpty() -> currentlyTyping.joinToString(prefix = "typing: ")
9598
else -> nobodyTyping
9699
}

0 commit comments

Comments
 (0)