├── .gitignore ├── LICENSE ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hi │ │ └── dhl │ │ └── demo │ │ └── binding │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hi │ │ │ └── dhl │ │ │ └── demo │ │ │ └── binding │ │ │ ├── App.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainViewModel.kt │ │ │ ├── brvah │ │ │ └── BRVAHActivity.kt │ │ │ ├── databind │ │ │ ├── BindViewStubActivity.kt │ │ │ ├── BindingAdapter.kt │ │ │ ├── DatBindActivity.kt │ │ │ ├── DataBindCustomView.kt │ │ │ ├── DataBindDialog.kt │ │ │ ├── DataBindIncludeActivity.kt │ │ │ └── list │ │ │ │ ├── DataBindRecycleActivity.kt │ │ │ │ ├── DataBindRecycleFragment.kt │ │ │ │ ├── ListViewModel.kt │ │ │ │ └── ProductAdapter.kt │ │ │ ├── di │ │ │ └── AppModule.kt │ │ │ ├── navigation │ │ │ ├── FragmentNav1.kt │ │ │ ├── FragmentNav2.kt │ │ │ ├── FragmentNav3.kt │ │ │ └── NavigationActivity.kt │ │ │ ├── viewbind │ │ │ ├── ViewBindActivity.kt │ │ │ ├── ViewBindCustomView.kt │ │ │ ├── ViewBindDialog.kt │ │ │ ├── ViewBindFragment.kt │ │ │ ├── ViewBindIncludeActivity.kt │ │ │ └── nested │ │ │ │ ├── NestedActivity.kt │ │ │ │ └── NestedFragment1.kt │ │ │ └── viewpager2 │ │ │ ├── Fragment1.kt │ │ │ ├── Fragment2.kt │ │ │ ├── Fragment3.kt │ │ │ ├── Fragment4.kt │ │ │ ├── Fragment5.kt │ │ │ └── ViewPager2Activity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── avatar.jpeg │ │ ├── ic_launcher_background.xml │ │ └── logo.png │ │ ├── layout │ │ ├── activity_brvah.xml │ │ ├── activity_data_bind.xml │ │ ├── activity_data_bind_recycle.xml │ │ ├── activity_include.xml │ │ ├── activity_include_view_bind.xml │ │ ├── activity_main.xml │ │ ├── activity_navigation.xml │ │ ├── activity_nested.xml │ │ ├── activity_view_bind.xml │ │ ├── activity_view_stub.xml │ │ ├── activity_viewpager.xml │ │ ├── dialog_app.xml │ │ ├── dialog_data_binding.xml │ │ ├── fragment1.xml │ │ ├── fragment2.xml │ │ ├── fragment3.xml │ │ ├── fragment4.xml │ │ ├── fragment5.xml │ │ ├── fragment_data_bind_recycle.xml │ │ ├── fragment_nav_1.xml │ │ ├── fragment_nav_2.xml │ │ ├── fragment_nav_3.xml │ │ ├── fragment_nested1.xml │ │ ├── fragment_nested2.xml │ │ ├── fragment_view_bind.xml │ │ ├── layout_include_data_item.xml │ │ ├── layout_include_item.xml │ │ ├── layout_merge_data_item.xml │ │ ├── layout_merge_item.xml │ │ ├── layout_view_custom.xml │ │ ├── layout_view_custom_data.xml │ │ ├── recycle_item_product.xml │ │ ├── recycle_item_product_footer.xml │ │ ├── recycle_item_product_header.xml │ │ ├── view_stub.xml │ │ └── view_stub_data.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── nav_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── hi │ └── dhl │ └── demo │ └── binding │ └── ExampleUnitTest.kt ├── binding ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ ├── androidx │ └── lifecycle │ │ └── BindingLifecycleObserver.kt │ └── com │ └── hi │ └── dhl │ └── binding │ ├── base │ ├── ActivityDelegate.kt │ ├── DialogDelegate.kt │ └── FragmentDelegate.kt │ ├── databind │ ├── ActivityDataBinding.kt │ ├── DialogDataBinding.kt │ ├── FragmentDataBinding.kt │ ├── ViewGroupDataBinding.kt │ └── ViewHolderDataBinding.kt │ ├── ext │ ├── ComponentExt.kt │ ├── LifecycleExt.kt │ └── ReflectExt.kt │ └── viewbind │ ├── ActivityViewBinding.kt │ ├── DialogViewBinding.kt │ ├── FragmentViewBinding.kt │ ├── ViewGroupViewBinding.kt │ └── ViewHolderViewBinding.kt ├── build.gradle ├── buildSrc ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── com │ │ └── hi │ │ └── dhl │ │ └── Deps.kt │ └── test │ └── kotlin │ └── com │ └── hi │ └── dhl │ └── DepsTest.java ├── doc └── README_CN.md ├── gradle-mvn-push.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows: 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | 6 | # Python: 7 | *.py[cod] 8 | *.so 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | migrations 14 | 15 | #Django 16 | *.egg-info 17 | *.pot 18 | *.py[co] 19 | .tox/ 20 | __pycache__ 21 | MANIFEST 22 | dist/ 23 | docs/_build/ 24 | docs/locale/ 25 | node_modules/ 26 | tests/coverage_html/ 27 | tests/.coverage 28 | build/ 29 | tests/report/ 30 | 31 | #-------------------------------- 32 | __pycache__/ 33 | *.py[cod] 34 | *$py.class 35 | 36 | # C extensions 37 | *.so 38 | 39 | # Distribution / packaging 40 | .Python 41 | env/ 42 | build/ 43 | develop-eggs/ 44 | dist/ 45 | downloads/ 46 | eggs/ 47 | .eggs/ 48 | lib/ 49 | lib64/ 50 | parts/ 51 | sdist/ 52 | var/ 53 | *.egg-info/ 54 | .installed.cfg 55 | *.egg 56 | 57 | # PyInstaller 58 | # Usually these files are written by a python script from a template 59 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 60 | *.manifest 61 | *.spec 62 | 63 | # Installer logs 64 | pip-log.txt 65 | pip-delete-this-directory.txt 66 | 67 | # Unit test / coverage reports 68 | htmlcov/ 69 | .tox/ 70 | .coverage 71 | .coverage.* 72 | .cache 73 | nosetests.xml 74 | coverage.xml 75 | *,cover 76 | .hypothesis/ 77 | 78 | # Translations 79 | *.mo 80 | *.pot 81 | 82 | # Django stuff: 83 | *.log 84 | local_settings.py 85 | 86 | # Flask stuff: 87 | instance/ 88 | .webassets-cache 89 | 90 | # Scrapy stuff: 91 | .scrapy 92 | 93 | # Sphinx documentation 94 | docs/_build/ 95 | 96 | # PyBuilder 97 | target/ 98 | 99 | # IPython Notebook 100 | .ipynb_checkpoints 101 | 102 | # pyenv 103 | .python-version 104 | 105 | # celery beat schedule file 106 | celerybeat-schedule 107 | 108 | # dotenv 109 | .env 110 | 111 | # virtualenv 112 | venv/ 113 | ENV/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | database/ 122 | media/ 123 | whoosh_index/ 124 | .idea/ 125 | *.sqlite3 126 | fabfile.py 127 | 128 | 129 | 130 | #-------------------------------- 131 | 132 | 133 | #java 134 | *.class 135 | 136 | # Package Files # 137 | *.jar 138 | *.war 139 | *.ear 140 | 141 | # Mobile Tools for Java (J2ME) 142 | .mtj.tmp/ 143 | 144 | 145 | # My configurations: 146 | db.ini 147 | deploy_key_rsa 148 | 149 | # Package Files # 150 | *.jar 151 | *.war 152 | *.ear 153 | 154 | #phpstorm 155 | *.idea 156 | 157 | #过滤数据库文件、sln解决方案文件、配置文件 158 | *.mdb 159 | *.ldb 160 | *.sln 161 | *.config 162 | 163 | #other 164 | data/error/ 165 | .idea*/ 166 | .idea/ 167 | *.htm 168 | 169 | # 忽略名称中末尾为ignore的文件夹 170 | *ignore/ 171 | *ignore*/ 172 | 173 | 174 | 175 | 176 | # Logs 177 | logs 178 | *.log 179 | npm-debug.log* 180 | # Runtime data 181 | pids 182 | *.pid 183 | *.seed 184 | *.pid.lock 185 | # Directory for instrumented libs generated by jscoverage/JSCover 186 | lib-cov 187 | # Coverage directory used by tools like istanbul 188 | coverage 189 | # nyc test coverage 190 | .nyc_output 191 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 192 | .grunt 193 | # Bower dependency directory (https://bower.io/) 194 | bower_components 195 | # node-waf configuration 196 | .lock-wscript 197 | # Compiled binary addons (http://nodejs.org/api/addons.html) 198 | build/Release 199 | # Dependency directories 200 | node_modules/ 201 | jspm_packages/ 202 | # Typescript v1 declaration files 203 | typings/ 204 | # Optional npm cache directory 205 | .npm 206 | # Optional eslint cache 207 | .eslintcache 208 | # Optional REPL history 209 | .node_repl_history 210 | # Output of 'npm pack' 211 | *.tgz 212 | # Yarn Integrity file 213 | .yarn-integrity 214 | # dotenv environment variables file 215 | .env 216 | .vscode 217 | # ignore sh 218 | sh/ 219 | # ignore test sdk.config.json 220 | sdk.config.json 221 | # ignore local config 222 | server/config.local.js 223 | 224 | 225 | #-------android 226 | # Built application files 227 | #*.apk 228 | *.ap_ 229 | 230 | # Files for the ART/Dalvik VM 231 | *.dex 232 | 233 | # Java class files 234 | *.class 235 | 236 | # Generated files 237 | bin/ 238 | gen/ 239 | out/ 240 | 241 | # Gradle files 242 | .gradle/ 243 | build/ 244 | 245 | # Local configuration file (sdk path, etc) 246 | local.properties 247 | 248 | # Proguard folder generated by Eclipse 249 | proguard/ 250 | 251 | # Log Files 252 | *.log 253 | 254 | # Android Studio Navigation editor temp files 255 | .navigation/ 256 | 257 | # Android Studio captures folder 258 | captures/ 259 | 260 | # Intellij 261 | *.iml 262 | .idea/ 263 | 264 | # Keystore files 265 | *.jks 266 | 267 | # External native build folder generated in Android Studio 2.2 and later 268 | .externalNativeBuild 269 | 270 | # DS_Store files 271 | *.DS_Store 272 | 273 | .MWebMetaData/ 274 | .sync/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | id 'kotlin-parcelize' 6 | } 7 | 8 | android { 9 | compileSdkVersion 32 10 | 11 | defaultConfig { 12 | applicationId "com.hi.dhl.demo.binding" 13 | minSdkVersion 24 14 | targetSdkVersion 32 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled true 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_11 30 | targetCompatibility JavaVersion.VERSION_11 31 | } 32 | 33 | kotlinOptions { 34 | jvmTarget = JavaVersion.VERSION_11.toString() 35 | } 36 | 37 | buildFeatures { 38 | dataBinding = true 39 | viewBinding = true 40 | } 41 | } 42 | 43 | dependencies { 44 | ext.fragment = "1.2.5" 45 | ext.koin_version = "2.2.1" 46 | ext.nav_version = "2.3.2" 47 | ext.constraintlayout = "2.0.4" 48 | ext.material = "1.2.1" 49 | ext.appcompat = "1.2.0" 50 | ext.ktx = "1.3.2" 51 | ext.remote = true 52 | 53 | implementation "androidx.core:core-ktx:${ktx}" 54 | implementation "androidx.appcompat:appcompat:${appcompat}" 55 | implementation "com.google.android.material:material:${material}" 56 | implementation "androidx.constraintlayout:constraintlayout:${constraintlayout}" 57 | 58 | implementation "org.koin:koin-androidx-viewmodel:${koin_version}" 59 | implementation "io.coil-kt:coil:1.1.0" 60 | 61 | implementation"androidx.navigation:navigation-fragment-ktx:$nav_version" 62 | implementation"androidx.navigation:navigation-ui-ktx:$nav_version" 63 | 64 | implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02' 65 | 66 | if (remote) { 67 | implementation 'com.hi-dhl:binding:1.2.0' 68 | } else { 69 | implementation project(':binding') 70 | } 71 | implementation "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4" 72 | testImplementation 'junit:junit:4.+' 73 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 74 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 75 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keepclassmembers class ** implements androidx.viewbinding.ViewBinding { 24 | public static ** bind(***); 25 | public static ** inflate(***); 26 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/hi/dhl/demo/binding/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.hi.dhl.demo.binding", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 39 | 40 | 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 59 | 60 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/App.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding 2 | 3 | import android.app.Application 4 | import com.hi.dhl.demo.binding.di.appModules 5 | import org.koin.android.ext.koin.androidContext 6 | import org.koin.android.logger.AndroidLogger 7 | import org.koin.core.context.loadKoinModules 8 | import org.koin.core.context.startKoin 9 | import org.koin.core.logger.Level 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/12
15 |  *     desc  :
16 |  * 
17 | */ 18 | class App : Application() { 19 | override fun onCreate() { 20 | super.onCreate() 21 | startKoin { 22 | AndroidLogger(Level.DEBUG) 23 | androidContext(this@App) 24 | loadKoinModules(appModules) 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.appcompat.app.AppCompatActivity 6 | import com.hi.dhl.binding.viewbind 7 | import com.hi.dhl.demo.binding.databind.DatBindActivity 8 | import com.hi.dhl.demo.binding.databinding.ActivityMainBinding 9 | import com.hi.dhl.demo.binding.viewbind.ViewBindActivity 10 | 11 | 12 | class MainActivity : AppCompatActivity(), View.OnClickListener { 13 | 14 | private val binding: ActivityMainBinding by viewbind() 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | getViews().forEach { 20 | it.setOnClickListener(this) 21 | } 22 | 23 | } 24 | 25 | override fun onClick(v: View) { 26 | with(binding) { 27 | when (v) { 28 | btnDataBind -> DatBindActivity.startActivity(this@MainActivity) 29 | btnViewBind -> ViewBindActivity.startActivity(this@MainActivity) 30 | } 31 | } 32 | } 33 | 34 | private fun getViews() = with(binding) { 35 | arrayListOf(btnDataBind, btnViewBind) 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding 2 | 3 | import android.os.Parcelable 4 | import androidx.databinding.BaseObservable 5 | import androidx.databinding.Bindable 6 | import androidx.databinding.ObservableField 7 | import androidx.lifecycle.LiveData 8 | import androidx.lifecycle.MutableLiveData 9 | import androidx.lifecycle.ViewModel 10 | import java.util.* 11 | import kotlinx.android.parcel.Parcelize 12 | 13 | /** 14 | *
15 |  *     author: dhl
16 |  *     date  : 2020/12/12
17 |  *     desc  :
18 |  * 
19 | */ 20 | 21 | class MainViewModel : ViewModel() { 22 | val inputnNumber = ObservableField() 23 | 24 | private val _imgLiveData = MutableLiveData() 25 | val imgLiveData: LiveData = _imgLiveData 26 | 27 | private val _userLiveData = MutableLiveData() 28 | val userLiveData: LiveData = _userLiveData 29 | 30 | /** 31 | * 将 inputnNumber 和 AppCompatTextView 通过 android:text="@={mainViewModel.inputnNumber}" 进行双向绑定, 32 | * 当 inputnNumber 变更的时候,AppCompatTextView 也会跟着一起变化 33 | */ 34 | fun generateTimber() { 35 | val timer = Timer() 36 | timer.schedule( 37 | object : TimerTask() { 38 | override fun run() { 39 | inputnNumber.set("ObservableField 双向绑定示例 \n Time: " + System.currentTimeMillis()) 40 | } 41 | }, 42 | 0, 500 43 | ) 44 | } 45 | 46 | fun bindImage(url: String) { 47 | _imgLiveData.value = url 48 | } 49 | 50 | fun bindUser() { 51 | val user = User(name = "dhl", account = "公众号:ByteCode") 52 | _userLiveData.value = user 53 | } 54 | 55 | fun bindAccount(): Account { 56 | val account = Account() 57 | account.name = "i am BaseObservable" 58 | return account 59 | } 60 | 61 | } 62 | 63 | @Parcelize 64 | data class User(val name: String, val account: String) : Parcelable 65 | 66 | class Account : BaseObservable() { 67 | 68 | @get:Bindable 69 | var name: String = "" 70 | set(value) { 71 | field = value 72 | notifyPropertyChanged(BR.name) 73 | } 74 | 75 | @get:Bindable 76 | var avator: String = "" 77 | set(avator) { 78 | field = avator 79 | notifyPropertyChanged(BR.avator) 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/brvah/BRVAHActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.brvah 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.annotation.LayoutRes 10 | import androidx.appcompat.app.AppCompatActivity 11 | import com.chad.library.adapter.base.BaseQuickAdapter 12 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 13 | import com.hi.dhl.binding.viewbind 14 | import com.hi.dhl.demo.binding.R 15 | import com.hi.dhl.demo.binding.databind.list.ListViewModel 16 | import com.hi.dhl.demo.binding.databind.list.Product 17 | import com.hi.dhl.demo.binding.databinding.ActivityBrvahBinding 18 | import com.hi.dhl.demo.binding.databinding.RecycleItemProductBinding 19 | import org.koin.androidx.viewmodel.ext.android.viewModel 20 | 21 | /** 22 | *
23 |  *     author: dhl
24 |  *     date  : 2021/5/15
25 |  *     desc  :
26 |  *
27 |  *     因有小伙伴反馈在开源库 BRVAH 中无法使用,所以单独写了一个如何在 BRVAH 中使用的例子
28 |  *     issue: https://github.com/hi-dhl/Binding/issues/24
29 |  *
30 |  * 
31 | */ 32 | class BRVAHActivity : AppCompatActivity() { 33 | 34 | private val binding: ActivityBrvahBinding by viewbind() 35 | private val viewModel: ListViewModel by viewModel() 36 | private val adapter: BRVAHAdapter by lazy { BRVAHAdapter() } 37 | 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | with(binding) { 41 | recyclerView.adapter = adapter 42 | } 43 | 44 | viewModel.liveData.observe(this@BRVAHActivity) { 45 | adapter.addData(it) 46 | adapter.notifyDataSetChanged() 47 | } 48 | } 49 | 50 | companion object { 51 | fun startActivity(activity: Activity) { 52 | activity.startActivity(Intent(activity, BRVAHActivity::class.java)) 53 | } 54 | } 55 | } 56 | 57 | class BRVAHAdapter : BaseQuickAdapter(0) { 58 | override fun convert(holder: BRVAHViewHolder, item: Product) { 59 | holder.bindData(item) 60 | } 61 | 62 | override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): BRVAHViewHolder { 63 | val view = inflateView(parent, viewType) 64 | return BRVAHViewHolder(view) 65 | } 66 | 67 | private fun inflateView(viewGroup: ViewGroup, @LayoutRes viewType: Int): View { 68 | val layoutInflater = LayoutInflater.from(viewGroup.context) 69 | return layoutInflater.inflate(viewType, viewGroup, false) 70 | } 71 | 72 | override fun getDefItemViewType(position: Int): Int = R.layout.recycle_item_product 73 | } 74 | 75 | 76 | class BRVAHViewHolder(view: View) : BaseViewHolder(view) { 77 | val binding: RecycleItemProductBinding by viewbind() 78 | 79 | fun bindData(data: Product) { 80 | binding.apply { 81 | product = data 82 | executePendingBindings() 83 | } 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/BindViewStubActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.databinding.DataBindingUtil 8 | import androidx.databinding.ViewStubProxy 9 | import com.hi.dhl.binding.databind 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databinding.ActivityViewStubBinding 12 | import com.hi.dhl.demo.binding.databinding.ViewStubBinding 13 | import com.hi.dhl.demo.binding.databinding.ViewStubDataBinding 14 | 15 | /** 16 | *
17 |  *     author: dhl
18 |  *     date  : 2020/12/31
19 |  *     desc  :
20 |  * 
21 | */ 22 | class BindViewStubActivity : AppCompatActivity() { 23 | 24 | val binding: ActivityViewStubBinding by databind(R.layout.activity_view_stub) 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | 29 | binding.viewStub.setOnInflateListener { stub, inflated -> 30 | 31 | // ViewBinding 32 | val viewStub: ViewStubBinding = ViewStubBinding.bind(inflated) 33 | viewStub.tvTitle.setText("使用 ViewStub 加载 ViewBinding 布局") 34 | 35 | } 36 | 37 | binding.viewStubData.setOnInflateListener { stub, inflated -> 38 | 39 | // DataBinding 40 | val dataViewStub: ViewStubDataBinding = DataBindingUtil.bind(inflated)!! 41 | dataViewStub.tvTitle.setText("使用 ViewStub 加载 DataBinding 布局") 42 | } 43 | 44 | inflateLayout(binding.viewStub) 45 | inflateLayout(binding.viewStubData) 46 | } 47 | 48 | private fun inflateLayout(viewStubProxy: ViewStubProxy) { 49 | if (!viewStubProxy.isInflated) { 50 | viewStubProxy.viewStub!!.inflate() 51 | } 52 | } 53 | 54 | companion object { 55 | 56 | fun startActivtiy(activity: Activity) { 57 | activity.startActivity(Intent(activity, BindViewStubActivity::class.java)) 58 | } 59 | 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/BindingAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.widget.ImageView 4 | import android.widget.TextView 5 | import androidx.databinding.BindingAdapter 6 | import androidx.recyclerview.widget.RecyclerView 7 | import coil.load 8 | import com.hi.dhl.demo.binding.R 9 | import com.hi.dhl.demo.binding.User 10 | import com.hi.dhl.demo.binding.databind.list.Product 11 | import com.hi.dhl.demo.binding.databind.list.ProductAdapter 12 | 13 | /** 14 | *
15 |  *     author: dhl
16 |  *     date  : 2020/12/13
17 |  *     desc  :
18 |  * 
19 | */ 20 | 21 | @BindingAdapter("bindingImage") 22 | fun bindingImage(imageView: ImageView, url: String?) { 23 | imageView.load(url) { 24 | crossfade(true) 25 | placeholder(R.mipmap.ic_launcher_round) 26 | } 27 | } 28 | 29 | @BindingAdapter("bindingLiveData") 30 | fun bindingLiveData(textView: TextView, user: User?) { 31 | user?.apply { 32 | textView.setText("@BindingAdapter + LiveData + parcelize 示例 \n") 33 | textView.append("${name} - ${account}") 34 | } 35 | 36 | } 37 | 38 | @BindingAdapter("bindList") 39 | fun bindAdapterList(recyclerView: RecyclerView, data: List?) { 40 | val adapter = recyclerView.adapter as? ProductAdapter 41 | ?: throw RuntimeException("adapter must bu not null") 42 | data?.let { 43 | adapter.submitList(it) 44 | adapter.notifyDataSetChanged() 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/DatBindActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.hi.dhl.binding.databind 9 | import com.hi.dhl.demo.binding.MainViewModel 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databind.list.DataBindRecycleActivity 12 | import com.hi.dhl.demo.binding.databinding.ActivityDataBindBinding 13 | import com.hi.dhl.demo.binding.navigation.NavigationActivity 14 | import org.koin.androidx.viewmodel.ext.android.viewModel 15 | 16 | /** 17 | *
18 |  *     author: dhl
19 |  *     date  : 2020/12/13
20 |  *     desc  :
21 |  * 
22 | */ 23 | class DatBindActivity : AppCompatActivity(), View.OnClickListener { 24 | 25 | val viewModel: MainViewModel by viewModel() 26 | 27 | val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind) 28 | 29 | // 第二种用法 或者通过下列方式绑定数据, 所有使用 DataBinding 绑定的地方都可以使用这种方式 30 | // val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind) { 31 | // val account = Account() 32 | // account.name = "test" 33 | // this.account = account 34 | // } 35 | 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | with(binding) { 40 | account = viewModel.bindAccount() 41 | mainViewModel = viewModel 42 | } 43 | 44 | getViews().forEach { 45 | it.setOnClickListener(this) 46 | } 47 | } 48 | 49 | 50 | override fun onClick(v: View) { 51 | val lifecycle = this.lifecycle 52 | with(binding) { 53 | when (v) { 54 | btnBindRandom -> viewModel.generateTimber() 55 | btnBindAdapter -> viewModel.bindUser() 56 | btnDialog -> DataBindDialog(this@DatBindActivity, lifecycle).show() 57 | btnRecycle -> DataBindRecycleActivity.startActivity(this@DatBindActivity) 58 | btnNavigation -> NavigationActivity.startActivity(this@DatBindActivity) 59 | btnStub -> BindViewStubActivity.startActivtiy(this@DatBindActivity) 60 | btnInclude -> DataBindIncludeActivity.startActivtiy(this@DatBindActivity) 61 | } 62 | } 63 | } 64 | 65 | private fun getViews() = with(binding) { 66 | arrayListOf( 67 | btnBindRandom, 68 | btnBindAdapter, 69 | btnDialog, 70 | btnRecycle, 71 | btnNavigation, 72 | btnStub, 73 | btnInclude 74 | ) 75 | } 76 | 77 | companion object { 78 | fun startActivity(activity: Activity) { 79 | activity.startActivity(Intent(activity, DatBindActivity::class.java)) 80 | } 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/DataBindCustomView.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.LinearLayout 6 | import com.hi.dhl.binding.databind 7 | import com.hi.dhl.demo.binding.R 8 | import com.hi.dhl.demo.binding.databinding.LayoutViewCustomDataBinding 9 | 10 | /** 11 | *
12 |  *     author: dhl
13 |  *     date  : 2021/1/14
14 |  *     desc  :
15 |  * 
16 | */ 17 | 18 | class DataBindCustomView @JvmOverloads constructor( 19 | context: Context, 20 | attr: AttributeSet? = null, 21 | defStyleAttr: Int = 0, 22 | ) : LinearLayout(context, attr, defStyleAttr) { 23 | 24 | val binding: LayoutViewCustomDataBinding by databind(R.layout.layout_view_custom_data) 25 | 26 | init { 27 | with(binding) { 28 | result.setText("这是 ViewGroup 通过 DataBinding 绑定") 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/DataBindDialog.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.view.Window 7 | import androidx.lifecycle.Lifecycle 8 | import com.hi.dhl.binding.databind 9 | import com.hi.dhl.demo.binding.R 10 | import com.hi.dhl.demo.binding.databinding.DialogDataBindingBinding 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/12
16 |  *     desc  :
17 |  * 
18 | */ 19 | class DataBindDialog(context: Context, lifecycle: Lifecycle) : 20 | Dialog(context, R.style.AppDialog) { 21 | 22 | val binding: DialogDataBindingBinding by databind(R.layout.dialog_data_binding, lifecycle) 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | requestWindowFeature(Window.FEATURE_NO_TITLE) 27 | binding.apply { result.setText("DataBindDialog") } 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/DataBindIncludeActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.binding.databind 8 | import com.hi.dhl.demo.binding.MainViewModel 9 | import com.hi.dhl.demo.binding.R 10 | import com.hi.dhl.demo.binding.User 11 | import com.hi.dhl.demo.binding.databinding.ActivityIncludeBinding 12 | import com.hi.dhl.demo.binding.databinding.LayoutMergeItemBinding 13 | import org.koin.androidx.viewmodel.ext.android.viewModel 14 | 15 | /** 16 | *
17 |  *     author: dhl
18 |  *     date  : 2020/12/31
19 |  *     desc  :
20 |  * 
21 | */ 22 | class DataBindIncludeActivity : AppCompatActivity() { 23 | 24 | val viewModel: MainViewModel by viewModel() 25 | private val binding: ActivityIncludeBinding by databind(R.layout.activity_include) 26 | 27 | override fun onCreate(savedInstanceState: Bundle?) { 28 | super.onCreate(savedInstanceState) 29 | with(binding) { 30 | user = User(name = "数据绑定:dhl", account = "数据绑定:公众号:ByteCode") 31 | 32 | // 布局是 ViewBdining 33 | include.includeTvTitle.setText("使用 include 布局中的控件, 不包含 merge") 34 | 35 | // 布局是 ViewBdining 36 | LayoutMergeItemBinding.bind(binding.root) 37 | .mergeTvTitle.setText("使用 include 布局中的控件, 包含 merge") 38 | 39 | // 布局是 DataBidning 使用 include 布局中的控件, 不包含 merge 40 | includeData.includeTvTitle.setText("通过代码设置 include layout 的控件") 41 | // 布局是 DataBidning,使用 include 布局中的控件, 包含 merge 42 | includeDataMerge.mergeTvTitle.setText("通过代码设置 merge layout 的控件") 43 | } 44 | } 45 | 46 | companion object { 47 | 48 | fun startActivtiy(activity: Activity) { 49 | activity.startActivity(Intent(activity, DataBindIncludeActivity::class.java)) 50 | } 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/list/DataBindRecycleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind.list 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.binding.databind 8 | import com.hi.dhl.binding.viewbind 9 | import com.hi.dhl.demo.binding.R 10 | import com.hi.dhl.demo.binding.databinding.ActivityDataBindRecycleBinding 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/17
16 |  *     desc  :
17 |  * 
18 | */ 19 | class DataBindRecycleActivity : AppCompatActivity() { 20 | 21 | private val binding: ActivityDataBindRecycleBinding by viewbind() 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | binding.apply { } 26 | // databinding 在 Fragment 中使用 27 | addFragment() 28 | } 29 | 30 | private fun addFragment() { 31 | supportFragmentManager.beginTransaction() 32 | .replace(R.id.container, DataBindRecycleFragment()) 33 | .commit() 34 | } 35 | 36 | companion object { 37 | fun startActivity(activity: Activity) { 38 | activity.startActivity(Intent(activity, DataBindRecycleActivity::class.java)) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/list/DataBindRecycleFragment.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind.list 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.fragment.app.Fragment 6 | import com.hi.dhl.binding.databind 7 | import com.hi.dhl.demo.binding.R 8 | import com.hi.dhl.demo.binding.databinding.FragmentDataBindRecycleBinding 9 | import org.koin.androidx.viewmodel.ext.android.viewModel 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/15
15 |  *     desc  :
16 |  * 
17 | */ 18 | class DataBindRecycleFragment : Fragment(R.layout.fragment_data_bind_recycle) { 19 | 20 | private val listViewModel: ListViewModel by viewModel() 21 | 22 | private val binding: FragmentDataBindRecycleBinding by databind() 23 | 24 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 25 | super.onViewCreated(view, savedInstanceState) 26 | binding.apply { 27 | viewModel = listViewModel 28 | adapter = ProductAdapter() 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/list/ListViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind.list 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | 7 | /** 8 | *
 9 |  *     author: dhl
10 |  *     date  : 2020/12/17
11 |  *     desc  :
12 |  * 
13 | */ 14 | class ListViewModel : ViewModel() { 15 | 16 | private val _liveData = MutableLiveData>() 17 | val liveData: LiveData> = _liveData 18 | 19 | init { 20 | val data = mutableListOf() 21 | (1..15).forEach { 22 | val id = it 23 | val name = "公众号:ByteCode,这是通过 DataBinding 绑定的 item" 24 | data.add(Product(id, name)) 25 | } 26 | _liveData.value = data 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/databind/list/ProductAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.databind.list 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.annotation.LayoutRes 7 | import androidx.recyclerview.widget.DiffUtil 8 | import androidx.recyclerview.widget.ListAdapter 9 | import androidx.recyclerview.widget.RecyclerView 10 | import com.hi.dhl.binding.databind 11 | import com.hi.dhl.binding.viewbind 12 | import com.hi.dhl.demo.binding.R 13 | import com.hi.dhl.demo.binding.databinding.RecycleItemProductBinding 14 | import com.hi.dhl.demo.binding.databinding.RecycleItemProductFooterBinding 15 | import com.hi.dhl.demo.binding.databinding.RecycleItemProductHeaderBinding 16 | 17 | /** 18 | *
 19 |  *     author: dhl
 20 |  *     date  : 2020/12/17
 21 |  *     desc  :
 22 |  * 
23 | */ 24 | 25 | /** 26 | * 这是 DataBinging 和 ViewBinding在 Adapter 中的使用例子, 27 | * 通过扩展 RecyclerView.ViewHolder 来使用 DataBinding 和 ViewBinding, 28 | * 即所有与 RecyclerView.ViewHolder 相关的 Adapter 都可以使用(ListAdapter、PagingDataAdapter、RecyclerView.Adapter 等等) 29 | */ 30 | class ProductAdapter : ListAdapter(Product.CALLBACK) { 31 | 32 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 33 | val view = inflateView(parent, viewType) 34 | return when (viewType) { 35 | R.layout.recycle_item_product_header -> ProductViewHolderHeader(view) 36 | R.layout.recycle_item_product_footer -> ProductViewHolderFooter(view) 37 | else -> ProductViewHolder(view) 38 | } 39 | } 40 | 41 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 42 | val data = getItem(position) 43 | if (holder is ProductViewHolder) { 44 | holder.bindData(data, position) 45 | } 46 | 47 | when { 48 | holder is ProductViewHolderHeader -> holder.bindData(data, position) 49 | holder is ProductViewHolderFooter -> holder.bindData(null, position) 50 | holder is ProductViewHolder -> { 51 | val data = getItem(position) 52 | holder.bindData(data, position) 53 | } 54 | } 55 | 56 | } 57 | 58 | override fun getItemViewType(position: Int): Int = when (position) { 59 | 0 -> R.layout.recycle_item_product_header 60 | itemCount - 1 -> R.layout.recycle_item_product_footer 61 | else -> R.layout.recycle_item_product 62 | } 63 | 64 | private fun inflateView(viewGroup: ViewGroup, @LayoutRes viewType: Int): View { 65 | val layoutInflater = LayoutInflater.from(viewGroup.context) 66 | return layoutInflater.inflate(viewType, viewGroup, false) 67 | } 68 | } 69 | 70 | class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) { 71 | 72 | val binding: RecycleItemProductBinding by databind() 73 | 74 | fun bindData(data: Product?, position: Int) { 75 | binding.apply { 76 | product = data 77 | executePendingBindings() 78 | } 79 | } 80 | } 81 | 82 | 83 | class ProductViewHolderHeader(view: View) : RecyclerView.ViewHolder(view) { 84 | 85 | val binding: RecycleItemProductHeaderBinding by viewbind() 86 | 87 | fun bindData(data: Product?, position: Int) { 88 | binding.apply { 89 | name.text = "通过 ViewBinding 绑定的 head" 90 | } 91 | } 92 | } 93 | 94 | class ProductViewHolderFooter(view: View) : RecyclerView.ViewHolder(view) { 95 | 96 | val binding: RecycleItemProductFooterBinding by viewbind() 97 | 98 | fun bindData(data: Product?, position: Int) { 99 | binding.apply { 100 | name.text = "通过 ViewBinding 绑定的 footer" 101 | } 102 | } 103 | } 104 | 105 | data class Product(val id: Int, val name: String) { 106 | companion object { 107 | val CALLBACK: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { 108 | // 判断两个Objects 是否代表同一个item对象, 一般使用Bean的id比较 109 | override fun areItemsTheSame(oldItem: Product, newItem: Product): Boolean = 110 | oldItem.id == newItem.id 111 | 112 | // 判断两个Objects 是否有相同的内容。 113 | override fun areContentsTheSame(oldItem: Product, newItem: Product): Boolean = true 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/di/AppModule.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.di 2 | 3 | import com.hi.dhl.demo.binding.MainViewModel 4 | import com.hi.dhl.demo.binding.databind.list.ListViewModel 5 | import org.koin.androidx.viewmodel.dsl.viewModel 6 | import org.koin.dsl.module 7 | 8 | /** 9 | *
10 |  *     author: dhl
11 |  *     date  : 2020/4/19
12 |  *     desc  :
13 |  * 
14 | */ 15 | val viewModelsModule = module { 16 | viewModel { MainViewModel() } 17 | viewModel { ListViewModel() } 18 | } 19 | 20 | val appModules = listOf(viewModelsModule) -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/navigation/FragmentNav1.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.navigation 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.navigation.Navigation 9 | import com.hi.dhl.binding.viewbind 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databinding.FragmentNav1Binding 12 | 13 | /** 14 | *
15 |  *     author: dhl
16 |  *     date  : 2020/12/21
17 |  *     desc  :
18 |  * 
19 | */ 20 | class FragmentNav1 : Fragment() { 21 | 22 | val binding: FragmentNav1Binding by viewbind() 23 | 24 | override fun onCreateView( 25 | inflater: LayoutInflater, container: ViewGroup?, 26 | savedInstanceState: Bundle? 27 | ): View { 28 | return binding.root 29 | } 30 | 31 | 32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 33 | super.onViewCreated(view, savedInstanceState) 34 | binding.btnJump.setOnClickListener { 35 | Navigation.findNavController(it).navigate(R.id.action_fragmentNav1_to_fragmentNav2) 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/navigation/FragmentNav2.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.navigation 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.navigation.Navigation 9 | import com.hi.dhl.binding.databind 10 | import com.hi.dhl.demo.binding.MainViewModel 11 | import com.hi.dhl.demo.binding.R 12 | import com.hi.dhl.demo.binding.databinding.FragmentNav2Binding 13 | import org.koin.androidx.viewmodel.ext.android.viewModel 14 | 15 | /** 16 | *
17 |  *     author: dhl
18 |  *     date  : 2020/12/21
19 |  *     desc  :
20 |  * 
21 | */ 22 | class FragmentNav2 : Fragment() { 23 | 24 | val binding: FragmentNav2Binding by databind() 25 | val viewModel: MainViewModel by viewModel() 26 | 27 | override fun onCreateView( 28 | inflater: LayoutInflater, container: ViewGroup?, 29 | savedInstanceState: Bundle? 30 | ): View { 31 | 32 | return binding.apply { 33 | lifecycleOwner = this@FragmentNav2 34 | mainViewModel = viewModel 35 | }.root 36 | } 37 | 38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 39 | super.onViewCreated(view, savedInstanceState) 40 | 41 | with(binding) { 42 | mainViewModel = viewModel 43 | viewModel.generateTimber() 44 | binding.btnJump.setOnClickListener { 45 | Navigation.findNavController(it).navigate(R.id.action_fragmentNav2_to_fragmentNav3) 46 | } 47 | } 48 | 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/navigation/FragmentNav3.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.navigation 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.navigation.Navigation 9 | import com.hi.dhl.binding.viewbind 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databinding.FragmentNav3Binding 12 | 13 | /** 14 | *
15 |  *     author: dhl
16 |  *     date  : 2020/12/21
17 |  *     desc  :
18 |  * 
19 | */ 20 | class FragmentNav3 : Fragment(R.layout.fragment_nav_3) { 21 | 22 | val binding: FragmentNav3Binding by viewbind() 23 | 24 | // override fun onCreateView( 25 | // inflater: LayoutInflater, container: ViewGroup?, 26 | // savedInstanceState: Bundle? 27 | // ): View { 28 | // return binding.root 29 | // } 30 | 31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 32 | super.onViewCreated(view, savedInstanceState) 33 | binding.btnJump.setOnClickListener { 34 | Navigation.findNavController(it).navigate(R.id.action_fragmentNav3_to_fragmentNav1) 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/navigation/NavigationActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.navigation 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.demo.binding.R 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/21
13 |  *     desc  :
14 |  * 
15 | */ 16 | class NavigationActivity : AppCompatActivity() { 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_navigation) 20 | } 21 | 22 | companion object { 23 | fun startActivity(activity: Activity) { 24 | activity.startActivity(Intent(activity, NavigationActivity::class.java)) 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.binding.viewbind 8 | import com.hi.dhl.demo.binding.R 9 | import com.hi.dhl.demo.binding.databinding.ActivityViewBindBinding 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/13
15 |  *     desc  :
16 |  * 
17 | */ 18 | class ViewBindActivity : AppCompatActivity() { 19 | val binding: ActivityViewBindBinding by viewbind() 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | binding.apply { 24 | addFragment() 25 | } 26 | } 27 | 28 | private fun addFragment() { 29 | supportFragmentManager.beginTransaction() 30 | .replace(R.id.container, ViewBindFragment()) 31 | .commit() 32 | } 33 | 34 | companion object { 35 | fun startActivity(activity: Activity) { 36 | activity.startActivity(Intent(activity, ViewBindActivity::class.java)) 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindCustomView.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.LinearLayout 6 | import com.hi.dhl.binding.viewbind 7 | import com.hi.dhl.demo.binding.databinding.LayoutMergeItemBinding 8 | import com.hi.dhl.demo.binding.databinding.LayoutViewCustomBinding 9 | 10 | /** 11 | *
12 |  *     author: dhl
13 |  *     date  : 2021/1/14
14 |  *     desc  :
15 |  * 
16 | */ 17 | 18 | class ViewBindCustomView @JvmOverloads constructor( 19 | context: Context, 20 | attr: AttributeSet? = null, 21 | defStyleAttr: Int = 0, 22 | ) : LinearLayout(context, attr, defStyleAttr) { 23 | 24 | lateinit var onDialogClickListener: OnDialogClickListener 25 | 26 | // 当根布局为 merge 标签,使用此方法进行初始化 27 | val binding: LayoutViewCustomBinding by viewbind(this) 28 | 29 | // 当根布局是非 merge 标签,使用此方法进行初始化 30 | // val binding: LayoutViewCustomBinding by viewbind() 31 | 32 | init { 33 | with(binding) { 34 | result.setText("这是 ViewGroup 通过 ViewBinding 绑定") 35 | result.setOnClickListener { 36 | if (::onDialogClickListener.isInitialized) { 37 | onDialogClickListener.onClick() 38 | } 39 | } 40 | 41 | LayoutMergeItemBinding.bind(root) 42 | .mergeTvTitle.setText("在 ViewGroup 中使用 merge 标签") 43 | } 44 | } 45 | 46 | fun setDialogClickListener(onDialogClickListener: OnDialogClickListener) { 47 | this.onDialogClickListener = onDialogClickListener 48 | } 49 | 50 | interface OnDialogClickListener { 51 | fun onClick() 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindDialog.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.util.Log 7 | import android.view.Window 8 | import androidx.lifecycle.Lifecycle 9 | import com.hi.dhl.binding.viewbind 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databinding.DialogAppBinding 12 | 13 | /** 14 | *
15 |  *     author: dhl
16 |  *     date  : 2020/12/12
17 |  *     desc  :
18 |  * 
19 | */ 20 | class ViewBindDialog(context: Context, lifecycle: Lifecycle) : Dialog(context, R.style.AppDialog) { 21 | 22 | val binding: DialogAppBinding by viewbind(lifecycle) 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | requestWindowFeature(Window.FEATURE_NO_TITLE) 27 | binding.apply { 28 | result.setText("ViewBindDialog") 29 | result.setOnClickListener { 30 | Log.e(TAG, "绑定 OnClickListener") 31 | } 32 | 33 | customView.onDialogClickListener = object : ViewBindCustomView.OnDialogClickListener { 34 | override fun onClick() { 35 | Log.e(TAG, "绑定自定义的 OnDialogClickListener") 36 | } 37 | 38 | } 39 | } 40 | } 41 | 42 | companion object { 43 | private val TAG: String = "ViewBindDialog" 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindFragment.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.fragment.app.Fragment 8 | import com.hi.dhl.binding.viewbind 9 | import com.hi.dhl.demo.binding.R 10 | import com.hi.dhl.demo.binding.brvah.BRVAHActivity 11 | import com.hi.dhl.demo.binding.databind.BindViewStubActivity 12 | import com.hi.dhl.demo.binding.databind.list.DataBindRecycleActivity 13 | import com.hi.dhl.demo.binding.databinding.FragmentViewBindBinding 14 | import com.hi.dhl.demo.binding.navigation.NavigationActivity 15 | import com.hi.dhl.demo.binding.viewbind.nested.NestedActivity 16 | import com.hi.dhl.demo.binding.viewpager2.ViewPager2Activity 17 | 18 | /** 19 | *
20 |  *     author: dhl
21 |  *     date  : 2020/12/12
22 |  *     desc  :
23 |  * 
24 | */ 25 | class ViewBindFragment : Fragment(R.layout.fragment_view_bind), View.OnClickListener { 26 | 27 | 28 | val binding: FragmentViewBindBinding by viewbind() 29 | var activity: Activity? = null 30 | 31 | override fun onAttach(context: Context) { 32 | super.onAttach(context) 33 | if (context is Activity) { 34 | activity = context 35 | } 36 | } 37 | 38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 39 | super.onViewCreated(view, savedInstanceState) 40 | 41 | getViews().forEach { 42 | it.setOnClickListener(this) 43 | } 44 | 45 | } 46 | 47 | private fun getViews() = with(binding) { 48 | arrayListOf( 49 | btnDialog, 50 | btnRecycle, 51 | btnNavigation, 52 | btnDialog, 53 | btnStub, 54 | btnInclude, 55 | btnViewPager, 56 | btnBRVAH, 57 | btnFragment 58 | ) 59 | } 60 | 61 | override fun onClick(v: View) { 62 | 63 | val lifecycle = this.lifecycle 64 | with(binding) { 65 | when (v) { 66 | btnDialog -> { 67 | this@ViewBindFragment.context?.let { ctx -> 68 | ViewBindDialog(ctx, lifecycle).show() 69 | } 70 | } 71 | btnRecycle -> DataBindRecycleActivity.startActivity(requireActivity()) 72 | btnBRVAH -> BRVAHActivity.startActivity(requireActivity()) 73 | btnNavigation -> NavigationActivity.startActivity(requireActivity()) 74 | btnStub -> BindViewStubActivity.startActivtiy(requireActivity()) 75 | btnInclude -> ViewBindIncludeActivity.startActivtiy(requireActivity()) 76 | btnViewPager -> ViewPager2Activity.startActivity(requireActivity()) 77 | btnFragment -> NestedActivity.startActivity(requireActivity()) 78 | else -> { 79 | } 80 | } 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindIncludeActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.binding.viewbind 8 | import com.hi.dhl.demo.binding.databinding.ActivityIncludeViewBindBinding 9 | import com.hi.dhl.demo.binding.databinding.LayoutMergeItemBinding 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/31
15 |  *     desc  :
16 |  * 
17 | */ 18 | class ViewBindIncludeActivity : AppCompatActivity() { 19 | 20 | val binding: ActivityIncludeViewBindBinding by viewbind() 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | 25 | with(binding) { 26 | tvTitle.setText("直接使用布局中的控件") 27 | 28 | // include without merge 29 | include.includeTvTitle.setText("使用 include 布局中的控件, 不包含 merge") 30 | 31 | // include 32 | LayoutMergeItemBinding.bind(root) 33 | .mergeTvTitle.setText("使用 include 布局中的控件, 包含 merge") 34 | } 35 | } 36 | 37 | companion object { 38 | 39 | fun startActivtiy(activity: Activity) { 40 | activity.startActivity(Intent(activity, ViewBindIncludeActivity::class.java)) 41 | } 42 | 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/nested/NestedActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind.nested 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.hi.dhl.binding.viewbind 8 | import com.hi.dhl.demo.binding.R 9 | import com.hi.dhl.demo.binding.databinding.ActivityNestedBinding 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/13
15 |  *     desc  :
16 |  * 
17 | */ 18 | class NestedActivity : AppCompatActivity() { 19 | val binding: ActivityNestedBinding by viewbind() 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | binding.apply { 24 | addFragment() 25 | } 26 | } 27 | 28 | private fun addFragment() { 29 | val fragment1 = NestedFragment1() 30 | fragment1.resId = R.drawable.avatar 31 | 32 | val fragment2 = NestedFragment1() 33 | fragment2.resId = R.drawable.logo 34 | 35 | supportFragmentManager.beginTransaction() 36 | .add(R.id.fragment1, fragment1) 37 | .add(R.id.fragment2, fragment2) 38 | .commit() 39 | } 40 | 41 | companion object { 42 | fun startActivity(activity: Activity) { 43 | activity.startActivity(Intent(activity, NestedActivity::class.java)) 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewbind/nested/NestedFragment1.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewbind.nested 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.fragment.app.Fragment 8 | import com.hi.dhl.binding.viewbind 9 | import com.hi.dhl.demo.binding.R 10 | import com.hi.dhl.demo.binding.databinding.FragmentNested1Binding 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/12
16 |  *     desc  :
17 |  * 
18 | */ 19 | class NestedFragment1 : Fragment(R.layout.fragment_nested1) { 20 | 21 | 22 | val binding: FragmentNested1Binding by viewbind() 23 | var activity: NestedActivity? = null 24 | var resId = R.drawable.avatar 25 | 26 | override fun onAttach(context: Context) { 27 | super.onAttach(context) 28 | if (context is NestedActivity) { 29 | activity = context 30 | } 31 | } 32 | 33 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 34 | super.onViewCreated(view, savedInstanceState) 35 | 36 | with(binding){ 37 | image.setImageResource(resId) 38 | } 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/Fragment1.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.viewpager2.adapter.FragmentStateAdapter 9 | import com.hi.dhl.binding.viewbind 10 | import com.hi.dhl.demo.binding.databinding.Fragment1Binding 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/21
16 |  *     desc  :
17 |  * 
18 | */ 19 | class Fragment1 : Fragment() { 20 | 21 | val binding: Fragment1Binding by viewbind() 22 | 23 | override fun onCreateView( 24 | inflater: LayoutInflater, container: ViewGroup?, 25 | savedInstanceState: Bundle? 26 | ): View { 27 | return binding.root 28 | } 29 | 30 | 31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 32 | super.onViewCreated(view, savedInstanceState) 33 | with(binding) { 34 | viewpager2.adapter = object : FragmentStateAdapter(this@Fragment1.requireActivity()) { 35 | override fun getItemCount() = 2 36 | 37 | override fun createFragment(position: Int): Fragment { 38 | return when (position) { 39 | 0 -> Fragment4() 40 | else -> Fragment5() 41 | } 42 | } 43 | } 44 | 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/Fragment2.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.navigation.Navigation 9 | import com.hi.dhl.binding.databind 10 | import com.hi.dhl.demo.binding.MainViewModel 11 | import com.hi.dhl.demo.binding.R 12 | import com.hi.dhl.demo.binding.databinding.Fragment1Binding 13 | import com.hi.dhl.demo.binding.databinding.Fragment2Binding 14 | import com.hi.dhl.demo.binding.databinding.FragmentNav2Binding 15 | import org.koin.androidx.viewmodel.ext.android.viewModel 16 | 17 | /** 18 | *
19 |  *     author: dhl
20 |  *     date  : 2020/12/21
21 |  *     desc  :
22 |  * 
23 | */ 24 | class Fragment2 : Fragment() { 25 | 26 | val binding: Fragment2Binding by databind() 27 | val viewModel: MainViewModel by viewModel() 28 | 29 | override fun onCreateView( 30 | inflater: LayoutInflater, container: ViewGroup?, 31 | savedInstanceState: Bundle? 32 | ): View { 33 | 34 | return binding.apply { 35 | lifecycleOwner = this@Fragment2 36 | mainViewModel = viewModel 37 | }.root 38 | } 39 | 40 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 41 | super.onViewCreated(view, savedInstanceState) 42 | 43 | with(binding) { 44 | mainViewModel = viewModel 45 | viewModel.generateTimber() 46 | } 47 | 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/Fragment3.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.fragment.app.Fragment 6 | import com.hi.dhl.binding.viewbind 7 | import com.hi.dhl.demo.binding.R 8 | import com.hi.dhl.demo.binding.databinding.Fragment3Binding 9 | 10 | /** 11 | *
12 |  *     author: dhl
13 |  *     date  : 2020/12/21
14 |  *     desc  :
15 |  * 
16 | */ 17 | class Fragment3 : Fragment(R.layout.fragment3) { 18 | 19 | val binding: Fragment3Binding by viewbind() 20 | 21 | // override fun onCreateView( 22 | // inflater: LayoutInflater, container: ViewGroup?, 23 | // savedInstanceState: Bundle? 24 | // ): View { 25 | // return binding.root 26 | // } 27 | 28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 29 | super.onViewCreated(view, savedInstanceState) 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/Fragment4.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.hi.dhl.binding.viewbind 9 | import com.hi.dhl.demo.binding.databinding.Fragment4Binding 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/21
15 |  *     desc  :
16 |  * 
17 | */ 18 | class Fragment4 : Fragment() { 19 | 20 | val binding: Fragment4Binding by viewbind() 21 | 22 | override fun onCreateView( 23 | inflater: LayoutInflater, container: ViewGroup?, 24 | savedInstanceState: Bundle? 25 | ): View { 26 | return binding.root 27 | } 28 | 29 | 30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 31 | super.onViewCreated(view, savedInstanceState) 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/Fragment5.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.hi.dhl.binding.viewbind 9 | import com.hi.dhl.demo.binding.databinding.Fragment5Binding 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/21
15 |  *     desc  :
16 |  * 
17 | */ 18 | class Fragment5 : Fragment() { 19 | 20 | val binding: Fragment5Binding by viewbind() 21 | 22 | override fun onCreateView( 23 | inflater: LayoutInflater, container: ViewGroup?, 24 | savedInstanceState: Bundle? 25 | ): View { 26 | return binding.root 27 | } 28 | 29 | 30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 31 | super.onViewCreated(view, savedInstanceState) 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hi/dhl/demo/binding/viewpager2/ViewPager2Activity.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding.viewpager2 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.appcompat.app.AppCompatActivity 8 | import androidx.fragment.app.FragmentTransaction 9 | import com.hi.dhl.binding.viewbind 10 | import com.hi.dhl.demo.binding.R 11 | import com.hi.dhl.demo.binding.databinding.ActivityViewpagerBinding 12 | 13 | 14 | /** 15 | *
16 |  *     author: dhl
17 |  *     date  : 2021/4/10
18 |  *     desc  :
19 |  * 
20 | */ 21 | class ViewPager2Activity : AppCompatActivity(), View.OnClickListener { 22 | val binding: ActivityViewpagerBinding by viewbind() 23 | var fragment1: Fragment1 = Fragment1() 24 | var fragment2: Fragment2 = Fragment2() 25 | var fragment3: Fragment3 = Fragment3() 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | 29 | with(binding) { 30 | 31 | val fragmentTransaction = supportFragmentManager.beginTransaction() 32 | fragmentTransaction.add(R.id.container, fragment3) 33 | fragmentTransaction.add(R.id.container, fragment2) 34 | fragmentTransaction.add(R.id.container, fragment1) 35 | hideFragment(fragmentTransaction) 36 | fragmentTransaction.show(fragment1) 37 | fragmentTransaction.commit() 38 | 39 | getViews().forEach { 40 | it.setOnClickListener(this@ViewPager2Activity) 41 | } 42 | } 43 | 44 | } 45 | 46 | private fun getViews() = with(binding) { 47 | arrayListOf( 48 | tab1, 49 | tab2, 50 | tab3 51 | ) 52 | } 53 | 54 | companion object { 55 | fun startActivity(activity: Activity) { 56 | activity.startActivity(Intent(activity, ViewPager2Activity::class.java)) 57 | } 58 | } 59 | 60 | override fun onClick(v: View) { 61 | val fragmentTransaction = supportFragmentManager.beginTransaction() 62 | hideFragment(fragmentTransaction) 63 | with(binding) { 64 | when (v) { 65 | tab1 -> { 66 | fragmentTransaction.show(fragment1) 67 | } 68 | tab2 -> { 69 | fragmentTransaction.show(fragment2) 70 | } 71 | tab3 -> fragmentTransaction.show(fragment3) 72 | else -> { 73 | } 74 | } 75 | } 76 | fragmentTransaction.commitNow() 77 | } 78 | 79 | private fun hideFragment(fragmentTransaction: FragmentTransaction) { 80 | getViews().forEach { 81 | fragmentTransaction.hide(fragment1) 82 | fragmentTransaction.hide(fragment2) 83 | fragmentTransaction.hide(fragment3) 84 | 85 | } 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avatar.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/drawable/avatar.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/drawable/logo.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_brvah.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_data_bind.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 23 | 24 | 32 | 33 | 39 | 40 | 49 | 50 | 56 | 57 | 58 | 67 | 68 | 77 | 78 | 79 | 88 | 89 | 95 | 96 | 102 | 103 | 110 | 111 | 118 | 119 | 126 | 127 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_data_bind_recycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_include.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 17 | 18 | 21 | 22 | 23 | 24 | 28 | 29 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_include_view_bind.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 26 | 27 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_nested.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_view_bind.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_view_stub.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_viewpager.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 22 | 23 | 29 | 30 | 39 | 40 | 49 | 50 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 21 | 22 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_data_binding.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 12 | 13 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment1.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 17 | 18 | 22 | 23 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment3.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment4.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment5.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_data_bind_recycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 19 | 20 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_nav_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_nav_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | 17 | 21 | 22 | 31 | 32 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_nav_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_nested1.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_nested2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_view_bind.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 23 | 24 | 31 | 32 | 39 | 40 | 47 | 48 | 55 | 56 | 63 | 64 | 67 | 68 | 75 | 76 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_include_data_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | 17 | 24 | 25 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_include_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_merge_data_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | 16 | 17 | 22 | 23 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_merge_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_view_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_view_custom_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycle_item_product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycle_item_product_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycle_item_product_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_stub.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_stub_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 15 | 16 | 17 | 21 | 22 | 25 | 26 | 27 | 31 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12sp 7 | 10sp 8 | 13sp 9 | 14sp 10 | 16sp 11 | 18sp 12 | 20sp 13 | 22sp 14 | 25sp 15 | 28sp 16 | 30sp 17 | 32sp 18 | 40sp 19 | 50sp 20 | 21 | 22 | 1dp 23 | 3dp 24 | 2dp 25 | 5dp 26 | 6dp 27 | 8dp 28 | 10dp 29 | 12dp 30 | 14dp 31 | 16dp 32 | 18dp 33 | 20dp 34 | 30dp 35 | 25dp 36 | 40dp 37 | 38 | 39 | 1dp 40 | 3dp 41 | 2dp 42 | 5dp 43 | 6dp 44 | 7dp 45 | 8dp 46 | 10dp 47 | 12dp 48 | 13dp 49 | 15dp 50 | 16dp 51 | 22dp 52 | 30dp 53 | 35dp 54 | 45dp 55 | 40dp 56 | 50dp 57 | 60dp 58 | 20dp 59 | 25dp 60 | 80dp 61 | 100dp 62 | 63 | 8dp 64 | 16dp 65 | 24dp 66 | 32dp 67 | 40dp 68 | 50dp 69 | 48dp 70 | 56dp 71 | 64dp 72 | 72dp 73 | 80dp 74 | 160dp 75 | 76 | 8dp 77 | 78 | 100dp 79 | 10dp 80 | 200dp 81 | 180dp 82 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Binding 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | -------------------------------------------------------------------------------- /app/src/test/java/com/hi/dhl/demo/binding/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.demo.binding 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /binding/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdkVersion 32 8 | 9 | defaultConfig { 10 | minSdkVersion 14 11 | targetSdkVersion 32 12 | versionCode 10109 13 | versionName "1.1.9" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | consumerProguardFiles "consumer-rules.pro" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | kotlinOptions { 30 | jvmTarget = '1.8' 31 | } 32 | buildFeatures { 33 | dataBinding = true 34 | viewBinding = true 35 | } 36 | } 37 | 38 | dependencies { 39 | ext.core = "1.3.2" 40 | ext.appcompat = "1.2.0" 41 | ext.recyclerview = "1.1.0" 42 | implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1' 43 | implementation "androidx.core:core-ktx:$core" 44 | implementation "androidx.appcompat:appcompat:$appcompat" 45 | implementation "androidx.recyclerview:recyclerview:$recyclerview" 46 | } 47 | 48 | apply from: "${rootDir}/gradle-mvn-push.gradle" -------------------------------------------------------------------------------- /binding/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/binding/consumer-rules.pro -------------------------------------------------------------------------------- /binding/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /binding/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /binding/src/main/java/androidx/lifecycle/BindingLifecycleObserver.kt: -------------------------------------------------------------------------------- 1 | package androidx.lifecycle 2 | 3 | /** 4 | *
 5 |  *     author: dhl
 6 |  *     date  : 2021/1/25
 7 |  *     desc  :
 8 |  * 
9 | */ 10 | 11 | open class BindingLifecycleObserver : DefaultLifecycleObserver { 12 | 13 | override fun onCreate(owner: LifecycleOwner) { 14 | } 15 | 16 | override fun onStart(owner: LifecycleOwner) { 17 | } 18 | 19 | override fun onResume(owner: LifecycleOwner) { 20 | } 21 | 22 | override fun onPause(owner: LifecycleOwner) { 23 | } 24 | 25 | override fun onStop(owner: LifecycleOwner) { 26 | } 27 | 28 | override fun onDestroy(owner: LifecycleOwner) { 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/base/ActivityDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.base 2 | 3 | import android.app.Activity 4 | import android.os.Build 5 | import androidx.activity.ComponentActivity 6 | import androidx.viewbinding.ViewBinding 7 | import com.hi.dhl.binding.observerWhenDestroyed 8 | import com.hi.dhl.binding.registerLifecycleBelowQ 9 | import kotlin.properties.ReadOnlyProperty 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/15
15 |  *     desc  :
16 |  * 
17 | */ 18 | 19 | abstract class ActivityDelegate( 20 | activity: Activity 21 | ) : ReadOnlyProperty { 22 | 23 | protected var viewBinding: T? = null 24 | private val LIFECYCLE_FRAGMENT_TAG = "com.hi.dhl.binding.lifecycle_fragment" 25 | 26 | init { 27 | when (activity) { 28 | is ComponentActivity -> activity.lifecycle.observerWhenDestroyed { destroyed() } 29 | else -> { 30 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 31 | activity.observerWhenDestroyed { destroyed() } 32 | } 33 | } 34 | } 35 | 36 | } 37 | 38 | fun addLifecycleFragment(activity: Activity) { 39 | activity.registerLifecycleBelowQ { 40 | destroyed() 41 | } 42 | } 43 | 44 | private fun destroyed() { 45 | viewBinding = null 46 | } 47 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/base/DialogDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.base 2 | 3 | import android.app.Dialog 4 | import androidx.lifecycle.Lifecycle 5 | import androidx.viewbinding.ViewBinding 6 | import com.hi.dhl.binding.observerWhenDestroyed 7 | import kotlin.properties.ReadOnlyProperty 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/15
13 |  *     desc  :
14 |  * 
15 | */ 16 | abstract class DialogDelegate( 17 | lifecycle: Lifecycle? = null 18 | ) : ReadOnlyProperty { 19 | 20 | protected var viewBinding: T? = null 21 | 22 | init { 23 | lifecycle?.observerWhenDestroyed { destroyed() } 24 | } 25 | 26 | fun destroyed() { 27 | viewBinding = null 28 | } 29 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/base/FragmentDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.base 2 | 3 | import androidx.fragment.app.Fragment 4 | import androidx.fragment.app.FragmentManager 5 | import androidx.viewbinding.ViewBinding 6 | import com.hi.dhl.binding.observerWhenCreated 7 | import kotlin.properties.ReadOnlyProperty 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/15
13 |  *     desc  :
14 |  * 
15 | */ 16 | abstract class FragmentDelegate( 17 | fragment: Fragment 18 | ) : ReadOnlyProperty { 19 | 20 | protected var viewBinding: T? = null 21 | 22 | init { 23 | 24 | // 详情查看 [issue][https://github.com/hi-dhl/Binding/issues/31#issuecomment-1109729949] 25 | fragment.lifecycle.observerWhenCreated { 26 | val fragmentManager = fragment.requireFragmentManager() 27 | fragmentManager.registerFragmentLifecycleCallbacks(object : 28 | FragmentManager.FragmentLifecycleCallbacks() { 29 | override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) { 30 | super.onFragmentViewDestroyed(fm, f) 31 | // 检查 fragment 的目的,为了防止类似于加载多个 Fragment 场景销毁的时候,出现不必要的异常 32 | if (f == fragment) { 33 | destroyed() 34 | fragmentManager.unregisterFragmentLifecycleCallbacks(this) 35 | } 36 | 37 | } 38 | }, false) 39 | } 40 | 41 | } 42 | 43 | private fun destroyed() { 44 | viewBinding = null 45 | } 46 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/databind/ActivityDataBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.databind 2 | 3 | import android.app.Activity 4 | import androidx.activity.ComponentActivity 5 | import androidx.annotation.LayoutRes 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.databinding.ViewDataBinding 8 | import com.hi.dhl.binding.base.ActivityDelegate 9 | import kotlin.reflect.KProperty 10 | 11 | /** 12 | *
13 |  *     author: dhl
14 |  *     date  : 2020/12/10
15 |  *     desc  :
16 |  * 
17 | */ 18 | 19 | class ActivityDataBinding( 20 | val activity: Activity, 21 | @LayoutRes val resId: Int, 22 | private var block: (T.() -> Unit)? = null 23 | ) : ActivityDelegate(activity) { 24 | 25 | override fun getValue(thisRef: Activity, property: KProperty<*>): T { 26 | return viewBinding?.run { 27 | this 28 | 29 | } ?: let { 30 | // 当继承 Activity 且 Build.VERSION.SDK_INT < Build.VERSION_CODES.Q 时触发 31 | addLifecycleFragment(activity) 32 | 33 | // 获取 ViewDataBinding 34 | val bind: T = DataBindingUtil.setContentView(thisRef, resId) 35 | return bind.apply { 36 | if (activity is ComponentActivity) { 37 | bind.lifecycleOwner = activity 38 | } 39 | viewBinding = this 40 | block?.invoke(this) 41 | block = null 42 | } 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/databind/DialogDataBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.databind 2 | 3 | import android.app.Dialog 4 | import android.view.LayoutInflater 5 | import androidx.annotation.LayoutRes 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.databinding.ViewDataBinding 8 | import androidx.lifecycle.Lifecycle 9 | import com.hi.dhl.binding.base.DialogDelegate 10 | import kotlin.reflect.KProperty 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/15
16 |  *     desc  :
17 |  * 
18 | */ 19 | class DialogDataBinding( 20 | val classes: Class, 21 | val inflater: LayoutInflater, 22 | @LayoutRes val resId: Int, 23 | lifecycle: Lifecycle? = null, 24 | private var block: (T.() -> Unit)? = null 25 | ) : DialogDelegate(lifecycle) { 26 | 27 | override fun getValue(thisRef: Dialog, property: KProperty<*>): T { 28 | return viewBinding?.run { 29 | this 30 | 31 | } ?: let { 32 | 33 | val bind = DataBindingUtil.bind(inflater.inflate(resId, null))!! as T 34 | thisRef.setContentView(bind.root) 35 | return bind.apply { 36 | viewBinding = this 37 | block?.invoke(this) 38 | block = null 39 | } 40 | } 41 | 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/databind/FragmentDataBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.databind 2 | 3 | import androidx.databinding.DataBindingUtil 4 | import androidx.databinding.ViewDataBinding 5 | import androidx.fragment.app.Fragment 6 | import androidx.lifecycle.Lifecycle 7 | import com.hi.dhl.binding.base.FragmentDelegate 8 | import com.hi.dhl.binding.inflateMethod 9 | import java.lang.Exception 10 | import kotlin.reflect.KProperty 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/10
16 |  *     desc  :
17 |  * 
18 | */ 19 | 20 | class FragmentDataBinding( 21 | classes: Class, 22 | val fragment: Fragment, 23 | private var block: (T.() -> Unit)? = null 24 | ) : FragmentDelegate(fragment) { 25 | 26 | private val layoutInflater = classes.inflateMethod() 27 | 28 | override fun getValue(thisRef: Fragment, property: KProperty<*>): T { 29 | return viewBinding?.run { 30 | return this 31 | 32 | } ?: let { 33 | 34 | try { 35 | /** 36 | * 检查目的,是为了防止在 onCreateView() or after onDestroyView() 使用 binding。 37 | * 另外在销毁之后,如果再次使用,由于 delegate property 会被再次初始化出现的异常 38 | * 39 | * 捕获这个异常的原因,是为了兼容之前的版本,防止因为升级,造成崩溃 40 | */ 41 | check(thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { 42 | "cannot use binding in before onCreateView() or after onDestroyView() from 1.1.4. about [issue](https://github.com/hi-dhl/Binding/issues/31#issuecomment-1109733307)" 43 | } 44 | } catch (e: Exception) { 45 | e.printStackTrace() 46 | } 47 | 48 | val bind: T 49 | if (thisRef.view == null) { 50 | // 这里为了兼容在 navigation 中使用 Fragment 51 | bind = layoutInflater.invoke(null, thisRef.layoutInflater) as T 52 | } else { 53 | bind = DataBindingUtil.bind(thisRef.view!!)!! 54 | } 55 | 56 | return bind.apply { 57 | viewBinding = this 58 | lifecycleOwner = fragment.viewLifecycleOwner 59 | block?.invoke(this) 60 | block = null 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/databind/ViewGroupDataBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.databind 2 | 3 | import android.app.Activity 4 | import android.os.Build 5 | import android.view.LayoutInflater 6 | import android.view.ViewGroup 7 | import androidx.activity.ComponentActivity 8 | import androidx.annotation.LayoutRes 9 | import androidx.databinding.DataBindingUtil 10 | import androidx.viewbinding.ViewBinding 11 | import com.hi.dhl.binding.observerWhenDestroyed 12 | import com.hi.dhl.binding.registerLifecycleBelowQ 13 | import kotlin.properties.ReadOnlyProperty 14 | import kotlin.reflect.KProperty 15 | 16 | /** 17 | *
18 |  *     author: dhl
19 |  *     date  : 2020/12/17
20 |  *     desc  :
21 |  * 
22 | */ 23 | 24 | class ViewGroupDataBinding( 25 | classes: Class, 26 | @LayoutRes val resId: Int, 27 | val inflater: LayoutInflater, 28 | val viewGroup: ViewGroup? = null, 29 | private var block: (T.() -> Unit)? = null 30 | ) : ReadOnlyProperty { 31 | 32 | private var viewBinding: T? = null 33 | 34 | init { 35 | viewGroup?.apply { 36 | when (context) { 37 | is ComponentActivity -> { 38 | (context as ComponentActivity).lifecycle.observerWhenDestroyed { destroyed() } 39 | } 40 | is Activity -> { 41 | val activity = context as Activity 42 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 43 | activity.observerWhenDestroyed { destroyed() } 44 | } else { 45 | activity.registerLifecycleBelowQ { destroyed() } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | override fun getValue(thisRef: ViewGroup, property: KProperty<*>): T { 52 | return viewBinding?.run { 53 | this 54 | 55 | } ?: let { 56 | val bind = DataBindingUtil.inflate(inflater, resId, thisRef, true) as T 57 | val value = block 58 | bind.apply { 59 | viewBinding = this 60 | value?.invoke(this) 61 | block = null 62 | } 63 | } 64 | } 65 | 66 | private fun destroyed() { 67 | viewBinding = null 68 | } 69 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/databind/ViewHolderDataBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.databind 2 | 3 | import androidx.databinding.DataBindingUtil 4 | import androidx.databinding.ViewDataBinding 5 | import androidx.recyclerview.widget.RecyclerView 6 | import kotlin.properties.ReadOnlyProperty 7 | import kotlin.reflect.KProperty 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/17
13 |  *     desc  :
14 |  * 
15 | */ 16 | class ViewHolderDataBinding( 17 | classes: Class, 18 | private var block: (T.() -> Unit)? = null 19 | ) : ReadOnlyProperty { 20 | 21 | private var viewBinding: T? = null 22 | 23 | override fun getValue(thisRef: RecyclerView.ViewHolder, property: KProperty<*>): T { 24 | return viewBinding?.run { 25 | this 26 | } ?: let { 27 | 28 | val bind = DataBindingUtil.bind(thisRef.itemView) as T 29 | val value = block 30 | bind.apply { 31 | viewBinding = this 32 | value?.invoke(this) 33 | block = null 34 | } 35 | } 36 | } 37 | 38 | private fun destroyed() { 39 | viewBinding = null 40 | } 41 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/ext/ComponentExt.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding 2 | 3 | import android.app.Activity 4 | import android.app.Dialog 5 | import android.view.LayoutInflater 6 | import android.view.ViewGroup 7 | import androidx.annotation.LayoutRes 8 | import androidx.databinding.ViewDataBinding 9 | import androidx.fragment.app.Fragment 10 | import androidx.lifecycle.Lifecycle 11 | import androidx.recyclerview.widget.RecyclerView 12 | import androidx.viewbinding.ViewBinding 13 | import com.hi.dhl.binding.databind.* 14 | import com.hi.dhl.binding.viewbind.* 15 | 16 | /** 17 | *
 18 |  *     author: dhl
 19 |  *     date  : 2020/12/10
 20 |  *     desc  :
 21 |  * 
22 | */ 23 | 24 | 25 | inline fun Fragment.databind() = 26 | FragmentDataBinding(T::class.java, this) 27 | 28 | inline fun Fragment.databind(noinline block: T.() -> Unit) = 29 | FragmentDataBinding(T::class.java, this, block = block) 30 | 31 | inline fun Activity.databind(@LayoutRes resId: Int) = 32 | ActivityDataBinding(this, resId) 33 | 34 | inline fun Dialog.databind( 35 | @LayoutRes resId: Int 36 | ) = DialogDataBinding( 37 | classes = T::class.java, 38 | inflater = this.layoutInflater, 39 | resId = resId, 40 | ) 41 | 42 | inline fun Activity.databind( 43 | @LayoutRes resId: Int, 44 | noinline block: T.() -> Unit 45 | ) = ActivityDataBinding(this, resId, block) 46 | 47 | inline fun Dialog.databind( 48 | @LayoutRes resId: Int, 49 | noinline block: T.() -> Unit 50 | ) = DialogDataBinding( 51 | classes = T::class.java, 52 | inflater = this.layoutInflater, 53 | resId = resId, 54 | block = block, 55 | ) 56 | 57 | inline fun Dialog.databind( 58 | @LayoutRes resId: Int, 59 | lifecycle: Lifecycle 60 | ) = DialogDataBinding( 61 | classes = T::class.java, 62 | inflater = this.layoutInflater, 63 | resId = resId, 64 | lifecycle = lifecycle 65 | ) 66 | 67 | inline fun RecyclerView.ViewHolder.databind() = 68 | ViewHolderDataBinding(T::class.java) 69 | 70 | inline fun RecyclerView.ViewHolder.databind(noinline block: (T.() -> Unit)) = 71 | ViewHolderDataBinding(T::class.java, block) 72 | 73 | inline fun ViewGroup.databind(@LayoutRes resId: Int) = 74 | ViewGroupDataBinding( 75 | classes = T::class.java, 76 | resId = resId, 77 | inflater = LayoutInflater.from(getContext()) 78 | ) 79 | 80 | inline fun ViewGroup.databind( 81 | @LayoutRes resId: Int, 82 | noinline block: (T.() -> Unit) 83 | ) = ViewGroupDataBinding( 84 | classes = T::class.java, 85 | resId = resId, 86 | inflater = LayoutInflater.from(getContext()), 87 | viewGroup = this, 88 | block = block 89 | ) 90 | 91 | inline fun Activity.viewbind() = 92 | ActivityViewBinding(T::class.java, this) 93 | 94 | //inline fun AppCompatActivity.viewbind() = 95 | // ActivityViewBinding(T::class.java, this) 96 | // 97 | //inline fun FragmentActivity.viewbind() = 98 | // ActivityViewBinding(T::class.java, this) 99 | 100 | inline fun Fragment.viewbind() = 101 | FragmentViewBinding(T::class.java, this) 102 | 103 | inline fun Dialog.viewbind() = 104 | DialogViewBinding(T::class.java) 105 | 106 | inline fun Dialog.viewbind(lifecycle: Lifecycle) = 107 | DialogViewBinding(T::class.java, lifecycle) 108 | 109 | inline fun RecyclerView.ViewHolder.viewbind() = 110 | ViewHolderViewBinding(T::class.java) 111 | 112 | inline fun ViewGroup.viewbind() = ViewGroupViewBinding( 113 | classes = T::class.java, 114 | inflater = LayoutInflater.from(getContext()) 115 | ) 116 | 117 | inline fun ViewGroup.viewbind(viewGroup: ViewGroup) = 118 | ViewGroupViewBinding( 119 | classes = T::class.java, 120 | inflater = LayoutInflater.from(getContext()), 121 | viewGroup = viewGroup 122 | ) -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/ext/LifecycleExt.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.app.Application 6 | import android.app.Fragment 7 | import android.os.Build 8 | import android.os.Bundle 9 | import androidx.appcompat.app.AppCompatActivity 10 | import androidx.fragment.app.FragmentActivity 11 | import androidx.lifecycle.BindingLifecycleObserver 12 | import androidx.lifecycle.Lifecycle 13 | import androidx.lifecycle.LifecycleOwner 14 | 15 | /** 16 | *
 17 |  *     author: dhl
 18 |  *     date  : 2020/12/12
 19 |  *     desc  :
 20 |  * 
21 | */ 22 | 23 | fun Lifecycle.observerWhenDestroyed(destroyed: () -> Unit) { 24 | addObserver(LifecycleObserver(lifecycle = this, destroyed = destroyed)) 25 | } 26 | 27 | fun Lifecycle.observerWhenCreated(create: () -> Unit) { 28 | addObserver(LifecycleObserver(lifecycle = this, create = create)) 29 | } 30 | 31 | class LifecycleObserver( 32 | var lifecycle: Lifecycle?, 33 | var destroyed: (() -> Unit)? = null, 34 | var create: (() -> Unit)? = null 35 | ) : BindingLifecycleObserver() { 36 | 37 | override fun onCreate(owner: LifecycleOwner) { 38 | create?.invoke() 39 | } 40 | 41 | override fun onDestroy(owner: LifecycleOwner) { 42 | destroyed?.invoke() 43 | lifecycle?.apply { 44 | removeObserver(this@LifecycleObserver) 45 | lifecycle = null 46 | } 47 | create = null 48 | destroyed = null 49 | } 50 | } 51 | 52 | fun Activity.observerWhenDestroyed(destroyed: () -> Unit) { 53 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 54 | registerActivityLifecycleCallbacks(LifecycleCallbacks(destroyed)) 55 | } 56 | } 57 | 58 | class LifecycleCallbacks(var destroyed: (() -> Unit)? = null) : 59 | Application.ActivityLifecycleCallbacks { 60 | override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { 61 | } 62 | 63 | override fun onActivityStarted(activity: Activity) { 64 | } 65 | 66 | override fun onActivityResumed(activity: Activity) { 67 | } 68 | 69 | override fun onActivityPaused(activity: Activity) { 70 | } 71 | 72 | override fun onActivityStopped(activity: Activity) { 73 | } 74 | 75 | override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { 76 | } 77 | 78 | override fun onActivityDestroyed(activity: Activity) { 79 | destroyed?.invoke() 80 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 81 | activity.unregisterActivityLifecycleCallbacks(this) 82 | } 83 | destroyed = null 84 | } 85 | } 86 | 87 | class LifecycleFragment : Fragment { 88 | var destroyed: (() -> Unit)? = null 89 | 90 | constructor() 91 | 92 | @SuppressLint("ValidFragment") 93 | constructor(destroyed: () -> Unit) : this() { 94 | this.destroyed = destroyed 95 | } 96 | 97 | override fun onDestroy() { 98 | super.onDestroy() 99 | destroyed?.invoke() 100 | destroyed = null 101 | } 102 | } 103 | 104 | /** 105 | * 当继承 Activity 且 Build.VERSION.SDK_INT < Build.VERSION_CODES.Q 以下的时候, 106 | * 会添加一个 空白的 Fragment, 当生命周期处于 onDestroy 时销毁数据 107 | */ 108 | private const val LIFECYCLE_FRAGMENT_TAG = "com.hi.dhl.binding.lifecycle_fragment" 109 | internal inline fun Activity.registerLifecycleBelowQ(crossinline destroyed: () -> Unit) { 110 | val activity = this 111 | if (activity is FragmentActivity || activity is AppCompatActivity) return 112 | 113 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return 114 | 115 | val fragmentManager = activity.fragmentManager 116 | if (fragmentManager.findFragmentByTag(LIFECYCLE_FRAGMENT_TAG) == null) { 117 | val transaction = fragmentManager.beginTransaction() 118 | transaction.add(LifecycleFragment { destroyed() }, LIFECYCLE_FRAGMENT_TAG).commit() 119 | fragmentManager.executePendingTransactions() 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/ext/ReflectExt.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | 7 | /** 8 | *
 9 |  *     author: dhl
10 |  *     date  : 2020/12/11
11 |  *     desc  :
12 |  * 
13 | */ 14 | 15 | const val INFLATE_NAME = "inflate" 16 | const val BIND_NAME = "bind" 17 | 18 | fun Class.inflateMethod() = getMethod(INFLATE_NAME, LayoutInflater::class.java) 19 | 20 | fun Class.inflateMethodWithViewGroup() = 21 | getMethod(INFLATE_NAME, LayoutInflater::class.java, ViewGroup::class.java) 22 | 23 | fun Class.bindMethod() = getMethod(BIND_NAME, View::class.java) -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/viewbind/ActivityViewBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.viewbind 2 | 3 | import android.app.Activity 4 | import androidx.viewbinding.ViewBinding 5 | import com.hi.dhl.binding.base.ActivityDelegate 6 | import com.hi.dhl.binding.inflateMethod 7 | import kotlin.reflect.KProperty 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/10
13 |  *     desc  :
14 |  * 
15 | */ 16 | 17 | class ActivityViewBinding( 18 | classes: Class, 19 | val activity: Activity 20 | ) : ActivityDelegate(activity) { 21 | 22 | private var layoutInflater = classes.inflateMethod() 23 | 24 | override fun getValue(thisRef: Activity, property: KProperty<*>): T { 25 | return viewBinding?.run { 26 | this 27 | 28 | } ?: let { 29 | // 当继承 Activity 且 Build.VERSION.SDK_INT < Build.VERSION_CODES.Q 时触发 30 | addLifecycleFragment(activity) 31 | 32 | // 获取 ViewBinding 实例 33 | val bind = layoutInflater.invoke(null, thisRef.layoutInflater) as T 34 | thisRef.setContentView(bind.root) 35 | return bind.apply { viewBinding = this } 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/viewbind/DialogViewBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.viewbind 2 | 3 | import android.app.Dialog 4 | import androidx.lifecycle.Lifecycle 5 | import androidx.viewbinding.ViewBinding 6 | import com.hi.dhl.binding.base.DialogDelegate 7 | import com.hi.dhl.binding.inflateMethod 8 | import kotlin.reflect.KProperty 9 | 10 | /** 11 | *
12 |  *     author: dhl
13 |  *     date  : 2020/12/12
14 |  *     desc  :
15 |  * 
16 | */ 17 | class DialogViewBinding( 18 | classes: Class, 19 | lifecycle: Lifecycle? = null 20 | ) : DialogDelegate(lifecycle) { 21 | 22 | private var layoutInflater = classes.inflateMethod() 23 | 24 | override fun getValue(thisRef: Dialog, property: KProperty<*>): T { 25 | return viewBinding?.run { 26 | this 27 | 28 | } ?: let { 29 | 30 | val bind = layoutInflater.invoke(null, thisRef.layoutInflater) as T 31 | thisRef.setContentView(bind.root) 32 | return bind.apply { viewBinding = this } 33 | } 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/viewbind/FragmentViewBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.viewbind 2 | 3 | import androidx.fragment.app.Fragment 4 | import androidx.lifecycle.Lifecycle 5 | import androidx.viewbinding.ViewBinding 6 | import com.hi.dhl.binding.base.FragmentDelegate 7 | import com.hi.dhl.binding.bindMethod 8 | import com.hi.dhl.binding.inflateMethod 9 | import java.lang.Exception 10 | import kotlin.reflect.KProperty 11 | 12 | /** 13 | *
14 |  *     author: dhl
15 |  *     date  : 2020/12/11
16 |  *     desc  :
17 |  * 
18 | */ 19 | class FragmentViewBinding( 20 | classes: Class, 21 | fragment: Fragment 22 | ) : FragmentDelegate(fragment) { 23 | 24 | private val layoutInflater = classes.inflateMethod() 25 | private val bindView = classes.bindMethod() 26 | 27 | override fun getValue(thisRef: Fragment, property: KProperty<*>): T { 28 | return viewBinding?.run { 29 | return this 30 | 31 | } ?: let { 32 | 33 | try { 34 | /** 35 | * 检查目的,是为了防止在 onCreateView() or after onDestroyView() 使用 binding。 36 | * 另外在销毁之后,如果再次使用,由于 delegate property 会被再次初始化出现的异常 37 | * 38 | * 捕获这个异常的原因,是为了兼容之前的版本,防止因为升级,造成崩溃 39 | */ 40 | check(thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { 41 | "cannot use binding in before onCreateView() or after onDestroyView() from 1.1.4. about [issue](https://github.com/hi-dhl/Binding/issues/31#issuecomment-1109733307)" 42 | } 43 | } catch (e: Exception) { 44 | e.printStackTrace() 45 | } 46 | 47 | 48 | val bind: T 49 | if (thisRef.view == null) { 50 | // 这里为了兼容在 navigation 中使用 Fragment 51 | bind = layoutInflater.invoke(null, thisRef.layoutInflater) as T 52 | } else { 53 | bind = bindView.invoke(null, thisRef.view) as T 54 | 55 | } 56 | 57 | return bind.apply { viewBinding = this } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/viewbind/ViewGroupViewBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.viewbind 2 | 3 | import android.app.Activity 4 | import android.os.Build 5 | import android.view.LayoutInflater 6 | import android.view.ViewGroup 7 | import androidx.activity.ComponentActivity 8 | import androidx.viewbinding.ViewBinding 9 | import com.hi.dhl.binding.inflateMethod 10 | import com.hi.dhl.binding.inflateMethodWithViewGroup 11 | import com.hi.dhl.binding.observerWhenDestroyed 12 | import com.hi.dhl.binding.registerLifecycleBelowQ 13 | import java.lang.reflect.Method 14 | import kotlin.properties.ReadOnlyProperty 15 | import kotlin.reflect.KProperty 16 | 17 | /** 18 | *
19 |  *     author: dhl
20 |  *     date  : 2020/12/17
21 |  *     desc  :
22 |  * 
23 | */ 24 | 25 | class ViewGroupViewBinding( 26 | classes: Class, 27 | val inflater: LayoutInflater, 28 | val viewGroup: ViewGroup? = null 29 | ) : ReadOnlyProperty { 30 | 31 | private var viewBinding: T? = null 32 | private var layoutInflater: Method 33 | 34 | init { 35 | if (viewGroup != null) { 36 | layoutInflater = classes.inflateMethodWithViewGroup() 37 | } else { 38 | layoutInflater = classes.inflateMethod() 39 | } 40 | 41 | viewGroup?.apply { 42 | when (context) { 43 | is ComponentActivity -> { 44 | (context as ComponentActivity).lifecycle.observerWhenDestroyed { destroyed() } 45 | } 46 | is Activity -> { 47 | val activity = context as Activity 48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 49 | activity.observerWhenDestroyed { destroyed() } 50 | } else { 51 | activity.registerLifecycleBelowQ { destroyed() } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | override fun getValue(thisRef: ViewGroup, property: KProperty<*>): T { 59 | return viewBinding?.run { 60 | this 61 | 62 | } ?: let { 63 | 64 | val bind: T 65 | if (viewGroup != null) { 66 | bind = layoutInflater.invoke(null, inflater, viewGroup) as T 67 | } else { 68 | bind = layoutInflater.invoke(null, inflater) as T 69 | } 70 | 71 | bind.apply { 72 | if (viewGroup == null) { 73 | thisRef.addView(bind.root) 74 | } 75 | viewBinding = this 76 | } 77 | } 78 | } 79 | 80 | private fun destroyed() { 81 | viewBinding = null 82 | } 83 | } -------------------------------------------------------------------------------- /binding/src/main/java/com/hi/dhl/binding/viewbind/ViewHolderViewBinding.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl.binding.viewbind 2 | 3 | import androidx.recyclerview.widget.RecyclerView 4 | import androidx.viewbinding.ViewBinding 5 | import com.hi.dhl.binding.bindMethod 6 | import kotlin.properties.ReadOnlyProperty 7 | import kotlin.reflect.KProperty 8 | 9 | /** 10 | *
11 |  *     author: dhl
12 |  *     date  : 2020/12/17
13 |  *     desc  :
14 |  * 
15 | */ 16 | class ViewHolderViewBinding( 17 | classes: Class 18 | ) : ReadOnlyProperty { 19 | 20 | private var viewBinding: T? = null 21 | private val bindView = classes.bindMethod() 22 | 23 | override fun getValue(thisRef: RecyclerView.ViewHolder, property: KProperty<*>): T { 24 | return viewBinding?.run { 25 | this 26 | 27 | } ?: let { 28 | val bind = bindView.invoke(null, thisRef.itemView) as T 29 | bind.apply { viewBinding = this } 30 | } 31 | } 32 | 33 | private fun destroyed() { 34 | viewBinding = null 35 | } 36 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '7.2.1' apply false 4 | id 'com.android.library' version '7.2.1' apply false 5 | id 'org.jetbrains.kotlin.android' version '1.6.10' apply false 6 | id 'org.jetbrains.dokka' version '1.7.10' apply false 7 | } 8 | 9 | task clean(type: Delete) { 10 | delete rootProject.buildDir 11 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins{ 2 | `java-gradle-plugin` 3 | `kotlin-dsl` 4 | `kotlin-dsl-precompiled-script-plugins` 5 | } 6 | 7 | buildscript { 8 | 9 | repositories { 10 | gradlePluginPortal() 11 | maven { setUrl("https://oss.sonatype.org/content/repositories/snapshots") } 12 | maven { setUrl("https://maven.aliyun.com/repository/public") } 13 | maven { setUrl("https://maven.aliyun.com/repository/google") } 14 | google() 15 | mavenCentral() 16 | } 17 | dependencies { 18 | classpath(kotlin("gradle-plugin", "1.5.31")) 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation(gradleKotlinDsl()) 24 | implementation(kotlin("stdlib", "1.5.31")) 25 | } 26 | 27 | repositories { 28 | gradlePluginPortal() 29 | maven { setUrl("https://oss.sonatype.org/content/repositories/snapshots") } 30 | maven { setUrl("https://maven.aliyun.com/repository/public") } 31 | maven { setUrl("https://maven.aliyun.com/repository/google") } 32 | google() 33 | mavenCentral() 34 | } -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/hi/dhl/Deps.kt: -------------------------------------------------------------------------------- 1 | package com.hi.dhl 2 | 3 | import org.gradle.api.JavaVersion 4 | 5 | object Versions { 6 | val junit = "4.12" 7 | 8 | val kotlinVersion = "1.4.21" 9 | val gradleVersion = "4.1.1" 10 | 11 | val fragment = "1.2.5" 12 | val viewmodel = "2.2.1" 13 | val navigation = "2.3.2" 14 | val constraintlayout = "2.0.4" 15 | val material = "1.2.1" 16 | val appcompat = "1.2.0" 17 | val coreKtx = "1.3.2" 18 | val coil = "1.1.0" 19 | val binding = "1.1.9-SNAPSHOT" 20 | val baseRecyclerViewAdapterHelper = "3.0.4" 21 | val espressoCore = "3.3.0" 22 | val junitExt = "1.1.2" 23 | val viewpager2 = "1.0.0-beta02" 24 | val recyclerview = "1.1.0" 25 | 26 | val compileSdkVersion = 30 27 | val buildToolsVersion = "30.0.2" 28 | val libMinSdkVersion = 14 29 | val libTargetSdkVersion = 32 30 | val libVersionCode = 10104 31 | val libVersionName = "1.1.5" 32 | 33 | val remote = true 34 | 35 | } 36 | 37 | object Common{ 38 | val jdk = JavaVersion.VERSION_11 39 | } 40 | 41 | object Deps { 42 | 43 | val kotlinStdlib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlinVersion}" 44 | 45 | object AndroidX{ 46 | val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}" 47 | val appcompat = "androidx.appcompat:appcompat:${Versions.appcompat}" 48 | val constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}" 49 | val viewmodel = "org.koin:koin-androidx-viewmodel:${Versions.viewmodel}" 50 | val navigationFragmentKtx = "androidx.navigation:navigation-fragment-ktx:${Versions.navigation}" 51 | val navigationUiKtx = "androidx.navigation:navigation-ui-ktx:${Versions.navigation}" 52 | val viewpager2 = "androidx.viewpager2:viewpager2:${Versions.viewpager2}" 53 | val junitExt = "androidx.test.ext:junit:${Versions.junitExt}" 54 | val espressoCore = "androidx.test.espresso:espresso-core:${Versions.espressoCore}" 55 | val recyclerview = "androidx.recyclerview:recyclerview:${Versions.recyclerview}" 56 | } 57 | 58 | object Android{ 59 | val material = "com.google.android.material:material:${Versions.material}" 60 | } 61 | 62 | val coil = "io.coil-kt:coil:${Versions.coil}" 63 | val binding = "com.hi-dhl:binding:${Versions.binding}" 64 | 65 | val baseRecyclerViewAdapterHelper = "com.github.CymChad:BaseRecyclerViewAdapterHelper:${Versions.baseRecyclerViewAdapterHelper}" 66 | val junit = "junit:junit:${Versions.junit}" 67 | 68 | } 69 | -------------------------------------------------------------------------------- /buildSrc/src/test/kotlin/com/hi/dhl/DepsTest.java: -------------------------------------------------------------------------------- 1 | package com.hi.dhl; 2 | 3 | public class DepsTest { 4 | 5 | } -------------------------------------------------------------------------------- /doc/README_CN.md: -------------------------------------------------------------------------------- 1 | #

Binding

2 | 3 |

4 | Simple API implement DataBinding and ViewBinding. Welcome star
5 | 简单的 API 实现 DataBinding 和 ViewBinding,欢迎 star 6 |

7 | 8 |

9 | English  10 | · 11 |  中文 12 |

13 | 14 |

15 | 16 |

17 | 18 |

如果图片无法查看,请点击这里查看 图例1 | 图例2

19 | 20 |

21 | 22 |

23 | 24 |

25 | 26 |

27 | 28 | 29 | ## 关于 Binding 30 | 31 | > 因 Jcenter 即将被废弃,已经将 Binding 迁移到 mavenCentral 32 | 33 | Binding 简化 DataBinding 和 ViewBinding 的使用, 只需要一行代码即可实现 DataBinding 和 ViewBinding。 34 | 35 | Binding 未来的规划提供通用的 `findViewById` 解决方案,,因技术的迭代更新从 butterknife 、 DataBinding 、 Kotlin 合成方法(Synthetic 视图)到现在 ViewBinding , 未来也有可能出现新的技术,无论技术怎么变化,只需要更新 Binding ,对外的使用保持不变。 36 | 37 | * Kotlin 合成方法(Synthetic 视图)比 ViewBinding 方便这么多,为什么会被 Google 抛弃掉,请查看这篇文章 [Kotlin 插件的落幕,ViewBinding 的崛起](https://mp.weixin.qq.com/s/FxrRyXp9-VDdv-mfkzsIsA)。 38 | 39 | * 这篇文章 [竟然如此简单,DataBinding 和 ViewBinding](https://mp.weixin.qq.com/s/omn7AhHzihhtr0vtq6csNg) 从使用的角度分析了 DataBinding 和 ViewBinding 不同之处,同时也介绍了如何用更简单的方式实现 DataBinding 和 ViewBinding。 40 | 41 | 感谢小伙伴们的建议,目前 Binding 已经适配了大量的场景,同时也提供了很多 DataBinding 和 ViewBinding 实战案例,如果你在使用过程中遇到 Binding 不兼容的场景,欢迎提 issue,我会尽快解决。 42 | 43 | **如果这个仓库对你有帮助,请在仓库右上角帮我 star 一下,非常感谢你的支持,同时也欢迎你提交 PR** ❤️❤️❤️ 44 | 45 | **[Binding](https://github.com/hi-dhl/Binding) 具有以下优点:** 46 | 47 | * 支持在自定义 ViewGroup 使用 DataBinding 或者 ViewBinding 48 | * 提供了很多实战案例包含 `Ativity` 、 `Fragment` 、 `Dialog` 、 `Adapter` 、 `include` 、 `merge` 、 `ViewStub` 、 `Navigation` 、 数据双向绑定 等等场景 49 | * 简单的 API 只需要一行代码即可实现 DataBinding 或者 ViewBinding 50 | * 支持在 `Activity` 、`AppCompatActivity` 、`FragmentActivity` 、`Fragment` 、`Dialog` 中的使用 DataBinding 或者 ViewBinding 51 | * 支持在 `ListAdapter` 、 `PagedListAdapter` 、 `PagingDataAdapter` 、 `RecyclerView.Adapter` 中的使用 DataBinding 或者 ViewBinding 52 | * 支持在 Navigaion Fragment 管理框架、 BottomSheetDialogFragment 等等场景中使用 DataBinding 和 ViewBinding 53 | * 避免大量的模板代码 54 | * 避免内存泄露,具有生命周期感知能力,当生命周期处于 `onDestroyed()` 时会自动销毁数据 55 | 56 | 57 | ## Download 58 | 59 | 将下列代码添加在 Project 级别的 `build.gradle` 文件中 60 | 61 | ``` 62 | allprojects { 63 | repositories { 64 | // aliyun center 包含 mavenCentral 和 jcenter 65 | maven { url "https://maven.aliyun.com/repository/public" } 66 | // maven 67 | mavenCentral() 68 | } 69 | } 70 | ``` 71 | 72 | **添加依赖** 73 | 74 | 将下列代码添加在模块级 `build.gradle` 文件中,并且需要开启 DataBinding 或者 ViewBinding 75 | 76 | ``` 77 | android { 78 | buildFeatures { 79 | dataBinding = true 80 | viewBinding = true 81 | } 82 | } 83 | 84 | dependencies { 85 | implementation 'com.hi-dhl:binding:${binding_version}' 86 | } 87 | ``` 88 | 89 | binding 最新版本 ![](https://img.shields.io/maven-central/v/com.hi-dhl/binding.svg?label=Maven%20Central) 90 | 91 | ## 简单的 API 92 | 93 | Binding 统一封装了 DataBinding 和 ViewBinding, 提供了简单的 API 如下所示。 94 | 95 | **ViewBinding 中的使用** 96 | 97 | ``` 98 | val binding: ActivityViewBindBinding by viewbind() 99 | ``` 100 | 101 | **DataBinding 中的使用** 102 | 103 | ``` 104 | val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind) 105 | 或者 106 | val binding: ActivityDataBindBinding by databind() 107 | ``` 108 | 109 | 我们来看一下在 `Ativity` 、 `Fragment` 、 `Dialog` 、 `Adapter` 、 `include` 、 `merge` 、 `ViewStub` 、 `Navigation` 、 `ViewGroup` 、 数据双向绑定 等等场景中如何使用。 110 | 111 | ## 使用 112 | 113 | 在自定义 ViewGroup 中使用 DataBinding 和 ViewBinding, 114 | 115 | * ViewBinding 两种用法 116 | * 当根布局是非 merge 标签,使用此方法进行初始化 `val binding: LayoutViewCustomBinding by viewbind()` 117 | * 当根布局为 merge 标签,使用此方法进行初始化 `val binding: LayoutViewCustomBinding by viewbind(this)` 118 | 119 | * DataBinding 的使用 120 | 121 | ``` 122 | val binding: LayoutViewCustomDataBinding by databind(R.layout.layout_view_custom_data) 123 | ``` 124 | 125 | 详细的 Demo 示例如下所示。 126 | 127 | ``` 128 | class ViewBindCustomView @JvmOverloads constructor( 129 | context: Context, 130 | attr: AttributeSet? = null, 131 | defStyleAttr: Int = 0, 132 | ) : LinearLayout(context, attr, defStyleAttr) { 133 | 134 | // ViewBinding 135 | 136 | // 当根布局为 merge 标签,使用此方法进行初始化 137 | val binding: LayoutViewCustomBinding by viewbind(this) 138 | 139 | // 当根布局是非 merge 标签,使用此方法进行初始化 140 | val binding: LayoutViewCustomBinding by viewbind() 141 | 142 | // DataBinding 143 | val binding: LayoutViewCustomDataBinding by databind(R.layout.layout_view_custom_data) 144 | 145 | init { 146 | with(binding) { 147 | result.setText("在自定义 ViewGroup 中使用 DataBinding 或者 ViewBinding") 148 | } 149 | } 150 | } 151 | ``` 152 | 153 | 在 Adapter 中使用 DataBinding 和 ViewBinding,只需要在 ViewHolder 中添加 `by viewbind()` 或者 `by databind()` 即可,示例如下所示,[查看详细示例](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/databind/list/ProductAdapter.kt) 154 | 155 | ``` 156 | class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) { 157 | 158 | // 通过 DataBinding 绑定的 itemView 159 | val binding: RecycleItemProductBinding by databind() 160 | 161 | fun bindData(data: Product?, position: Int) { 162 | binding.apply { 163 | product = data 164 | executePendingBindings() 165 | } 166 | } 167 | } 168 | 169 | class ProductViewHolderHeader(view: View) : RecyclerView.ViewHolder(view) { 170 | 171 | // ViewBinding 172 | val binding: RecycleItemProductHeaderBinding by viewbind() 173 | 174 | fun bindData(data: Product?, position: Int) { 175 | binding.apply { 176 | name.text = "通过 ViewBinding 绑定的 head" 177 | } 178 | } 179 | } 180 | ``` 181 | 182 | 183 | 在 `Activity` 、`AppCompatActivity` 、`FragmentActivity` 中使用,添加 `by viewbind()` 或者 `by databind(R.layout.activity_main)` 即可,示例如下所示。 184 | 185 | ``` 186 | class MainActivity : AppCompatActivity() { 187 | 188 | // DataBinding 189 | val binding: ActivityMainBinding by databind(R.layout.activity_main) 190 | 191 | // ViewBinding 192 | val binding: ActivityMainBinding by viewbind() 193 | } 194 | ``` 195 | 196 | 在 `Fragment` 中提供了两种方式: 197 | 198 | * 方式一:在 `onCreateView` 中使用,[查看详细示例](https://github.com/hi-dhl/Binding/tree/main/app/src/main/java/com/hi/dhl/demo/binding/navigation) 199 | * 方式二:在 `onViewCreated` 中使用,查看 [ViewBindFragment.kt](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindFragment.kt) 和 [DataBindRecycleFragment.kt](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/databind/list/DataBindRecycleFragment.kt) 200 | 201 | **方式一:不建议使用,建议直接使用方式二,详见 issue [#13](https://github.com/hi-dhl/Binding/issues/13)** 202 | 203 | ``` 204 | class FragmentNav1 : Fragment() { 205 | 206 | // DataBinding 207 | val binding: FragmentMainBinding by databind() 208 | 209 | // ViewBinding 210 | val binding: FragmentMainBinding by viewbind() 211 | 212 | override fun onCreateView( 213 | inflater: LayoutInflater, container: ViewGroup?, 214 | savedInstanceState: Bundle? 215 | ): View { 216 | return binding.root 217 | } 218 | } 219 | ``` 220 | 221 | **方式二:** 222 | 223 | ``` 224 | class FragmentNav1 : Fragment(R.layout.fragment_main) { 225 | 226 | // DataBinding 227 | val binding: FragmentMainBinding by databind() 228 | 229 | // ViewBinding 230 | val binding: FragmentMainBinding by viewbind() 231 | 232 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 233 | super.onViewCreated(view, savedInstanceState) 234 | binding.apply { textView.setText("Binding") } 235 | } 236 | } 237 | ``` 238 | 239 | 在 `Dialog` 中使用方式如下所示。 240 | 241 | ``` 242 | class AppDialog(context: Context) : Dialog(context, R.style.AppDialog) { 243 | 244 | // DataBinding 245 | val binding: DialogAppBinding by databind(R.layout.dialog_data_binding) 246 | 247 | // ViewBinding 248 | val binding: DialogAppBinding by viewbind() 249 | 250 | override fun onCreate(savedInstanceState: Bundle?) { 251 | super.onCreate(savedInstanceState) 252 | binding.apply { result.setText("DialogAppBinding") } 253 | } 254 | } 255 | ``` 256 | 257 | 或者添加具有生命周期感知的 `Dialog`。 258 | 259 | ``` 260 | class AppDialog(context: Context,lifecycle: Lifecycle) : Dialog(context, R.style.AppDialog) { 261 | 262 | // DataBinding 监听生命周期 263 | val binding: DialogAppBinding by databind(R.layout.dialog_data_binding, lifecycle) 264 | 265 | // ViewBinding 监听生命周期 266 | val binding: DialogAppBinding by viewbind(lifecycle) 267 | 268 | override fun onCreate(savedInstanceState: Bundle?) { 269 | super.onCreate(savedInstanceState) 270 | binding.apply { result.setText("DialogAppBinding") } 271 | } 272 | } 273 | ``` 274 | 275 | 扩展方法,支持 DataBinding 初始化的时候绑定数据,感谢 `@br3ant` 贡献,[查看详细示例](https://github.com/hi-dhl/Binding/blob/054aa169d8dd39023be55be589b67e8097702bd1/app/src/main/java/com/hi/dhl/demo/binding/databind/DatBindActivity.kt#L28-L33) 276 | 277 | ``` 278 | val binding: ActivityDataBindBinding by databind(R.layout.activity_data_bind) { 279 | val account = Account() 280 | account.name = "test" 281 | this.account = account 282 | } 283 | ``` 284 | 285 | 不想为某个布局生成 binding 类,将下面属性添加到布局文件的根视图中 286 | 287 | ``` 288 | 289 | 290 | ``` 291 | 292 | ### 混淆 293 | 294 | ``` 295 | -keepclassmembers class ** implements androidx.viewbinding.ViewBinding { 296 | public static ** bind(***); 297 | public static ** inflate(***); 298 | } 299 | ``` 300 | 301 | ### 更新记录 302 | 303 | **2023-04-13(V1.2.0)** 304 | 305 | * 兼容 lifecycle 2.6.0 FullLifecycleObserver 被删除的问题 306 | 307 | **2022-10-07(V1.1.9)** 308 | 309 | * 兼容 jdk >= 1.8 310 | 311 | **2022-7-13(V1.1.7)** 312 | 313 | * 兼容不传 ViewGroup 的情况[#34](https://github.com/hi-dhl/Binding/issues/34) 314 | 315 | **2022-5-12(V1.1.5)** 316 | 317 | * 修改 ViewGroup 销毁的时候释放资源 [#33](https://github.com/hi-dhl/Binding/issues/33) 318 | 319 | **2022-5-03(V1.1.4)** 320 | 321 | * 修复了生命周期问题 322 | * 修复了销毁之后再次使用,由于 delegate property 会被再次初始化,出现的异常 [#31](https://github.com/hi-dhl/Binding/issues/31) 323 | 324 | **2021-5-09(V1.1.3)** 325 | 326 | * 修复在 ViewGroup 中是用 merge 标签,inflate 无法找到的问题 [#26](https://github.com/hi-dhl/Binding/issues/26) 327 | 328 | **2021-3-09(V1.1.2)** 329 | 330 | * 修改 FragmentDataBinding 绑定 View 生命周期为 viewLifecycleOwner [#18](https://github.com/hi-dhl/Binding/issues/18) 331 | * 迁移到 mavenCentral 332 | 333 | **2021-1-25(V1.0.9)** 334 | 335 | * 修复了 Fragment lifecycle 和 Fragment 中的 View 生命周期不一致问题 [#15](https://github.com/hi-dhl/Binding/issues/15) 336 | * 修复了 Fragment 根部局的 layout 属性失效的问题 [#13](https://github.com/hi-dhl/Binding/issues/13) 337 | 338 | **2021-1-14(V1.0.8)** 339 | 340 | * 支持在自定义 ViewGroup 使用 DataBinding 或者 ViewBinding 341 | * 增加了在 ViewGroup 中的使用案例 342 | 343 | **2020-12-31** 344 | 345 | * 增加 ViewStub 在 DataBinding 和 ViewBinding 中的使用案例,[查看详细示例](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/databind/BindViewStubActivity.kt) 346 | * 增加 include 在 DataBinding 和 ViewBinding 中的使用案例,[DataBindIncludeActivity](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/databind/DataBindIncludeActivity.kt) 或者 [ViewBindIncludeActivity](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/viewbind/ViewBindIncludeActivity.kt) 347 | 348 | **2020-12-28(V1.0.6)** 349 | 350 | * 支持 Activity 和 Fragment 自动绑定 LifecycleOwner。[详见 issue](https://github.com/hi-dhl/Binding/issues/8) 351 | 352 | **2020-12-21(V1.0.5)** 353 | 354 | * 支持在 navigation fragment 中使用 DataBinding 和 ViewBinding,[查看详细示例](https://github.com/hi-dhl/Binding/tree/main/app/src/main/java/com/hi/dhl/demo/binding/navigation) 355 | 356 | **2020-12-17(V1.0.4)** 357 | 358 | * 支持所有与 RecyclerView.ViewHolder 相关的 Adapter(ListAdapter、PagingDataAdapter、RecyclerView.Adapter 等等)使用 DataBinding 和 ViewBinding,[查看详细示例](https://github.com/hi-dhl/Binding/blob/main/app/src/main/java/com/hi/dhl/demo/binding/databind/list/ProductAdapter.kt) 359 | 360 | * 支持通过 `by databind` 初始化,同时可以绑定数据,感谢 `@br3ant` 贡献,[查看详细示例](https://github.com/hi-dhl/Binding/blob/054aa169d8dd39023be55be589b67e8097702bd1/app/src/main/java/com/hi/dhl/demo/binding/databind/DatBindActivity.kt#L28-L33) 361 | 362 | **2020-12-15(V1.0.3)** 363 | 364 | * 添加了 DataBinding 在 Dialog 中的使用, `by databind(R.layout.dialog_data_binding)` 或者 `by databind(R.layout.dialog_data_binding, lifecycle)` 365 | * 处理了 `大于等于 Android 10.0` 和 `小于 Android 10.0` 生命周期问题,当处于 `onDestroyed()` 时会自动销毁数据 366 | * 最低 SDK 版本降低至 14 367 | 368 | **2020-12-14:** 369 | 370 | * Demo 增加 DataBinding 示例 371 | * Demo 增加 ViewBinding 示例 372 | * Demo 增加 kotlin-parcelize 示例 373 | 374 | **2020-12-13(V1.0.1)** 375 | 376 | * 添加了 ViewBinding 在 Dialog 中的使用, `by viewbind()` 或者 `by viewbind(lifecycle)` 377 | 378 | **2020-12-12(V1.0.0)** 379 | 380 | * 添加 DataBinding 和 ViewBinding 在 `Activity` 、`AppCompatActivity` 、`FragmentActivity` 、`Fragment` 中的使用 381 | * 避免模板代码,只需要一行代码即可实现 DataBinding 或者 ViewBinding 382 | * 当生命周期处于 `onDestroyed()` 时会自动销毁数据 383 | 384 | ### 联系我 385 | 386 | * 个人微信:hi-dhl 387 | * 公众号:ByteCode,包含 Jetpack ,Kotlin ,Android 10 系列源码,译文,LeetCode / 剑指 Offer / 多线程 / 国内外大厂算法题 等等一系列文章 388 | 389 | 390 | 391 | --- 392 | 393 | 最后推荐我一直在更新维护的项目和网站: 394 | 395 | * 计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看:[AndroidX-Jetpack-Practice](https://github.com/hi-dhl/AndroidX-Jetpack-Practice) 396 | 397 | * LeetCode / 剑指 offer / 国内外大厂面试题 / 多线程 题解,语言 Java 和 kotlin,包含多种解法、解题思路、时间复杂度、空间复杂度分析
398 | 399 | 400 | 401 | * 剑指 offer 及国内外大厂面试题解:[在线阅读](https://offer.hi-dhl.com) 402 | * LeetCode 系列题解:[在线阅读](https://leetcode.hi-dhl.com) 403 | 404 | * 最新 Android 10 源码分析系列文章,了解系统源码,不仅有助于分析问题,在面试过程中,对我们也是非常有帮助的,仓库持续更新,欢迎前去查看 [Android10-Source-Analysis](https://github.com/hi-dhl/Android10-Source-Analysis) 405 | 406 | * 整理和翻译一系列精选国外的技术文章,每篇文章都会有**译者思考**部分,对原文的更加深入的解读,仓库持续更新,欢迎前去查看 [Technical-Article-Translation](https://github.com/hi-dhl/Technical-Article-Translation) 407 | 408 | * 「为互联网人而设计,国内国外名站导航」涵括新闻、体育、生活、娱乐、设计、产品、运营、前端开发、Android 开发等等网址,欢迎前去查看 [为互联网人而设计导航网站](https://site.51git.cn) 409 | 410 | **感谢** 411 | 412 | 感谢 [Simple one-liner ViewBinding in Fragments and Activities with Kotlin](https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c) 文章带来的思路,以及从 [Anko](https://github.com/Kotlin/anko) 、 [ViewBindingDelegate](https://github.com/hoc081098/ViewBindingDelegate) 、[architecture-components-samples](https://github.com/android/architecture-components-samples) 和 jetpack 等等开源库中学习到技巧 413 | 414 | 415 | -------------------------------------------------------------------------------- /gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'signing' 3 | apply plugin: 'org.jetbrains.dokka' 4 | 5 | /** 6 | * https://docs.gradle.org/current/userguide/publishing_maven.html 7 | */ 8 | 9 | def getReleaseRepositoryUrl() { 10 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 11 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 12 | } 13 | 14 | def getSnapshotRepositoryUrl() { 15 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 16 | : "https://oss.sonatype.org/content/repositories/snapshots/" 17 | } 18 | 19 | 20 | task androidSourcesJar(type: Jar) { 21 | archiveClassifier.set('sources') 22 | if (project.plugins.findPlugin("com.android.application") 23 | || project.plugins.findPlugin("com.android.library")) { 24 | from android.sourceSets.main.java.srcDirs 25 | from android.sourceSets.main.kotlin.srcDirs 26 | } else { 27 | from sourceSets.main.java.srcDirs 28 | from sourceSets.main.kotlin.srcDirs 29 | } 30 | } 31 | 32 | tasks.withType(dokkaHtmlPartial.getClass()).configureEach { 33 | pluginsMapConfiguration.set( 34 | ["org.jetbrains.dokka.base.DokkaBase": """{ "separateInheritedMembers": true}"""] 35 | ) 36 | } 37 | 38 | task javadocJar(type: Jar, dependsOn: dokkaJavadoc) { 39 | archiveClassifier.set('javadoc') 40 | from dokkaJavadoc.outputDirectory 41 | } 42 | 43 | afterEvaluate { 44 | publishing { 45 | publications { 46 | release(MavenPublication) { 47 | groupId GROUP_ID 48 | artifactId POM_ARTIFACT_ID 49 | version VERSION_NAME 50 | 51 | if (project.plugins.findPlugin("com.android.library")) { 52 | from components.release 53 | } else { 54 | from components.java 55 | } 56 | 57 | artifact androidSourcesJar 58 | artifact javadocJar 59 | 60 | pom { 61 | name = POM_NAME 62 | description = POM_DESCRIPTION 63 | url = POM_URL 64 | packaging = POM_PACKAGING 65 | inceptionYear = POM_INCEPTION_YEAR 66 | 67 | licenses { 68 | license { 69 | name = POM_LICENCE_NAME 70 | distribution = POM_LICENCE_DIST 71 | } 72 | } 73 | developers { 74 | developer { 75 | id = POM_DEVELOPER_ID 76 | name = POM_DEVELOPER_NAME 77 | email = POM_DEVELOPER_EMAIL 78 | url = POM_DEVELOPER_URL 79 | } 80 | } 81 | scm { 82 | url = POM_SCM_URL 83 | connection = POM_SCM_CONNECTION 84 | developerConnection = POM_SCM_DEV_CONNECTION 85 | } 86 | } 87 | } 88 | } 89 | 90 | repositories { 91 | maven { 92 | def releasesRepoUrl = getReleaseRepositoryUrl() 93 | def snapshotsRepoUrl = getSnapshotRepositoryUrl() 94 | url = VERSION_NAME.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 95 | 96 | credentials { 97 | username sonatypeUsername 98 | password sonatypePassword 99 | } 100 | } 101 | } 102 | 103 | artifacts { 104 | archives androidSourcesJar 105 | archives javadocJar 106 | } 107 | 108 | signing { 109 | sign publishing.publications 110 | } 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | 23 | #VERSION_NAME=1.2.0-SNAPSHOT 24 | VERSION_NAME=1.2.0 25 | POM_DESCRIPTION=Simple API implement DataBinding and ViewBinding 26 | POM_NAME=binding 27 | POM_ARTIFACT_ID=binding 28 | POM_PACKAGING=aar 29 | POM_INCEPTION_YEAR=2020 30 | 31 | POM_URL=https://github.com/hi-dhl/Binding 32 | POM_SCM_URL=https://github.com/hi-dhl/Binding 33 | POM_SCM_CONNECTION=scm:git@github.com:hi-dhl/Binding.git 34 | POM_SCM_DEV_CONNECTION=scm:git@github.com:hi-dhl/Binding.git -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 10 10:24:40 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } 4 | maven { url "https://maven.aliyun.com/repository/public" } 5 | maven { url 'https://maven.aliyun.com/repository/google' } 6 | gradlePluginPortal() 7 | google() 8 | mavenCentral() 9 | } 10 | } 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } 15 | maven { url "https://maven.aliyun.com/repository/public" } 16 | maven { url 'https://maven.aliyun.com/repository/google' } 17 | gradlePluginPortal() 18 | google() 19 | mavenCentral() 20 | } 21 | } 22 | include ':binding' 23 | include ':app' 24 | rootProject.name = "Binding" -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hi-dhl/Binding/43ca731602ae3b15094b67c1fe904ab1e13410f7/settings.gradle.kts --------------------------------------------------------------------------------