Skip to content

Commit

Permalink
Support reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
wada811 committed Oct 26, 2020
1 parent 2dfcae0 commit 19c31b9
Show file tree
Hide file tree
Showing 13 changed files with 42 additions and 788 deletions.
63 changes: 21 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,37 @@ ViewBinding-ktx
For saving memory, you should set the `binding` variable to null after onDestroyView.

## Overview
- `ViewBinding-ktx` provide the unified way of declaring the `binding` variable in Activity and Fragment.
- `ViewBinding-ktx` is saving memory because of cleaning up the `binding` variable having the view tree after onDestroyView.
- `ViewBinding-ktx` needs one of the following
`ViewBinding-ktx`
- provides the unified way of declaring the `binding` variable
- between Activity and Fragment.
- between DataBinding-ktx and ViewBinding-ktx.
- is saving memory
- The `binding` variable is stored as the Fragment's view's tag.
- The `binding` variable is cleaning up along with the Fragment's view after onDestroyView.
- needs one of the following
- calling `setContentView` in Activity and calling `inflater.inflate` in `onCreateView` of Fragment.
- calling Activity/Fragment's secondary constructor passing layout res id.

## Usage
## Usage

### Reflection

```kotlin
private val binding: ViewBindingActivityBinding by viewBinding()
```

### No reflection

```kotlin
private val binding by viewBinding { ViewBindingActivityBinding.bind(it) }
```

### Activity
- Use Activity's secondary constructor passing layout res id.
```kotlin
class ViewBindingActivity : AppCompatActivity(R.layout.view_binding_activity) {
// Declare the `binding` variable using `by viewBinding()`.
private val binding by viewBinding(ViewBindingActivityBinding::bind)
private val binding: ViewBindingActivityBinding by viewBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// You can use binding
Expand All @@ -43,43 +58,7 @@ class ViewBindingActivity : AppCompatActivity(R.layout.view_binding_activity) {
```kotlin
class ViewBindingFragment : Fragment(R.layout.view_binding_fragment) {
// Declare the `binding` variable using `by viewBinding()`.
private val binding by viewBinding(ViewBindingFragmentBinding::bind)
// DO NOT override onCreateView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// You can use binding
}
}
```


## Note
### Activity
- If you forget to use Activity's secondary constructor passing layout res id, your app crash.

```kotlin
// You can define and use ViewBindingAppCompatActivity for not forgetting.
open class ViewBindingAppCompatActivity<T : ViewBinding>(@LayoutRes contentLayoutId: Int, bind: (View) -> T) : AppCompatActivity(contentLayoutId) {
protected val binding by viewBinding(bind)
}

class YourActivity : ViewBindingAppCompatActivity<YourActivityBinding>(R.layout.your_activity, YourActivityBinding::bind) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// You can use binding
}
}
```

### Fragment
- If you forget to use Fragment's secondary constructor passing layout res id, Fragment is not shown.

```kotlin
// You can define and use ViewBindingFragment for not forgetting.
open class ViewBindingFragment<T : ViewBinding>(@LayoutRes contentLayoutId : Int, bind: (View) -> T) : Fragment(contentLayoutId) {
protected val binding: T by viewBinding(bind)
}
class YourFragment : ViewBindingFragment<YourFragmentBinding>(R.layout.your_fragment) {
private val binding: ViewBindingFragmentBinding by viewBinding()
// DO NOT override onCreateView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Expand Down
11 changes: 4 additions & 7 deletions ViewBinding-ktx/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 15
targetSdkVersion 29
}
compileSdkVersion 30
buildFeatures {
viewBinding = true
}
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.fragment:fragment:1.2.5'
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
//noinspection GradleDependency
implementation 'androidx.fragment:fragment-ktx:1.1.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.viewbinding.ViewBinding

fun <T : ViewBinding> FragmentActivity.viewBinding(bind: (View) -> T): Lazy<T> = object : Lazy<T> {
inline fun <reified T : ViewBinding> FragmentActivity.viewBinding(
crossinline bind: (View) -> T = { T::class.java.getMethod("bind", View::class.java).invoke(null, it) as T }
): Lazy<T> = object : Lazy<T> {
private var binding: T? = null
override fun isInitialized(): Boolean = binding != null
override val value: T
get() = binding ?: bind(getContentView()).also {
binding = it
}
get() = binding ?: bind(getContentView()).also { binding = it }

private fun FragmentActivity.getContentView(): View {
return checkNotNull(findViewById<ViewGroup>(android.R.id.content).getChildAt(0)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import androidx.viewbinding.ViewBinding
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

fun <T : ViewBinding> Fragment.viewBinding(bind: (View) -> T): ReadOnlyProperty<Fragment, T> = object : ReadOnlyProperty<Fragment, T> {
inline fun <reified T : ViewBinding> Fragment.viewBinding(
crossinline bind: (View) -> T = { T::class.java.getMethod("bind", View::class.java).invoke(null, it) as T }
): ReadOnlyProperty<Fragment, T> = object : ReadOnlyProperty<Fragment, T> {
@Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
(requireView().getTag(property.name.hashCode()) as? T)?.let { return it }
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
buildscript {
ext.kotlin_version = '1.3.72'
ext.kotlin_version = '1.4.10'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sat Apr 25 16:47:20 JST 2020
#Mon Oct 26 09:43:16 JST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
28 changes: 4 additions & 24 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 29
compileSdkVersion 30
defaultConfig {
applicationId "com.wada811.viewbindingktx"
minSdkVersion 15
targetSdkVersion 29
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand All @@ -16,7 +16,7 @@ android {
buildTypes {
debug {
debuggable true
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
Expand All @@ -31,26 +31,6 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation project(':ViewBinding-ktx')
implementation 'com.squareup.leakcanary:leakcanary-android:2.2'

// Core library
androidTestImplementation 'androidx.test:core:1.2.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
// Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.ext:truth:1.2.0'
androidTestImplementation 'com.google.truth:truth:1.0'
// Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-web:3.2.0'
androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.2.0'
// LeakCanary
androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:2.2"
}

This file was deleted.

Loading

0 comments on commit 19c31b9

Please sign in to comment.