Showing preview only (627K chars total). Download the full file or copy to clipboard to get everything.
Repository: goldze/MVVMHabit
Branch: master
Commit: ab2bf079815e
Files: 190
Total size: 566.8 KB
Directory structure:
gitextract_gppaw7p9/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── UpdateLog.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── goldze/
│ │ └── mvvmhabit/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── goldze/
│ │ │ └── mvvmhabit/
│ │ │ ├── app/
│ │ │ │ ├── AppApplication.java
│ │ │ │ ├── AppViewModelFactory.java
│ │ │ │ └── Injection.java
│ │ │ ├── binding/
│ │ │ │ └── twinklingrefreshlayout/
│ │ │ │ └── ViewAdapter.java
│ │ │ ├── data/
│ │ │ │ ├── DemoRepository.java
│ │ │ │ └── source/
│ │ │ │ ├── HttpDataSource.java
│ │ │ │ ├── LocalDataSource.java
│ │ │ │ ├── http/
│ │ │ │ │ ├── HttpDataSourceImpl.java
│ │ │ │ │ └── service/
│ │ │ │ │ └── DemoApiService.java
│ │ │ │ └── local/
│ │ │ │ └── LocalDataSourceImpl.java
│ │ │ ├── entity/
│ │ │ │ ├── DemoEntity.java
│ │ │ │ ├── FormEntity.java
│ │ │ │ └── SpinnerItemData.java
│ │ │ ├── ui/
│ │ │ │ ├── base/
│ │ │ │ │ ├── adapter/
│ │ │ │ │ │ └── BaseFragmentPagerAdapter.java
│ │ │ │ │ ├── fragment/
│ │ │ │ │ │ └── BasePagerFragment.java
│ │ │ │ │ └── viewmodel/
│ │ │ │ │ └── ToolbarViewModel.java
│ │ │ │ ├── form/
│ │ │ │ │ ├── FormFragment.java
│ │ │ │ │ └── FormViewModel.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── LoginActivity.java
│ │ │ │ │ └── LoginViewModel.java
│ │ │ │ ├── main/
│ │ │ │ │ ├── DemoActivity.java
│ │ │ │ │ └── DemoViewModel.java
│ │ │ │ ├── network/
│ │ │ │ │ ├── NetWorkFragment.java
│ │ │ │ │ ├── NetWorkItemViewModel.java
│ │ │ │ │ ├── NetWorkViewModel.java
│ │ │ │ │ └── detail/
│ │ │ │ │ ├── DetailFragment.java
│ │ │ │ │ └── DetailViewModel.java
│ │ │ │ ├── rv_multi/
│ │ │ │ │ ├── MultiRecycleHeadViewModel.java
│ │ │ │ │ ├── MultiRecycleLeftItemViewModel.java
│ │ │ │ │ ├── MultiRecycleRightItemViewModel.java
│ │ │ │ │ ├── MultiRecycleViewFragment.java
│ │ │ │ │ └── MultiRecycleViewModel.java
│ │ │ │ ├── tab_bar/
│ │ │ │ │ ├── activity/
│ │ │ │ │ │ └── TabBarActivity.java
│ │ │ │ │ └── fragment/
│ │ │ │ │ ├── TabBar1Fragment.java
│ │ │ │ │ ├── TabBar2Fragment.java
│ │ │ │ │ ├── TabBar3Fragment.java
│ │ │ │ │ └── TabBar4Fragment.java
│ │ │ │ ├── viewpager/
│ │ │ │ │ ├── activity/
│ │ │ │ │ │ └── ViewPagerActivity.java
│ │ │ │ │ ├── adapter/
│ │ │ │ │ │ └── ViewPagerBindingAdapter.java
│ │ │ │ │ └── vm/
│ │ │ │ │ ├── ViewPagerItemViewModel.java
│ │ │ │ │ └── ViewPagerViewModel.java
│ │ │ │ └── vp_frg/
│ │ │ │ └── ViewPagerGroupFragment.java
│ │ │ └── utils/
│ │ │ ├── HttpsUtils.java
│ │ │ └── RetrofitClient.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── login_clear_input.xml
│ │ ├── layout/
│ │ │ ├── activity_demo.xml
│ │ │ ├── activity_login.xml
│ │ │ ├── activity_tab_bar.xml
│ │ │ ├── fragment_base_pager.xml
│ │ │ ├── fragment_detail.xml
│ │ │ ├── fragment_form.xml
│ │ │ ├── fragment_multi_rv.xml
│ │ │ ├── fragment_network.xml
│ │ │ ├── fragment_tab_bar_1.xml
│ │ │ ├── fragment_tab_bar_2.xml
│ │ │ ├── fragment_tab_bar_3.xml
│ │ │ ├── fragment_tab_bar_4.xml
│ │ │ ├── fragment_viewpager.xml
│ │ │ ├── item_multi_head.xml
│ │ │ ├── item_multi_rv_left.xml
│ │ │ ├── item_multi_rv_right.xml
│ │ │ ├── item_network.xml
│ │ │ ├── item_viewpager.xml
│ │ │ └── layout_toolbar.xml
│ │ ├── values/
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── xml/
│ │ └── network_security_config.xml
│ └── test/
│ └── java/
│ └── com/
│ └── goldze/
│ └── mvvmhabit/
│ └── ExampleUnitTest.java
├── build.gradle
├── config.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── mvvmhabit/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── me/
│ │ └── goldze/
│ │ └── mvvmhabit/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── me/
│ │ │ └── goldze/
│ │ │ └── mvvmhabit/
│ │ │ ├── base/
│ │ │ │ ├── AppManager.java
│ │ │ │ ├── BaseActivity.java
│ │ │ │ ├── BaseApplication.java
│ │ │ │ ├── BaseFragment.java
│ │ │ │ ├── BaseModel.java
│ │ │ │ ├── BaseViewModel.java
│ │ │ │ ├── ContainerActivity.java
│ │ │ │ ├── IBaseView.java
│ │ │ │ ├── IBaseViewModel.java
│ │ │ │ ├── IModel.java
│ │ │ │ ├── ItemViewModel.java
│ │ │ │ ├── MultiItemViewModel.java
│ │ │ │ └── ViewModelFactory.java
│ │ │ ├── binding/
│ │ │ │ ├── command/
│ │ │ │ │ ├── BindingAction.java
│ │ │ │ │ ├── BindingCommand.java
│ │ │ │ │ ├── BindingConsumer.java
│ │ │ │ │ ├── BindingFunction.java
│ │ │ │ │ └── ResponseCommand.java
│ │ │ │ └── viewadapter/
│ │ │ │ ├── checkbox/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── edittext/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── image/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── listview/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── mswitch/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── radiogroup/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── recyclerview/
│ │ │ │ │ ├── DividerLine.java
│ │ │ │ │ ├── LayoutManagers.java
│ │ │ │ │ ├── LineManagers.java
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── scrollview/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── spinner/
│ │ │ │ │ ├── IKeyAndValue.java
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── swiperefresh/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── view/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── viewgroup/
│ │ │ │ │ ├── IBindingItemViewModel.java
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ ├── viewpager/
│ │ │ │ │ └── ViewAdapter.java
│ │ │ │ └── webview/
│ │ │ │ └── ViewAdapter.java
│ │ │ ├── bus/
│ │ │ │ ├── Messenger.java
│ │ │ │ ├── RxBus.java
│ │ │ │ ├── RxBusSubscriber.java
│ │ │ │ ├── RxSubscriptions.java
│ │ │ │ ├── WeakAction.java
│ │ │ │ └── event/
│ │ │ │ ├── SingleLiveEvent.java
│ │ │ │ └── SnackbarMessage.java
│ │ │ ├── crash/
│ │ │ │ ├── CaocConfig.java
│ │ │ │ ├── CaocInitProvider.java
│ │ │ │ ├── CustomActivityOnCrash.java
│ │ │ │ └── DefaultErrorActivity.java
│ │ │ ├── http/
│ │ │ │ ├── ApiDisposableObserver.java
│ │ │ │ ├── BaseResponse.java
│ │ │ │ ├── DownLoadManager.java
│ │ │ │ ├── ExceptionHandle.java
│ │ │ │ ├── NetworkUtil.java
│ │ │ │ ├── ResponseThrowable.java
│ │ │ │ ├── cookie/
│ │ │ │ │ ├── CookieJarImpl.java
│ │ │ │ │ └── store/
│ │ │ │ │ ├── CookieStore.java
│ │ │ │ │ ├── MemoryCookieStore.java
│ │ │ │ │ ├── PersistentCookieStore.java
│ │ │ │ │ └── SerializableHttpCookie.java
│ │ │ │ ├── download/
│ │ │ │ │ ├── DownLoadStateBean.java
│ │ │ │ │ ├── DownLoadSubscriber.java
│ │ │ │ │ ├── ProgressCallBack.java
│ │ │ │ │ └── ProgressResponseBody.java
│ │ │ │ └── interceptor/
│ │ │ │ ├── BaseInterceptor.java
│ │ │ │ ├── CacheInterceptor.java
│ │ │ │ ├── ProgressInterceptor.java
│ │ │ │ └── logging/
│ │ │ │ ├── I.java
│ │ │ │ ├── Level.java
│ │ │ │ ├── Logger.java
│ │ │ │ ├── LoggingInterceptor.java
│ │ │ │ └── Printer.java
│ │ │ ├── utils/
│ │ │ │ ├── CloseUtils.java
│ │ │ │ ├── ConvertUtils.java
│ │ │ │ ├── ImageUtils.java
│ │ │ │ ├── KLog.java
│ │ │ │ ├── MaterialDialogUtils.java
│ │ │ │ ├── RegexUtils.java
│ │ │ │ ├── RxUtils.java
│ │ │ │ ├── SDCardUtils.java
│ │ │ │ ├── SPUtils.java
│ │ │ │ ├── StringUtils.java
│ │ │ │ ├── ToastUtils.java
│ │ │ │ ├── Utils.java
│ │ │ │ ├── compression/
│ │ │ │ │ ├── Luban.java
│ │ │ │ │ ├── OnCompressListener.java
│ │ │ │ │ └── Preconditions.java
│ │ │ │ └── constant/
│ │ │ │ ├── MemoryConstants.java
│ │ │ │ ├── RegexConstants.java
│ │ │ │ └── TimeConstants.java
│ │ │ └── widget/
│ │ │ └── ControlDistributeLinearLayout.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── activity_container.xml
│ │ │ └── customactivityoncrash_default_error_activity.xml
│ │ └── values/
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ └── strings.xml
│ └── test/
│ └── java/
│ └── me/
│ └── goldze/
│ └── mvvmhabit/
│ └── ExampleUnitTest.java
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .gitignore
================================================
*.iml
.gradle
key.jks
/local.properties
/.idea/workspace.xml
/.idea/libraries
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
/app/release
/mvvmhabit/bintray.gradle
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 goldze(曾宪泽)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
## 最新日志
**v4.0.0:2021年07月16日**
- 迁移AndroidX分支作为主线分支;
- 升级第三方框架依赖版本;
- 升级gradle插件版本支持;
- 优化框架代码,解决已知Bug;
- 修改文档说明。
#### [更多日志](./UpdateLog.md)
***
**注:**
[3.x:Support版(最后版本:3.1.6)](https://github.com/goldze/MVVMHabit/tree/20210716_v3.1.6_android)
[4.x:AndroidX版(最后版本:4.0.0)](https://github.com/goldze/MVVMHabit) 建议使用当前版本
> **原文地址:** [https://github.com/goldze/MVVMHabit](https://github.com/goldze/MVVMHabit)
②群 <a target="_blank" href="https://jq.qq.com/?_wv=1027&k=V3luKUW7"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="MVVMHabit-Family2" title="MVVMHabit-Family2"></a>
①群 <a target="_blank" href="https://jq.qq.com/?_wv=1027&k=Fv9et98F"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="MVVMHabit-Family" title="MVVMHabit-Family"></a>(已满)
# MVVMHabit
##
目前,android流行的MVC、MVP模式的开发框架很多,然而一款基于MVVM模式开发框架却很少。**MVVMHabit是以谷歌DataBinding+LiveData+ViewModel框架为基础,整合Okhttp+RxJava+Retrofit+Glide等流行模块,加上各种原生控件自定义的BindingAdapter,让事件与数据源完美绑定的一款容易上瘾的实用性MVVM快速开发框架**。从此告别findViewById(),告别setText(),告别setOnClickListener()...
## 框架流程

## 框架特点
- **快速开发**
只需要写项目的业务逻辑,不用再去关心网络请求、权限申请、View的生命周期等问题,撸起袖子就是干。
- **维护方便**
MVVM开发模式,低耦合,逻辑分明。Model层负责将请求的数据交给ViewModel;ViewModel层负责将请求到的数据做业务逻辑处理,最后交给View层去展示,与View一一对应;View层只负责界面绘制刷新,不处理业务逻辑,非常适合分配独立模块开发。
- **流行框架**
[retrofit](https://github.com/square/retrofit)+[okhttp](https://github.com/square/okhttp)+[rxJava](https://github.com/ReactiveX/RxJava)负责网络请求;[gson](https://github.com/google/gson)负责解析json数据;[glide](https://github.com/bumptech/glide)负责加载图片;[rxlifecycle](https://github.com/trello/RxLifecycle)负责管理view的生命周期;与网络请求共存亡;[rxbinding](https://github.com/JakeWharton/RxBinding)结合databinding扩展UI事件;[rxpermissions](https://github.com/tbruyelle/RxPermissions)负责Android 6.0权限申请;[material-dialogs](https://github.com/afollestad/material-dialogs)一个漂亮的、流畅的、可定制的material design风格的对话框。
- **数据绑定**
满足google目前控件支持的databinding双向绑定,并扩展原控件一些不支持的数据绑定。例如将图片的url路径绑定到ImageView控件中,在BindingAdapter方法里面则使用Glide加载图片;View的OnClick事件在BindingAdapter中方法使用RxView防重复点击,再把事件回调到ViewModel层,实现xml与ViewModel之间数据和事件的绑定(框架里面部分扩展控件和回调命令使用的是@kelin原创的)。
- **基类封装**
专门针对MVVM模式打造的BaseActivity、BaseFragment、BaseViewModel,在View层中不再需要定义ViewDataBinding和ViewModel,直接在BaseActivity、BaseFragment上限定泛型即可使用。普通界面只需要编写Fragment,然后使用ContainerActivity盛装(代理),这样就不需要每个界面都在AndroidManifest中注册一遍。
- **全局操作**
1. 全局的Activity堆栈式管理,在程序任何地方可以打开、结束指定的Activity,一键退出应用程序。
2. LoggingInterceptor全局拦截网络请求日志,打印Request和Response,格式化json、xml数据显示,方便与后台调试接口。
3. 全局Cookie,支持SharedPreferences和内存两种管理模式。
4. 通用的网络请求异常监听,根据不同的状态码或异常设置相应的message。
5. 全局的异常捕获,程序发生异常时不会崩溃,可跳入异常界面重启应用。
6. 全局事件回调,提供RxBus、Messenger两种回调方式。
7. 全局任意位置一行代码实现文件下载进度监听(暂不支持多文件进度监听)。
8. 全局点击事件防抖动处理,防止点击过快。
## 1、准备工作
> 网上的很多有关MVVM的资料,在此就不再阐述什么是MVVM了,不清楚的朋友可以先去了解一下。[todo-mvvm-live](https://github.com/googlesamples/android-architecture/tree/todo-mvvm-live)
### 1.1、启用databinding
在主工程app的build.gradle的android {}中加入:
```gradle
dataBinding {
enabled true
}
```
### 1.2、依赖Library
从远程依赖:
在根目录的build.gradle中加入
```gradle
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
```
在主项目app的build.gradle中依赖
```gradle
dependencies {
...
implementation 'com.github.goldze:MVVMHabit:4.0.0'
}
```
或
下载例子程序,在主项目app的build.gradle中依赖例子程序中的**mvvmhabit**:
```gradle
dependencies {
...
implementation project(':mvvmhabit')
}
```
### 1.3、配置config.gradle
如果不是远程依赖,而是下载的例子程序,那么还需要将例子程序中的config.gradle放入你的主项目根目录中,然后在根目录build.gradle的第一行加入:
```gradle
apply from: "config.gradle"
```
**注意:** config.gradle中的
android = [] 是你的开发相关版本配置,可自行修改
support = [] 是你的support相关配置,可自行修改
dependencies = [] 是依赖第三方库的配置,可以加新库,但不要去修改原有第三方库的版本号,不然可能会编译不过
### 1.4、配置AndroidManifest
添加权限:
```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
配置Application:
继承**mvvmhabit**中的BaseApplication,或者调用
```java
BaseApplication.setApplication(this);
```
来初始化你的Application
可以在你的自己AppApplication中配置
```java
//是否开启日志打印
KLog.init(true);
//配置全局异常崩溃操作
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SILENT) //背景模式,开启沉浸式
.enabled(true) //是否启动全局异常捕获
.showErrorDetails(true) //是否显示错误详细信息
.showRestartButton(true) //是否显示重启按钮
.trackActivities(true) //是否跟踪Activity
.minTimeBetweenCrashesMs(2000) //崩溃的间隔时间(毫秒)
.errorDrawable(R.mipmap.ic_launcher) //错误图标
.restartActivity(LoginActivity.class) //重新启动后的activity
//.errorActivity(YourCustomErrorActivity.class) //崩溃后的错误activity
//.eventListener(new YourCustomEventListener()) //崩溃后的错误监听
.apply();
```
## 2、快速上手
### 2.1、第一个Activity
> 以大家都熟悉的登录操作为例:三个文件**LoginActivty.java**、**LoginViewModel.java**、**activity_login.xml**
##### 2.1.1、关联ViewModel
在activity_login.xml中关联LoginViewModel。
```xml
<layout>
<data>
<variable
type="com.goldze.mvvmhabit.ui.login.LoginViewModel"
name="viewModel"
/>
</data>
.....
</layout>
```
> variable - type:类的全路径 <br>variable - name:变量名
##### 2.1.2、继承BaseActivity
LoginActivity继承BaseActivity
```java
public class LoginActivity extends BaseActivity<ActivityLoginBinding, LoginViewModel> {
//ActivityLoginBinding类是databinding框架自定生成的,对activity_login.xml
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_login;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public LoginViewModel initViewModel() {
//View持有ViewModel的引用,如果没有特殊业务处理,这个方法可以不重写
return ViewModelProviders.of(this).get(LoginViewModel.class);
}
}
```
> 保存activity_login.xml后databinding会生成一个ActivityLoginBinding类。(如果没有生成,试着点击Build->Clean Project)
BaseActivity是一个抽象类,有两个泛型参数,一个是ViewDataBinding,另一个是BaseViewModel,上面的ActivityLoginBinding则是继承的ViewDataBinding作为第一个泛型约束,LoginViewModel继承BaseViewModel作为第二个泛型约束。
重写BaseActivity的二个抽象方法
initContentView() 返回界面layout的id<br>
initVariableId() 返回变量的id,对应activity_login中name="viewModel",就像一个控件的id,可以使用R.id.xxx,这里的BR跟R文件一样,由系统生成,使用BR.xxx找到这个ViewModel的id。<br>
选择性重写initViewModel()方法,返回ViewModel对象
```java
@Override
public LoginViewModel initViewModel() {
//View持有ViewModel的引用,如果没有特殊业务处理,这个方法可以不重写
return ViewModelProviders.of(this).get(LoginViewModel.class);
}
```
**注意:** 不重写initViewModel(),默认会创建LoginActivity中第二个泛型约束的LoginViewModel,如果没有指定第二个泛型,则会创建BaseViewModel
##### 2.1.3、继承BaseViewModel
LoginViewModel继承BaseViewModel
```java
public class LoginViewModel extends BaseViewModel {
public LoginViewModel(@NonNull Application application) {
super(application);
}
....
}
```
BaseViewModel与BaseActivity通过LiveData来处理常用UI逻辑,即可在ViewModel中使用父类的showDialog()、startActivity()等方法。在这个LoginViewModel中就可以尽情的写你的逻辑了!
> BaseFragment的使用和BaseActivity一样,详情参考Demo。
### 2.2、数据绑定
> 拥有databinding框架自带的双向绑定,也有扩展
##### 2.2.1、传统绑定
绑定用户名:
在LoginViewModel中定义
```java
//用户名的绑定
public ObservableField<String> userName = new ObservableField<>("");
```
在用户名EditText标签中绑定
```xml
android:text="@={viewModel.userName}"
```
这样一来,输入框中输入了什么,userName.get()的内容就是什么,userName.set("")设置什么,输入框中就显示什么。
**注意:** @符号后面需要加=号才能达到双向绑定效果;userName需要是public的,不然viewModel无法找到它。
点击事件绑定:
在LoginViewModel中定义
```java
//登录按钮的点击事件
public View.OnClickListener loginOnClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
}
};
```
在登录按钮标签中绑定
```xml
android:onClick="@{viewModel.loginOnClick}"
```
这样一来,用户的点击事件直接被回调到ViewModel层了,更好的维护了业务逻辑
这就是强大的databinding框架双向绑定的特性,不用再给控件定义id,setText(),setOnClickListener()。
**但是,光有这些,完全满足不了我们复杂业务的需求啊!MVVMHabit闪亮登场:它有一套自定义的绑定规则,可以满足大部分的场景需求,请继续往下看。**
##### 2.2.2、自定义绑定
还拿点击事件说吧,不用传统的绑定方式,使用自定义的点击事件绑定。
在LoginViewModel中定义
```java
//登录按钮的点击事件
public BindingCommand loginOnClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
}
});
```
在activity_login中定义命名空间
```xml
xmlns:binding="http://schemas.android.com/apk/res-auto"
```
在登录按钮标签中绑定
```xml
binding:onClickCommand="@{viewModel.loginOnClickCommand}"
```
这和原本传统的绑定不是一样吗?不,这其实是有差别的。使用这种形式的绑定,在原本事件绑定的基础之上,带有防重复点击的功能,1秒内多次点击也只会执行一次操作。如果不需要防重复点击,可以加入这条属性
```xml
binding:isThrottleFirst="@{Boolean.TRUE}"
```
那这功能是在哪里做的呢?答案在下面的代码中。
```java
//防重复点击间隔(秒)
public static final int CLICK_INTERVAL = 1;
/**
* requireAll 是意思是是否需要绑定全部参数, false为否
* View的onClick事件绑定
* onClickCommand 绑定的命令,
* isThrottleFirst 是否开启防止过快点击
*/
@BindingAdapter(value = {"onClickCommand", "isThrottleFirst"}, requireAll = false)
public static void onClickCommand(View view, final BindingCommand clickCommand, final boolean isThrottleFirst) {
if (isThrottleFirst) {
RxView.clicks(view)
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object object) throws Exception {
if (clickCommand != null) {
clickCommand.execute();
}
}
});
} else {
RxView.clicks(view)
.throttleFirst(CLICK_INTERVAL, TimeUnit.SECONDS)//1秒钟内只允许点击1次
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object object) throws Exception {
if (clickCommand != null) {
clickCommand.execute();
}
}
});
}
}
```
onClickCommand方法是自定义的,使用@BindingAdapter注解来标明这是一个绑定方法。在方法中使用了RxView来增强view的clicks事件,.throttleFirst()限制订阅者在指定的时间内重复执行,最后通过BindingCommand将事件回调出去,就好比有一种拦截器,在点击时先做一下判断,然后再把事件沿着他原有的方向传递。
是不是觉得有点意思,好戏还在后头呢!
##### 2.2.3、自定义ImageView图片加载
绑定图片路径:
在ViewModel中定义
```java
public String imgUrl = "http://img0.imgtn.bdimg.com/it/u=2183314203,562241301&fm=26&gp=0.jpg";
```
在ImageView标签中
```xml
binding:url="@{viewModel.imgUrl}"
```
url是图片路径,这样绑定后,这个ImageView就会去显示这张图片,不限网络图片还是本地图片。
如果需要给一个默认加载中的图片,可以加这一句
```xml
binding:placeholderRes="@{R.mipmap.ic_launcher_round}"
```
> R文件需要在data标签中导入使用,如:`<import type="com.goldze.mvvmhabit.R" />`
BindingAdapter中的实现
```java
@BindingAdapter(value = {"url", "placeholderRes"}, requireAll = false)
public static void setImageUri(ImageView imageView, String url, int placeholderRes) {
if (!TextUtils.isEmpty(url)) {
//使用Glide框架加载图片
Glide.with(imageView.getContext())
.load(url)
.placeholder(placeholderRes)
.into(imageView);
}
}
```
很简单就自定义了一个ImageView图片加载的绑定,学会这种方式,可自定义扩展。
> 如果你对这些感兴趣,可以下载源码,在binding包中可以看到各类控件的绑定实现方式
##### 2.2.4、RecyclerView绑定
> RecyclerView也是很常用的一种控件,传统的方式需要针对各种业务要写各种Adapter,如果你使用了mvvmhabit,则可大大简化这种工作量,从此告别setAdapter()。
在ViewModel中定义:
```java
//给RecyclerView添加items
public final ObservableList<NetWorkItemViewModel> observableList = new ObservableArrayList<>();
//给RecyclerView添加ItemBinding
public final ItemBinding<NetWorkItemViewModel> itemBinding = ItemBinding.of(BR.viewModel, R.layout.item_network);
```
ObservableList<>和ItemBinding<>的泛型是Item布局所对应的ItemViewModel
在xml中绑定
```xml
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
binding:itemBinding="@{viewModel.itemBinding}"
binding:items="@{viewModel.observableList}"
binding:layoutManager="@{LayoutManagers.linear()}"
binding:lineManager="@{LineManagers.horizontal()}" />
```
layoutManager控制是线性(包含水平和垂直)排列还是网格排列,lineManager是设置分割线
网格布局的写法:`binding:layoutManager="@{LayoutManagers.grid(3)}`</br>
水平布局的写法:`binding:layoutManager="@{LayoutManagers.linear(LinearLayoutManager.HORIZONTAL,Boolean.FALSE)}"`</br>
使用到相关类,则需要导入该类才能使用,和导入Java类相似
> `<import type="me.tatarka.bindingcollectionadapter2.LayoutManagers" />`</br>
> `<import type="me.goldze.mvvmhabit.binding.viewadapter.recyclerview.LineManagers" />`</br>
> `<import type="android.support.v7.widget.LinearLayoutManager" />`
这样绑定后,在ViewModel中调用ObservableList的add()方法,添加一个ItemViewModel,界面上就会实时绘制出一个Item。在Item对应的ViewModel中,同样可以以绑定的形式完成逻辑
> 可以在请求到数据后,循环添加`observableList.add(new NetWorkItemViewModel(NetWorkViewModel.this, entity));`详细可以参考例子程序中NetWorkViewModel类。
**注意:** 在以前的版本中,ItemViewModel是继承BaseViewModel,传入Context,新版本3.x中可继承ItemViewModel,传入当前页面的ViewModel
更多RecyclerView、ListView、ViewPager等绑定方式,请参考 [https://github.com/evant/binding-collection-adapter](https://github.com/evant/binding-collection-adapter)
### 2.3、网络请求
> 网络请求一直都是一个项目的核心,现在的项目基本都离不开网络,一个好用网络请求框架可以让开发事半功倍。
#### 2.3.1、Retrofit+Okhttp+RxJava
> 现今,这三个组合基本是网络请求的标配,如果你对这三个框架不了解,建议先去查阅相关资料。
square出品的框架,用起来确实非常方便。**MVVMHabit**中引入了
```gradle
api "com.squareup.okhttp3:okhttp:3.10.0"
api "com.squareup.retrofit2:retrofit:2.4.0"
api "com.squareup.retrofit2:converter-gson:2.4.0"
api "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
```
构建Retrofit时加入
```java
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
```
或者直接使用例子程序中封装好的RetrofitClient
#### 2.3.2、网络拦截器
**LoggingInterceptor:** 全局拦截请求信息,格式化打印Request、Response,可以清晰的看到与后台接口对接的数据,
```java
LoggingInterceptor mLoggingInterceptor = new LoggingInterceptor
.Builder()//构建者模式
.loggable(true) //是否开启日志打印
.setLevel(Level.BODY) //打印的等级
.log(Platform.INFO) // 打印类型
.request("Request") // request的Tag
.response("Response")// Response的Tag
.addHeader("version", BuildConfig.VERSION_NAME)//打印版本
.build()
```
构建okhttp时加入
```java
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(mLoggingInterceptor)
.build();
```
**CacheInterceptor:** 缓存拦截器,当没有网络连接的时候自动读取缓存中的数据,缓存存放时间默认为3天。</br>
创建缓存对象
```java
//缓存时间
int CACHE_TIMEOUT = 10 * 1024 * 1024
//缓存存放的文件
File httpCacheDirectory = new File(mContext.getCacheDir(), "goldze_cache");
//缓存对象
Cache cache = new Cache(httpCacheDirectory, CACHE_TIMEOUT);
```
构建okhttp时加入
```java
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(new CacheInterceptor(mContext))
.build();
```
#### 2.3.3、Cookie管理
**MVVMHabit**提供两种CookieStore:**PersistentCookieStore** (SharedPreferences管理)和**MemoryCookieStore** (内存管理),可以根据自己的业务需求,在构建okhttp时加入相应的cookieJar
```java
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new PersistentCookieStore(mContext)))
.build();
```
或者
```java
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new MemoryCookieStore()))
.build();
```
#### 2.3.4、绑定生命周期
请求在ViewModel层。默认在BaseActivity中注入了LifecycleProvider对象到ViewModel,用于绑定请求的生命周期,View与请求共存亡。
```java
RetrofitClient.getInstance().create(DemoApiService.class)
.demoGet()
.compose(RxUtils.bindToLifecycle(getLifecycleProvider())) // 请求与View周期同步
.compose(RxUtils.schedulersTransformer()) // 线程调度
.compose(RxUtils.exceptionTransformer()) // 网络错误的异常转换
.subscribe(new Consumer<BaseResponse<DemoEntity>>() {
@Override
public void accept(BaseResponse<DemoEntity> response) throws Exception {
}
}, new Consumer<ResponseThrowable>() {
@Override
public void accept(ResponseThrowable throwable) throws Exception {
}
});
```
在请求时关键需要加入组合操作符`.compose(RxUtils.bindToLifecycle(getLifecycleProvider()))`<br>
**注意:** 由于BaseActivity/BaseFragment都实现了LifecycleProvider接口,并且默认注入到ViewModel中,所以在调用请求方法时可以直接调用getLifecycleProvider()拿到生命周期接口。如果你没有使用 **mvvmabit** 里面的BaseActivity或BaseFragment,使用自己定义的Base,那么需要让你自己的Activity继承RxAppCompatActivity、Fragment继承RxFragment才能用`RxUtils.bindToLifecycle(lifecycle)`方法。
#### 2.3.5、网络异常处理
网络异常在网络请求中非常常见,比如请求超时、解析错误、资源不存在、服务器内部错误等,在客户端则需要做相应的处理(当然,你可以把一部分异常甩锅给网络,比如当出现code 500时,提示:请求超时,请检查网络连接,此时偷偷将异常信息发送至后台(手动滑稽))。<br>
在使用Retrofit请求时,加入组合操作符`.compose(RxUtils.exceptionTransformer())`,当发生网络异常时,回调onError(ResponseThrowable)方法,可以拿到异常的code和message,做相应处理。<br>
> mvvmhabit中自定义了一个[ExceptionHandle](./mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ExceptionHandle.java),已为你完成了大部分网络异常的判断,也可自行根据项目的具体需求调整逻辑。<br>
**注意:** 这里的网络异常code,并非是与服务端协议约定的code。网络异常可以分为两部分,一部分是协议异常,即出现code = 404、500等,属于HttpException,另一部分为请求异常,即出现:连接超时、解析错误、证书验证失等。而与服务端约定的code规则,它不属于网络异常,它是属于一种业务异常。在请求中可以使用RxJava的filter(过滤器),也可以自定义BaseSubscriber统一处理网络请求的业务逻辑异常。由于每个公司的业务协议不一样,所以具体需要你自己来处理该类异常。
## 3、辅助功能
> 一个完整的快速开发框架,当然也少不了常用的辅助类。下面来介绍一下**MVVMabit**中有哪些辅助功能。
### 3.1、事件总线
> 事件总线存在的优点想必大家都很清楚了,android自带的广播机制对于组件间的通信而言,使用非常繁琐,通信组件彼此之间的订阅和发布的耦合也比较严重,特别是对于事件的定义,广播机制局限于序列化的类(通过Intent传递),不够灵活。
#### 3.3.1、RxBus
RxBus并不是一个库,而是一种模式。相信大多数开发者都使用过EventBus,对RxBus也是很熟悉。由于**MVVMabit**中已经加入RxJava,所以采用了RxBus代替EventBus作为事件总线通信,以减少库的依赖。
使用方法:
在ViewModel中重写registerRxBus()方法来注册RxBus,重写removeRxBus()方法来移除RxBus
```java
//订阅者
private Disposable mSubscription;
//注册RxBus
@Override
public void registerRxBus() {
super.registerRxBus();
mSubscription = RxBus.getDefault().toObservable(String.class)
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
}
});
//将订阅者加入管理站
RxSubscriptions.add(mSubscription);
}
//移除RxBus
@Override
public void removeRxBus() {
super.removeRxBus();
//将订阅者从管理站中移除
RxSubscriptions.remove(mSubscription);
}
```
在需要执行回调的地方发送
```java
RxBus.getDefault().post(object);
```
#### 3.3.2、Messenger
Messenger是一个轻量级全局的消息通信工具,在我们的复杂业务中,难免会出现一些交叉的业务,比如ViewModel与ViewModel之间需要有数据交换,这时候可以轻松地使用Messenger发送一个实体或一个空消息,将事件从一个ViewModel回调到另一个ViewModel中。
使用方法:
定义一个静态String类型的字符串token
```java
public static final String TOKEN_LOGINVIEWMODEL_REFRESH = "token_loginviewmodel_refresh";
```
在ViewModel中注册消息监听
```java
//注册一个空消息监听
//参数1:接受人(上下文)
//参数2:定义的token
//参数3:执行的回调监听
Messenger.getDefault().register(this, LoginViewModel.TOKEN_LOGINVIEWMODEL_REFRESH, new BindingAction() {
@Override
public void call() {
}
});
//注册一个带数据回调的消息监听
//参数1:接受人(上下文)
//参数2:定义的token
//参数3:实体的泛型约束
//参数4:执行的回调监听
Messenger.getDefault().register(this, LoginViewModel.TOKEN_LOGINVIEWMODEL_REFRESH, String.class, new BindingConsumer<String>() {
@Override
public void call(String s) {
}
});
```
在需要回调的地方使用token发送消息
```java
//发送一个空消息
//参数1:定义的token
Messenger.getDefault().sendNoMsg(LoginViewModel.TOKEN_LOGINVIEWMODEL_REFRESH);
//发送一个带数据回调消息
//参数1:回调的实体
//参数2:定义的token
Messenger.getDefault().send("refresh",LoginViewModel.TOKEN_LOGINVIEWMODEL_REFRESH);
```
> token最好不要重名,不然可能就会出现逻辑上的bug,为了更好的维护和清晰逻辑,建议以`aa_bb_cc`的格式来定义token。aa:TOKEN,bb:ViewModel的类名,cc:动作名(功能名)。
> 为了避免大量使用Messenger,建议只在ViewModel与ViewModel之间使用,View与ViewModel之间采用ObservableField去监听UI上的逻辑,可在继承了Base的Activity或Fragment中重写initViewObservable()方法来初始化UI的监听
注册了监听,当然也要解除它。在BaseActivity、BaseFragment的onDestroy()方法里已经调用`Messenger.getDefault().unregister(viewModel);`解除注册,所以不用担心忘记解除导致的逻辑错误和内存泄漏。
### 3.2、文件下载
文件下载几乎是每个app必备的功能,图文的下载,软件的升级等都要用到,mvvmhabit使用Retrofit+Okhttp+RxJava+RxBus实现一行代码监听带进度的文件下载。
下载文件
```java
String loadUrl = "你的文件下载路径";
String destFileDir = context.getCacheDir().getPath(); //文件存放的路径
String destFileName = System.currentTimeMillis() + ".apk";//文件存放的名称
DownLoadManager.getInstance().load(loadUrl, new ProgressCallBack<ResponseBody>(destFileDir, destFileName) {
@Override
public void onStart() {
//RxJava的onStart()
}
@Override
public void onCompleted() {
//RxJava的onCompleted()
}
@Override
public void onSuccess(ResponseBody responseBody) {
//下载成功的回调
}
@Override
public void progress(final long progress, final long total) {
//下载中的回调 progress:当前进度 ,total:文件总大小
}
@Override
public void onError(Throwable e) {
//下载错误回调
}
});
```
> 在ProgressResponseBody中使用了RxBus,发送下载进度信息到ProgressCallBack中,继承ProgressCallBack就可以监听到下载状态。回调方法全部执行在主线程,方便UI的更新,详情请参考例子程序。
### 3.3、ContainerActivity
一个盛装Fragment的一个容器(代理)Activity,普通界面只需要编写Fragment,使用此Activity盛装,这样就不需要每个界面都在AndroidManifest中注册一遍
使用方法:
在ViewModel中调用BaseViewModel的方法开一个Fragment
```java
startContainerActivity(你的Fragment类名.class.getCanonicalName())
```
在ViewModel中调用BaseViewModel的方法,携带一个序列化实体打开一个Fragment
```java
Bundle mBundle = new Bundle();
mBundle.putParcelable("entity", entity);
startContainerActivity(你的Fragment类名.class.getCanonicalName(), mBundle);
```
在你的Fragment中取出实体
```java
Bundle mBundle = getArguments();
if (mBundle != null) {
entity = mBundle.getParcelable("entity");
}
```
### 3.4、6.0权限申请
> 对RxPermissions已经熟悉的朋友可以跳过。
使用方法:
例如请求相机权限,在ViewModel中调用
```java
//请求打开相机权限
RxPermissions rxPermissions = new RxPermissions((Activity) context);
rxPermissions.request(Manifest.permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean) {
ToastUtils.showShort("权限已经打开,直接跳入相机");
} else {
ToastUtils.showShort("权限被拒绝");
}
}
});
```
更多权限申请方式请参考[RxPermissions原项目地址](https://github.com/tbruyelle/RxPermissions)
### 3.5、图片压缩
> 为了节约用户流量和加快图片上传的速度,某些场景将图片在本地压缩后再传给后台,所以特此提供一个图片压缩的辅助功能。
使用方法:
RxJava的方式压缩单张图片,得到一个压缩后的图片文件对象
```java
String filePath = "mnt/sdcard/1.png";
ImageUtils.compressWithRx(filePath, new Consumer<File>() {
@Override
public void accept(File file) throws Exception {
//将文件放入RequestBody
...
}
});
```
RxJava的方式压缩多张图片,按集合顺序每压缩成功一张,都将在onNext方法中得到一个压缩后的图片文件对象
```java
List<String> filePaths = new ArrayList<>();
filePaths.add("mnt/sdcard/1.png");
filePaths.add("mnt/sdcard/2.png");
ImageUtils.compressWithRx(filePaths, new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(File file) {
}
});
```
### 3.6、其他辅助类
**ToastUtils:** 吐司工具类
**MaterialDialogUtils:** Material风格对话框工具类
**SPUtils:** SharedPreferences工具类
**SDCardUtils:** SD卡相关工具类
**ConvertUtils:** 转换相关工具类
**StringUtils:** 字符串相关工具类
**RegexUtils:** 正则相关工具类
**KLog:** 日志打印,含json格式打印
## 4、附加
### 4.1、编译错误解决方法
> 使用databinding其实有个缺点,就是会遇到一些编译错误,而AS不能很好的定位到错误的位置,这对于刚开始使用databinding的开发者来说是一个比较郁闷的事。那么我在此把我自己在开发中遇到的各种编译问题的解决方法分享给大家,希望这对你会有所帮助。
##### 4.1.1、绑定错误
绑定错误是一个很常见的错误,基本都会犯。比如TextView的 `android:text=""` ,本来要绑定的是一个String类型,结果你不小心,可能绑了一个Boolean上去,或者变量名写错了,这时候编辑器不会报红错,而是在点编译运行的时候,在AS的Messages中会出现错误提示,如下图:
<img src="./img/error1.png" width="640" hegiht="640" align=center />
解决方法:把错误提示拉到最下面 (上面的提示找不到BR类这个不要管它),看最后一个错误 ,这里会提示是哪个xml出了错,并且会定位到行数,按照提示找到对应位置,即可解决该编译错误的问题。
**注意:** 行数要+1,意思是上面报出第33行错误,实际是第34行错误,AS定位的不准确 (这可能是它的一个bug)
##### 4.1.2、xml导包错误
在xml中需要导入ViewModel或者一些业务相关的类,假如在xml中导错了类,那一行则会报红,但是res/layout却没有错误提示,有一种场景,非常特殊,不容易找出错误位置。就是你写了一个xml,导入了一个类,比如XXXUtils,后来因为业务需求,把那个XXXUtils删了,这时候res/layout下不会出现任何错误,而你在编译运行的时候,才会出现错误日志。苦逼的是,不会像上面那样提示哪一个xml文件,哪一行出错了,最后一个错误只是一大片的报错报告。如下图:
<img src="./img/error2.png" width="640" hegiht="640" align=center />
解决方法:同样找到最后一个错误提示,找到Cannot resolve type for **xxx**这一句 (xxx是类名),然后使用全局搜索 (Ctrl+H) ,搜索哪个xml引用了这个类,跟踪点击进去,在xml就会出现一个红错,看到错误你就会明白了,这样就可解决该编译错误的问题。
##### 4.1.3、build错误
构建多module工程时,如出现【4.1.1、绑定错误】,且你能确定这个绑定是没有问题的,经过修改后出现下图错误:
<img src="./img/error3.png" width="640" hegiht="640" align=center />
解决方法:
这种是databinding比较大的坑,清理、重构和删build都不起作用,网上很难找到方法。经过试验,解决办法是手动创建异常中提到的文件夹,或者拷贝上一个没有报错的版本中对应的文件夹,可以解决这个异常
##### 4.1.4、自动生成类错误
有时候在写完xml时,databinding没有自动生成对应的Binding类及属性。比如新建了一个activity_login.xml,按照databinding的写法加入```<layout> <variable>```后,理论上会自动对应生成ActivityLoginBinding.java类和variable的属性,可能是as对databding的支持还不够吧,有时候偏偏就不生成,导致BR.xxx报红等一些莫名的错误。
解决方法:其实确保自己的写法没有问题,是可以直接运行的,报红不一定是你写的有问题,也有可能是编译器抽风了。或者使用下面的办法</br>
第一招:Build->Clean Project;</br>第二招:Build->Rebuild Project;</br>第三招:重启大法。
##### 4.1.5、gradle错误
如果遇到以下编译问题:
错误: 无法将类 BindingRecyclerViewAdapters中的方法 setAdapter应用到给定类型;
需要: RecyclerView,ItemBinding,List,BindingRecyclerViewAdapter,ItemIds<? super T>,ViewHolderFactory
找到: RecyclerView,ItemBinding,ObservableList,BindingRecyclerViewAdapter<CAP#1>,ItemIds,ViewHolderFactory
原因: 推断类型不符合等式约束条件
推断: CAP#1
等式约束条件: CAP#1,NetWorkItemViewModel
其中, T是类型变量:
T扩展已在方法 setAdapter(RecyclerView,ItemBinding,List,BindingRecyclerViewAdapter,ItemIds<? super T>,ViewHolderFactory)中声明的Object
其中, CAP#1是新类型变量:
CAP#1从?的捕获扩展Object
一般是由于gradle plugin版本3.5.1造成的,请换成gradle plugin 3.5.0以下版本
## 混淆
例子程序中给出了最新的【MVVMHabit混淆规则】,包含MVVMHabit中依赖的所有第三方library,可以将规则直接拷贝到自己app的混淆规则中。在此基础上你只需要关注自己业务代码以及自己引入第三方的混淆,【MVVMHabit混淆规则】请参考app目录下的[proguard-rules.pro](./app/proguard-rules.pro)文件。
## 组件化
进阶Android组件化方案,请移步:[MVVMHabitComponent](https://github.com/goldze/MVVMHabitComponent)
## About
**goldze:** 本人喜欢尝试新的技术,以后发现有好用的东西,我将会在企业项目中实战,没有问题了就会把它引入到**MVVMHabit**中,一直维护着这套框架,谢谢各位朋友的支持。如果觉得这套框架不错的话,麻烦点个 **star**,你的支持则是我前进的动力!
**QQ群**:84692105
## Thank
感谢[【zhangxiaoxiao】](https://github.com/zhanghacker)小伙伴长期提供的技术支持与帮助,为项目开源做出了很多的贡献。
## License
Copyright 2017 goldze(曾宪泽)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: UpdateLog.md
================================================
## 更新日志
**v4.0.0:2021年07月16日**
- 迁移AndroidX分支作为主线分支;
- 升级第三方框架依赖版本;
- 升级gradle插件版本支持;
- 优化框架代码,解决已知Bug;
- 修改文档说明。
***
**v3.0.7:2019年1月25日**
- 优化框架代码,解决已知Bug;
- 新增ViewPager+Fragment例子;
- 新增RecycleView多布局例子;
- 升级第三方依赖库;
- 修改文档说明。
***
**v3.0.0:2018年10月8日**
- 全面升级AAC,引入谷歌lifecycle组件;
- 修改Base基类,满足新一套模式;
- 升级第三方依赖库;
- 修改例子程序;
- 修改文档说明。
***
**v2.0.6:2018年7月19日**
- 优化框架性能、基类逻辑,新增绑定命令;
- 补充例子程序及注释;
- 升级/修改第三方依赖库;
- 补充文档说明。
***
**v2.0.0:2018年4月10日**
- 全面升级RxJava2;
- 优化绑定回调方式;
- 升级第三方依赖库;
- 微调例子程序。
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
defaultConfig {
applicationId rootProject.ext.android.applicationId
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled true
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
//support
implementation rootProject.ext.support["design"]
//下拉刷新,上拉加载
implementation 'com.lcodecorex:tkrefreshlayout:1.0.7'
//底部tabBar
implementation('me.majiajie:pager-bottom-tab-strip:2.2.5') {
exclude group: 'com.android.support'
}
//MVVMHabit
implementation project(':mvvmhabit')
// implementation rootProject.ext.dependencies.MVVMHabit
//内存泄漏测试
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#------------------------------------------主项目混淆规则----------------------------------------------
#实体类不参与混淆
-keep class com.goldze.mvvmhabit.entity.** { *; }
#tkrefreshlayout
-keep class com.lcodecore.tkrefreshlayout.** { *; }
-dontwarn com.lcodecore.tkrefreshlayout.**
#-------------------------------------------MVVMHabit混淆规则----------------------------------------------
#---------------------------------1.实体类---------------------------------
-keep class me.goldze.mvvmhabit.http.BaseResponse { *; }
#-------------------------------------------------------------------------
#--------------------------------2.第三方包-------------------------------
#support
-keep class android.support.** { *; }
-keep interface android.support.** { *; }
-dontwarn android.support.**
#databinding
-keep class android.databinding.** { *; }
-dontwarn android.databinding.**
#annotation
-keep class android.support.annotation.** { *; }
-keep interface android.support.annotation.** { *; }
#retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
#gson
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.sunloto.shandong.bean.** { *; }
#glide
-keep public class * implements com.bumptech.glide.module.AppGlideModule
-keep public class * implements com.bumptech.glide.module.LibraryGlideModule
-keep class com.bumptech.glide.** { *; }
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
#glide-transformations
-keep class jp.wasabeef.glide.transformations.** {*;}
-dontwarn jp.wasabeef.glide.transformations.**
#okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn com.squareup.okhttp.**
-dontwarn okhttp3.**
-dontwarn okio.**
#RxJava RxAndroid
-dontwarn rx.*
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
#RxLifecycle
-keep class com.trello.rxlifecycle2.** { *; }
-keep interface com.trello.rxlifecycle2.** { *; }
-dontwarn com.trello.rxlifecycle2.**
#RxPermissions
-keep class com.tbruyelle.rxpermissions2.** { *; }
-keep interface com.tbruyelle.rxpermissions2.** { *; }
#material-dialogs
-keep class com.afollestad.materialdialogs.** { *; }
-dontwarn om.afollestad.materialdialogs.**
#=====================bindingcollectionadapter=====================
-keep class me.tatarka.bindingcollectionadapter.** { *; }
-dontwarn me.tatarka.bindingcollectionadapter.**
#---------------------------------------------------------------------------
#---------------------------------3.与js互相调用的类------------------------
#无
#----------------------------------------------------------------------------
#---------------------------------4.反射相关的类和方法-----------------------
-keep public class * extends me.goldze.mvvmhabit.base.BaseActivity{ *; }
-keep public class * extends me.goldze.mvvmhabit.base.BaseFragment{ *; }
-keep public class * extends me.goldze.mvvmhabit.binding.command.BindingCommand{ *; }
-keep public class * extends me.goldze.mvvmhabit.binding.command.ResponseCommand{ *; }
#----------------------------------------------------------------------------
#---------------------------------5.自定义控件------------------------------
-keep class me.goldze.mvvmhabit.widget.** { *; }
#----------------------------------------------------------------------------
#---------------------------------6.其他定制区-------------------------------
#native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
#保持类中的所有方法名
-keepclassmembers class * {
public <methods>;
private <methods>;
}
#----------------------------------------------------------------------------
#---------------------------------基本指令区---------------------------------
# 抑制警告
-ignorewarnings
#指定代码的压缩级别
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#混淆包路径
-repackageclasses ''
-flattenpackagehierarchy ''
#保护注解
-keepattributes *Annotation*
#避免混淆泛型 如果混淆报错建议关掉
-keepattributes Signature
#保留SourceFile和LineNumber属性
-keepattributes SourceFile,LineNumberTable
#忽略警告
#-ignorewarning
#----------记录生成的日志数据,gradle build时在本项目根目录输出---------
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
#----------------------------------------------------------------------------
#---------------------------------默认保留区---------------------------------
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keep class **.R$* {
*;
}
-keepclassmembers class * {
void *(**On*Event);
}
#----------------------------------------------------------------------------
#---------------------------------webview------------------------------------
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, jav.lang.String);
}
#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
================================================
FILE: app/src/androidTest/java/com/goldze/mvvmhabit/ExampleInstrumentedTest.java
================================================
package com.goldze.mvvmhabit;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.goldze.mvvmhabit", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.goldze.mvvmhabit">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".app.AppApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.login.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.main.DemoActivity"></activity>
<activity android:name=".ui.tab_bar.activity.TabBarActivity"></activity>
<activity android:name=".ui.viewpager.activity.ViewPagerActivity"></activity>
</application>
</manifest>
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/app/AppApplication.java
================================================
package com.goldze.mvvmhabit.app;
import com.goldze.mvvmhabit.BuildConfig;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.ui.login.LoginActivity;
import com.squareup.leakcanary.LeakCanary;
import me.goldze.mvvmhabit.base.BaseApplication;
import me.goldze.mvvmhabit.crash.CaocConfig;
import me.goldze.mvvmhabit.utils.KLog;
/**
* Created by goldze on 2017/7/16.
*/
public class AppApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
//是否开启打印日志
KLog.init(BuildConfig.DEBUG);
//初始化全局异常崩溃
initCrash();
//内存泄漏检测
if (!LeakCanary.isInAnalyzerProcess(this)) {
LeakCanary.install(this);
}
}
private void initCrash() {
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SILENT) //背景模式,开启沉浸式
.enabled(true) //是否启动全局异常捕获
.showErrorDetails(true) //是否显示错误详细信息
.showRestartButton(true) //是否显示重启按钮
.trackActivities(true) //是否跟踪Activity
.minTimeBetweenCrashesMs(2000) //崩溃的间隔时间(毫秒)
.errorDrawable(R.mipmap.ic_launcher) //错误图标
.restartActivity(LoginActivity.class) //重新启动后的activity
// .errorActivity(YourCustomErrorActivity.class) //崩溃后的错误activity
// .eventListener(new YourCustomEventListener()) //崩溃后的错误监听
.apply();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/app/AppViewModelFactory.java
================================================
package com.goldze.mvvmhabit.app;
import android.annotation.SuppressLint;
import android.app.Application;
import com.goldze.mvvmhabit.data.DemoRepository;
import com.goldze.mvvmhabit.ui.login.LoginViewModel;
import com.goldze.mvvmhabit.ui.network.NetWorkViewModel;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
/**
* Created by goldze on 2019/3/26.
*/
public class AppViewModelFactory extends ViewModelProvider.NewInstanceFactory {
@SuppressLint("StaticFieldLeak")
private static volatile AppViewModelFactory INSTANCE;
private final Application mApplication;
private final DemoRepository mRepository;
public static AppViewModelFactory getInstance(Application application) {
if (INSTANCE == null) {
synchronized (AppViewModelFactory.class) {
if (INSTANCE == null) {
INSTANCE = new AppViewModelFactory(application, Injection.provideDemoRepository());
}
}
}
return INSTANCE;
}
@VisibleForTesting
public static void destroyInstance() {
INSTANCE = null;
}
private AppViewModelFactory(Application application, DemoRepository repository) {
this.mApplication = application;
this.mRepository = repository;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(NetWorkViewModel.class)) {
return (T) new NetWorkViewModel(mApplication, mRepository);
} else if (modelClass.isAssignableFrom(LoginViewModel.class)) {
return (T) new LoginViewModel(mApplication, mRepository);
}
throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass.getName());
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/app/Injection.java
================================================
package com.goldze.mvvmhabit.app;
import com.goldze.mvvmhabit.data.DemoRepository;
import com.goldze.mvvmhabit.data.source.HttpDataSource;
import com.goldze.mvvmhabit.data.source.LocalDataSource;
import com.goldze.mvvmhabit.data.source.http.HttpDataSourceImpl;
import com.goldze.mvvmhabit.data.source.http.service.DemoApiService;
import com.goldze.mvvmhabit.data.source.local.LocalDataSourceImpl;
import com.goldze.mvvmhabit.utils.RetrofitClient;
/**
* 注入全局的数据仓库,可以考虑使用Dagger2。(根据项目实际情况搭建,千万不要为了架构而架构)
* Created by goldze on 2019/3/26.
*/
public class Injection {
public static DemoRepository provideDemoRepository() {
//网络API服务
DemoApiService apiService = RetrofitClient.getInstance().create(DemoApiService.class);
//网络数据源
HttpDataSource httpDataSource = HttpDataSourceImpl.getInstance(apiService);
//本地数据源
LocalDataSource localDataSource = LocalDataSourceImpl.getInstance();
//两条分支组成一个数据仓库
return DemoRepository.getInstance(httpDataSource, localDataSource);
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/binding/twinklingrefreshlayout/ViewAdapter.java
================================================
package com.goldze.mvvmhabit.binding.twinklingrefreshlayout;
import com.lcodecore.tkrefreshlayout.RefreshListenerAdapter;
import com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout;
import androidx.databinding.BindingAdapter;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
/**
* Created by goldze on 2017/6/16.
* TwinklingRefreshLayout列表刷新的绑定适配器
*/
public class ViewAdapter {
@BindingAdapter(value = {"onRefreshCommand", "onLoadMoreCommand"}, requireAll = false)
public static void onRefreshAndLoadMoreCommand(TwinklingRefreshLayout layout, final BindingCommand onRefreshCommand, final BindingCommand onLoadMoreCommand) {
layout.setOnRefreshListener(new RefreshListenerAdapter() {
@Override
public void onRefresh(TwinklingRefreshLayout refreshLayout) {
super.onRefresh(refreshLayout);
if (onRefreshCommand != null) {
onRefreshCommand.execute();
}
}
@Override
public void onLoadMore(TwinklingRefreshLayout refreshLayout) {
super.onLoadMore(refreshLayout);
if (onLoadMoreCommand != null) {
onLoadMoreCommand.execute();
}
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/DemoRepository.java
================================================
package com.goldze.mvvmhabit.data;
import com.goldze.mvvmhabit.data.source.HttpDataSource;
import com.goldze.mvvmhabit.data.source.LocalDataSource;
import com.goldze.mvvmhabit.entity.DemoEntity;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import io.reactivex.Observable;
import me.goldze.mvvmhabit.base.BaseModel;
import me.goldze.mvvmhabit.http.BaseResponse;
/**
* MVVM的Model层,统一模块的数据仓库,包含网络数据和本地数据(一个应用可以有多个Repositor)
* Created by goldze on 2019/3/26.
*/
public class DemoRepository extends BaseModel implements HttpDataSource, LocalDataSource {
private volatile static DemoRepository INSTANCE = null;
private final HttpDataSource mHttpDataSource;
private final LocalDataSource mLocalDataSource;
private DemoRepository(@NonNull HttpDataSource httpDataSource,
@NonNull LocalDataSource localDataSource) {
this.mHttpDataSource = httpDataSource;
this.mLocalDataSource = localDataSource;
}
public static DemoRepository getInstance(HttpDataSource httpDataSource,
LocalDataSource localDataSource) {
if (INSTANCE == null) {
synchronized (DemoRepository.class) {
if (INSTANCE == null) {
INSTANCE = new DemoRepository(httpDataSource, localDataSource);
}
}
}
return INSTANCE;
}
@VisibleForTesting
public static void destroyInstance() {
INSTANCE = null;
}
@Override
public Observable<Object> login() {
return mHttpDataSource.login();
}
@Override
public Observable<DemoEntity> loadMore() {
return mHttpDataSource.loadMore();
}
@Override
public Observable<BaseResponse<DemoEntity>> demoGet() {
return mHttpDataSource.demoGet();
}
@Override
public Observable<BaseResponse<DemoEntity>> demoPost(String catalog) {
return mHttpDataSource.demoPost(catalog);
}
@Override
public void saveUserName(String userName) {
mLocalDataSource.saveUserName(userName);
}
@Override
public void savePassword(String password) {
mLocalDataSource.savePassword(password);
}
@Override
public String getUserName() {
return mLocalDataSource.getUserName();
}
@Override
public String getPassword() {
return mLocalDataSource.getPassword();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/HttpDataSource.java
================================================
package com.goldze.mvvmhabit.data.source;
import com.goldze.mvvmhabit.entity.DemoEntity;
import io.reactivex.Observable;
import me.goldze.mvvmhabit.http.BaseResponse;
/**
* Created by goldze on 2019/3/26.
*/
public interface HttpDataSource {
//模拟登录
Observable<Object> login();
//模拟上拉加载
Observable<DemoEntity> loadMore();
Observable<BaseResponse<DemoEntity>> demoGet();
Observable<BaseResponse<DemoEntity>> demoPost(String catalog);
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/LocalDataSource.java
================================================
package com.goldze.mvvmhabit.data.source;
/**
* Created by goldze on 2019/3/26.
*/
public interface LocalDataSource {
/**
* 保存用户名
*/
void saveUserName(String userName);
/**
* 保存用户密码
*/
void savePassword(String password);
/**
* 获取用户名
*/
String getUserName();
/**
* 获取用户密码
*/
String getPassword();
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/http/HttpDataSourceImpl.java
================================================
package com.goldze.mvvmhabit.data.source.http;
import com.goldze.mvvmhabit.data.source.HttpDataSource;
import com.goldze.mvvmhabit.data.source.http.service.DemoApiService;
import com.goldze.mvvmhabit.entity.DemoEntity;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import me.goldze.mvvmhabit.http.BaseResponse;
/**
* Created by goldze on 2019/3/26.
*/
public class HttpDataSourceImpl implements HttpDataSource {
private DemoApiService apiService;
private volatile static HttpDataSourceImpl INSTANCE = null;
public static HttpDataSourceImpl getInstance(DemoApiService apiService) {
if (INSTANCE == null) {
synchronized (HttpDataSourceImpl.class) {
if (INSTANCE == null) {
INSTANCE = new HttpDataSourceImpl(apiService);
}
}
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
private HttpDataSourceImpl(DemoApiService apiService) {
this.apiService = apiService;
}
@Override
public Observable<Object> login() {
return Observable.just(new Object()).delay(3, TimeUnit.SECONDS); //延迟3秒
}
@Override
public Observable<DemoEntity> loadMore() {
return Observable.create(new ObservableOnSubscribe<DemoEntity>() {
@Override
public void subscribe(ObservableEmitter<DemoEntity> observableEmitter) throws Exception {
DemoEntity entity = new DemoEntity();
List<DemoEntity.ItemsEntity> itemsEntities = new ArrayList<>();
//模拟一部分假数据
for (int i = 0; i < 10; i++) {
DemoEntity.ItemsEntity item = new DemoEntity.ItemsEntity();
item.setId(-1);
item.setName("模拟条目");
itemsEntities.add(item);
}
entity.setItems(itemsEntities);
observableEmitter.onNext(entity);
}
}).delay(3, TimeUnit.SECONDS); //延迟3秒
}
@Override
public Observable<BaseResponse<DemoEntity>> demoGet() {
return apiService.demoGet();
}
@Override
public Observable<BaseResponse<DemoEntity>> demoPost(String catalog) {
return apiService.demoPost(catalog);
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/http/service/DemoApiService.java
================================================
package com.goldze.mvvmhabit.data.source.http.service;
import com.goldze.mvvmhabit.entity.DemoEntity;
import io.reactivex.Observable;
import me.goldze.mvvmhabit.http.BaseResponse;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
/**
* Created by goldze on 2017/6/15.
*/
public interface DemoApiService {
@GET("action/apiv2/banner?catalog=1")
Observable<BaseResponse<DemoEntity>> demoGet();
@FormUrlEncoded
@POST("action/apiv2/banner")
Observable<BaseResponse<DemoEntity>> demoPost(@Field("catalog") String catalog);
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/local/LocalDataSourceImpl.java
================================================
package com.goldze.mvvmhabit.data.source.local;
import com.goldze.mvvmhabit.data.source.LocalDataSource;
import me.goldze.mvvmhabit.utils.SPUtils;
/**
* 本地数据源,可配合Room框架使用
* Created by goldze on 2019/3/26.
*/
public class LocalDataSourceImpl implements LocalDataSource {
private volatile static LocalDataSourceImpl INSTANCE = null;
public static LocalDataSourceImpl getInstance() {
if (INSTANCE == null) {
synchronized (LocalDataSourceImpl.class) {
if (INSTANCE == null) {
INSTANCE = new LocalDataSourceImpl();
}
}
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
private LocalDataSourceImpl() {
//数据库Helper构建
}
@Override
public void saveUserName(String userName) {
SPUtils.getInstance().put("UserName", userName);
}
@Override
public void savePassword(String password) {
SPUtils.getInstance().put("password", password);
}
@Override
public String getUserName() {
return SPUtils.getInstance().getString("UserName");
}
@Override
public String getPassword() {
return SPUtils.getInstance().getString("password");
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/DemoEntity.java
================================================
package com.goldze.mvvmhabit.entity;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.List;
/**
* Created by goldze on 2017/7/17.
*/
public class DemoEntity {
private String nextPageToken;
private String prevPageToken;
private int requestCount;
private int responseCount;
private int totalResults;
private List<ItemsEntity> items;
public String getNextPageToken() {
return nextPageToken;
}
public void setNextPageToken(String nextPageToken) {
this.nextPageToken = nextPageToken;
}
public String getPrevPageToken() {
return prevPageToken;
}
public void setPrevPageToken(String prevPageToken) {
this.prevPageToken = prevPageToken;
}
public int getRequestCount() {
return requestCount;
}
public void setRequestCount(int requestCount) {
this.requestCount = requestCount;
}
public int getResponseCount() {
return responseCount;
}
public void setResponseCount(int responseCount) {
this.responseCount = responseCount;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public List<ItemsEntity> getItems() {
return items;
}
public void setItems(List<ItemsEntity> items) {
this.items = items;
}
public static class ItemsEntity implements Parcelable{
private String detail;
private String href;
private int id;
private String img;
private String name;
private String pubDate;
private int type;
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPubDate() {
return pubDate;
}
public void setPubDate(String pubDate) {
this.pubDate = pubDate;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.detail);
dest.writeString(this.href);
dest.writeInt(this.id);
dest.writeString(this.img);
dest.writeString(this.name);
dest.writeString(this.pubDate);
dest.writeInt(this.type);
}
public ItemsEntity() {
}
protected ItemsEntity(Parcel in) {
this.detail = in.readString();
this.href = in.readString();
this.id = in.readInt();
this.img = in.readString();
this.name = in.readString();
this.pubDate = in.readString();
this.type = in.readInt();
}
public static final Creator<ItemsEntity> CREATOR = new Creator<ItemsEntity>() {
@Override
public ItemsEntity createFromParcel(Parcel source) {
return new ItemsEntity(source);
}
@Override
public ItemsEntity[] newArray(int size) {
return new ItemsEntity[size];
}
};
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/FormEntity.java
================================================
package com.goldze.mvvmhabit.entity;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.databinding.BaseObservable;
/**
* Created by goldze on 2017/7/17.
*/
public class FormEntity extends BaseObservable implements Parcelable {
private String id;
private String name;
private String sex;
private String Bir;
private String hobby;
private Boolean isMarry;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getBir() {
return Bir;
}
public void setBir(String bir) {
Bir = bir;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public FormEntity() {
}
public Boolean getMarry() {
return isMarry;
}
public void setMarry(Boolean marry) {
isMarry = marry;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.id);
dest.writeString(this.name);
dest.writeString(this.sex);
dest.writeString(this.Bir);
dest.writeString(this.hobby);
dest.writeValue(this.isMarry);
}
protected FormEntity(Parcel in) {
this.id = in.readString();
this.name = in.readString();
this.sex = in.readString();
this.Bir = in.readString();
this.hobby = in.readString();
this.isMarry = (Boolean) in.readValue(Boolean.class.getClassLoader());
}
public static final Creator<FormEntity> CREATOR = new Creator<FormEntity>() {
@Override
public FormEntity createFromParcel(Parcel source) {
return new FormEntity(source);
}
@Override
public FormEntity[] newArray(int size) {
return new FormEntity[size];
}
};
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/SpinnerItemData.java
================================================
package com.goldze.mvvmhabit.entity;
import me.goldze.mvvmhabit.binding.viewadapter.spinner.IKeyAndValue;
/**
* Created by goldze on 2017/7/17.
* Spinner条目数据实体
* 该实体类可以自定义,比如该类是数据库实体类. 或者是数据字典实体类, 但需要实现IKeyAndValue接口, 返回key和value两个值就可以在Spinner中绑定使用了
*/
public class SpinnerItemData implements IKeyAndValue {
//key是下拉显示的文字
private String key;
//value是对应需要上传给后台的值, 这个可以根据具体业务具体定义
private String value;
public SpinnerItemData(String key, String value) {
this.key = key;
this.value = value;
}
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return value;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/adapter/BaseFragmentPagerAdapter.java
================================================
package com.goldze.mvvmhabit.ui.base.adapter;
import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
/**
* Created by goldze on 2017/7/17.
* FragmentPager适配器
*/
public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> list;//ViewPager要填充的fragment列表
private List<String> title;//tab中的title文字列表
//使用构造方法来将数据传进去
public BaseFragmentPagerAdapter(FragmentManager fm, List<Fragment> list, List<String> title) {
super(fm);
this.list = list;
this.title = title;
}
@Override
public Fragment getItem(int position) {//获得position中的fragment来填充
return list.get(position);
}
@Override
public int getCount() {//返回FragmentPager的个数
return list.size();
}
//FragmentPager的标题,如果重写这个方法就显示不出tab的标题内容
@Override
public CharSequence getPageTitle(int position) {
return title.get(position);
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/fragment/BasePagerFragment.java
================================================
package com.goldze.mvvmhabit.ui.base.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.FragmentBasePagerBinding;
import com.goldze.mvvmhabit.ui.base.adapter.BaseFragmentPagerAdapter;
import com.google.android.material.tabs.TabLayout;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import me.goldze.mvvmhabit.base.BaseFragment;
import me.goldze.mvvmhabit.base.BaseViewModel;
/**
* Created by goldze on 2017/7/17.
* 抽取的二级BasePagerFragment
*/
public abstract class BasePagerFragment extends BaseFragment<FragmentBasePagerBinding, BaseViewModel> {
private List<Fragment> mFragments;
private List<String> titlePager;
protected abstract List<Fragment> pagerFragment();
protected abstract List<String> pagerTitleString();
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_base_pager;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
mFragments = pagerFragment();
titlePager = pagerTitleString();
//设置Adapter
BaseFragmentPagerAdapter pagerAdapter = new BaseFragmentPagerAdapter(getChildFragmentManager(), mFragments, titlePager);
binding.viewPager.setAdapter(pagerAdapter);
binding.tabs.setupWithViewPager(binding.viewPager);
binding.viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(binding.tabs));
}
@Override
public void initViewObservable() {
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/viewmodel/ToolbarViewModel.java
================================================
package com.goldze.mvvmhabit.ui.base.viewmodel;
import android.app.Application;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableField;
import androidx.databinding.ObservableInt;
import me.goldze.mvvmhabit.base.BaseModel;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
/**
* Create Author:goldze
* Create Date:2019/01/03
* Description: 对应include标题的ToolbarViewModel
* Toolbar的封装方式有很多种,具体封装需根据项目实际业务和习惯来编写
* 所有例子仅做参考,业务多种多样,可能我这里写的例子和你的需求不同,理解如何使用才最重要。
*/
public class ToolbarViewModel<M extends BaseModel> extends BaseViewModel<M> {
//标题文字
public ObservableField<String> titleText = new ObservableField<>("");
//右边文字
public ObservableField<String> rightText = new ObservableField<>("更多");
//右边文字的观察者
public ObservableInt rightTextVisibleObservable = new ObservableInt(View.GONE);
//右边图标的观察者
public ObservableInt rightIconVisibleObservable = new ObservableInt(View.GONE);
//兼容databinding,去泛型化
public ToolbarViewModel toolbarViewModel;
public ToolbarViewModel(@NonNull Application application) {
this(application, null);
}
public ToolbarViewModel(@NonNull Application application, M model) {
super(application, model);
toolbarViewModel = this;
}
/**
* 设置标题
*
* @param text 标题文字
*/
public void setTitleText(String text) {
titleText.set(text);
}
/**
* 设置右边文字
*
* @param text 右边文字
*/
public void setRightText(String text) {
rightText.set(text);
}
/**
* 设置右边文字的显示和隐藏
*
* @param visibility
*/
public void setRightTextVisible(int visibility) {
rightTextVisibleObservable.set(visibility);
}
/**
* 设置右边图标的显示和隐藏
*
* @param visibility
*/
public void setRightIconVisible(int visibility) {
rightIconVisibleObservable.set(visibility);
}
/**
* 返回按钮的点击事件
*/
public final BindingCommand backOnClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
finish();
}
});
public BindingCommand rightTextOnClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
rightTextOnClick();
}
});
public BindingCommand rightIconOnClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
rightIconOnClick();
}
});
/**
* 右边文字的点击事件,子类可重写
*/
protected void rightTextOnClick() {
}
/**
* 右边图标的点击事件,子类可重写
*/
protected void rightIconOnClick() {
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/form/FormFragment.java
================================================
package com.goldze.mvvmhabit.ui.form;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.DatePicker;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.FragmentFormBinding;
import com.goldze.mvvmhabit.entity.FormEntity;
import java.util.Calendar;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.Observable;
import androidx.lifecycle.Observer;
import me.goldze.mvvmhabit.base.BaseFragment;
import me.goldze.mvvmhabit.utils.MaterialDialogUtils;
/**
* Created by goldze on 2017/7/17.
* 表单提交/编辑界面
*/
public class FormFragment extends BaseFragment<FragmentFormBinding, FormViewModel> {
private FormEntity entity = new FormEntity();
@Override
public void initParam() {
//获取列表传入的实体
Bundle mBundle = getArguments();
if (mBundle != null) {
entity = mBundle.getParcelable("entity");
}
}
@Override
public int initContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return R.layout.fragment_form;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
//通过binding拿到toolbar控件, 设置给Activity
((AppCompatActivity) getActivity()).setSupportActionBar(binding.include.toolbar);
//View层传参到ViewModel层
viewModel.setFormEntity(entity);
//初始化标题
viewModel.initToolbar();
}
@Override
public void initViewObservable() {
//监听日期选择
viewModel.uc.showDateDialogObservable.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
final Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
viewModel.setBir(year, month, dayOfMonth);
}
}, year, month, day);
datePickerDialog.setMessage("生日选择");
datePickerDialog.show();
}
});
viewModel.entityJsonLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String submitJson) {
MaterialDialogUtils.showBasicDialog(getContext(), "提交的json实体数据:\r\n" + submitJson).show();
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/form/FormViewModel.java
================================================
package com.goldze.mvvmhabit.ui.form;
import android.app.Application;
import android.text.TextUtils;
import android.view.View;
import com.goldze.mvvmhabit.entity.FormEntity;
import com.goldze.mvvmhabit.entity.SpinnerItemData;
import com.goldze.mvvmhabit.ui.base.viewmodel.ToolbarViewModel;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableBoolean;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.binding.command.BindingConsumer;
import me.goldze.mvvmhabit.binding.viewadapter.spinner.IKeyAndValue;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Created by goldze on 2017/7/17.
*/
public class FormViewModel extends ToolbarViewModel {
public FormEntity entity;
public List<IKeyAndValue> sexItemDatas;
public SingleLiveEvent<String> entityJsonLiveData = new SingleLiveEvent<>();
//封装一个界面发生改变的观察者
public UIChangeObservable uc;
public class UIChangeObservable {
//显示日期对话框
public ObservableBoolean showDateDialogObservable;
public UIChangeObservable() {
showDateDialogObservable = new ObservableBoolean(false);
}
}
public FormViewModel(@NonNull Application application) {
super(application);
}
@Override
public void onCreate() {
super.onCreate();
uc = new UIChangeObservable();
//sexItemDatas 一般可以从本地Sqlite数据库中取出数据字典对象集合,让该对象实现IKeyAndValue接口
sexItemDatas = new ArrayList<>();
sexItemDatas.add(new SpinnerItemData("男", "1"));
sexItemDatas.add(new SpinnerItemData("女", "2"));
}
/**
* 初始化Toolbar
*/
public void initToolbar() {
//初始化标题栏
setRightTextVisible(View.VISIBLE);
if (TextUtils.isEmpty(entity.getId())) {
//ID为空是新增
setTitleText("表单提交");
} else {
//ID不为空是修改
setTitleText("表单编辑");
}
}
@Override
public void rightTextOnClick() {
ToastUtils.showShort("更多");
}
public void setFormEntity(FormEntity entity) {
if (this.entity == null) {
this.entity = entity;
}
}
//性别选择的监听
public BindingCommand<IKeyAndValue> onSexSelectorCommand = new BindingCommand<>(new BindingConsumer<IKeyAndValue>() {
@Override
public void call(IKeyAndValue iKeyAndValue) {
entity.setSex(iKeyAndValue.getValue());
}
});
//生日选择的监听
public BindingCommand onBirClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
//回调到view层(Fragment)中显示日期对话框
uc.showDateDialogObservable.set(!uc.showDateDialogObservable.get());
}
});
//是否已婚Switch点状态改变回调
public BindingCommand<Boolean> onMarryCheckedChangeCommand = new BindingCommand<>(new BindingConsumer<Boolean>() {
@Override
public void call(Boolean isChecked) {
entity.setMarry(isChecked);
}
});
//提交按钮点击事件
public BindingCommand onCmtClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
String submitJson = new Gson().toJson(entity);
entityJsonLiveData.setValue(submitJson);
}
});
public void setBir(int year, int month, int dayOfMonth) {
//设置数据到实体中,自动刷新界面
entity.setBir(year + "年" + (month + 1) + "月" + dayOfMonth + "日");
//刷新实体,驱动界面更新
entity.notifyChange();
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginActivity.java
================================================
package com.goldze.mvvmhabit.ui.login;
import android.os.Bundle;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.app.AppViewModelFactory;
import com.goldze.mvvmhabit.databinding.ActivityLoginBinding;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import me.goldze.mvvmhabit.base.BaseActivity;
/**
* 一个MVVM模式的登陆界面
*/
public class LoginActivity extends BaseActivity<ActivityLoginBinding, LoginViewModel> {
//ActivityLoginBinding类是databinding框架自定生成的,对应activity_login.xml
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_login;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public LoginViewModel initViewModel() {
//使用自定义的ViewModelFactory来创建ViewModel,如果不重写该方法,则默认会调用LoginViewModel(@NonNull Application application)构造方法
AppViewModelFactory factory = AppViewModelFactory.getInstance(getApplication());
return ViewModelProviders.of(this, factory).get(LoginViewModel.class);
}
@Override
public void initViewObservable() {
//监听ViewModel中pSwitchObservable的变化, 当ViewModel中执行【uc.pSwitchObservable.set(!uc.pSwitchObservable.get());】时会回调该方法
viewModel.uc.pSwitchEvent.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean aBoolean) {
//pSwitchObservable是boolean类型的观察者,所以可以直接使用它的值改变密码开关的图标
if (viewModel.uc.pSwitchEvent.getValue()) {
//密码可见
//在xml中定义id后,使用binding可以直接拿到这个view的引用,不再需要findViewById去找控件了
binding.ivSwichPasswrod.setImageResource(R.mipmap.show_psw);
binding.etPassword.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
} else {
//密码不可见
binding.ivSwichPasswrod.setImageResource(R.mipmap.show_psw_press);
binding.etPassword.setTransformationMethod(PasswordTransformationMethod.getInstance());
}
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginViewModel.java
================================================
package com.goldze.mvvmhabit.ui.login;
import android.app.Application;
import android.text.TextUtils;
import android.view.View;
import com.goldze.mvvmhabit.data.DemoRepository;
import com.goldze.mvvmhabit.ui.main.DemoActivity;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableField;
import androidx.databinding.ObservableInt;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.binding.command.BindingConsumer;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.utils.RxUtils;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Created by goldze on 2017/7/17.
*/
public class LoginViewModel extends BaseViewModel<DemoRepository> {
//用户名的绑定
public ObservableField<String> userName = new ObservableField<>("");
//密码的绑定
public ObservableField<String> password = new ObservableField<>("");
//用户名清除按钮的显示隐藏绑定
public ObservableInt clearBtnVisibility = new ObservableInt();
//封装一个界面发生改变的观察者
public UIChangeObservable uc = new UIChangeObservable();
public class UIChangeObservable {
//密码开关观察者
public SingleLiveEvent<Boolean> pSwitchEvent = new SingleLiveEvent<>();
}
public LoginViewModel(@NonNull Application application, DemoRepository repository) {
super(application, repository);
//从本地取得数据绑定到View层
userName.set(model.getUserName());
password.set(model.getPassword());
}
//清除用户名的点击事件, 逻辑从View层转换到ViewModel层
public BindingCommand clearUserNameOnClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
userName.set("");
}
});
//密码显示开关 (你可以尝试着狂按这个按钮,会发现它有防多次点击的功能)
public BindingCommand passwordShowSwitchOnClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
//让观察者的数据改变,逻辑从ViewModel层转到View层,在View层的监听则会被调用
uc.pSwitchEvent.setValue(uc.pSwitchEvent.getValue() == null || !uc.pSwitchEvent.getValue());
}
});
//用户名输入框焦点改变的回调事件
public BindingCommand<Boolean> onFocusChangeCommand = new BindingCommand<>(new BindingConsumer<Boolean>() {
@Override
public void call(Boolean hasFocus) {
if (hasFocus) {
clearBtnVisibility.set(View.VISIBLE);
} else {
clearBtnVisibility.set(View.INVISIBLE);
}
}
});
//登录按钮的点击事件
public BindingCommand loginOnClickCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
login();
}
});
/**
* 网络模拟一个登陆操作
**/
private void login() {
if (TextUtils.isEmpty(userName.get())) {
ToastUtils.showShort("请输入账号!");
return;
}
if (TextUtils.isEmpty(password.get())) {
ToastUtils.showShort("请输入密码!");
return;
}
//RaJava模拟登录
addSubscribe(model.login()
.compose(RxUtils.schedulersTransformer()) //线程调度
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
showDialog();
}
})
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
dismissDialog();
//保存账号密码
model.saveUserName(userName.get());
model.savePassword(password.get());
//进入DemoActivity页面
startActivity(DemoActivity.class);
//关闭页面
finish();
}
}));
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoActivity.java
================================================
package com.goldze.mvvmhabit.ui.main;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.ActivityDemoBinding;
import com.tbruyelle.rxpermissions2.RxPermissions;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import io.reactivex.functions.Consumer;
import me.goldze.mvvmhabit.base.BaseActivity;
import me.goldze.mvvmhabit.http.DownLoadManager;
import me.goldze.mvvmhabit.http.download.ProgressCallBack;
import me.goldze.mvvmhabit.utils.ToastUtils;
import okhttp3.ResponseBody;
/**
* Created by goldze on 2017/7/17.
*/
public class DemoActivity extends BaseActivity<ActivityDemoBinding, DemoViewModel> {
@Override
public void initParam() {
super.initParam();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_demo;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initViewObservable() {
//注册监听相机权限的请求
viewModel.requestCameraPermissions.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean aBoolean) {
requestCameraPermissions();
}
});
//注册文件下载的监听
viewModel.loadUrlEvent.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String url) {
downFile(url);
}
});
}
/**
* 请求相机权限
*/
private void requestCameraPermissions() {
//请求打开相机权限
RxPermissions rxPermissions = new RxPermissions(DemoActivity.this);
rxPermissions.request(Manifest.permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean) {
ToastUtils.showShort("相机权限已经打开,直接跳入相机");
} else {
ToastUtils.showShort("权限被拒绝");
}
}
});
}
private void downFile(String url) {
String destFileDir = getApplication().getCacheDir().getPath();
String destFileName = System.currentTimeMillis() + ".apk";
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle("正在下载...");
progressDialog.setCancelable(false);
progressDialog.show();
DownLoadManager.getInstance().load(url, new ProgressCallBack<ResponseBody>(destFileDir, destFileName) {
@Override
public void onStart() {
super.onStart();
}
@Override
public void onCompleted() {
progressDialog.dismiss();
}
@Override
public void onSuccess(ResponseBody responseBody) {
ToastUtils.showShort("文件下载完成!");
}
@Override
public void progress(final long progress, final long total) {
progressDialog.setMax((int) total);
progressDialog.setProgress((int) progress);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
ToastUtils.showShort("文件下载失败!");
progressDialog.dismiss();
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoViewModel.java
================================================
package com.goldze.mvvmhabit.ui.main;
import android.app.Application;
import android.os.Bundle;
import com.goldze.mvvmhabit.entity.FormEntity;
import com.goldze.mvvmhabit.ui.form.FormFragment;
import com.goldze.mvvmhabit.ui.network.NetWorkFragment;
import com.goldze.mvvmhabit.ui.rv_multi.MultiRecycleViewFragment;
import com.goldze.mvvmhabit.ui.tab_bar.activity.TabBarActivity;
import com.goldze.mvvmhabit.ui.viewpager.activity.ViewPagerActivity;
import com.goldze.mvvmhabit.ui.vp_frg.ViewPagerGroupFragment;
import androidx.annotation.NonNull;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
/**
* Created by goldze on 2017/7/17.
*/
public class DemoViewModel extends BaseViewModel {
//使用Observable
public SingleLiveEvent<Boolean> requestCameraPermissions = new SingleLiveEvent<>();
//使用LiveData
public SingleLiveEvent<String> loadUrlEvent = new SingleLiveEvent<>();
public DemoViewModel(@NonNull Application application) {
super(application);
}
//网络访问点击事件
public BindingCommand netWorkClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startContainerActivity(NetWorkFragment.class.getCanonicalName());
}
});
//RecycleView多布局
public BindingCommand rvMultiClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startContainerActivity(MultiRecycleViewFragment.class.getCanonicalName());
}
});
//进入TabBarActivity
public BindingCommand startTabBarClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startActivity(TabBarActivity.class);
}
});
//ViewPager绑定
public BindingCommand viewPagerBindingClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startActivity(ViewPagerActivity.class);
}
});
//ViewPager+Fragment
public BindingCommand viewPagerGroupBindingClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startContainerActivity(ViewPagerGroupFragment.class.getCanonicalName());
}
});
//表单提交点击事件
public BindingCommand formSbmClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
startContainerActivity(FormFragment.class.getCanonicalName());
}
});
//表单修改点击事件
public BindingCommand formModifyClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//模拟一个修改的实体数据
FormEntity entity = new FormEntity();
entity.setId("12345678");
entity.setName("goldze");
entity.setSex("1");
entity.setBir("xxxx年xx月xx日");
entity.setMarry(true);
//传入实体数据
Bundle mBundle = new Bundle();
mBundle.putParcelable("entity", entity);
startContainerActivity(FormFragment.class.getCanonicalName(), mBundle);
}
});
//权限申请
public BindingCommand permissionsClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
requestCameraPermissions.call();
}
});
//全局异常捕获
public BindingCommand exceptionClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//伪造一个异常
Integer.parseInt("goldze");
}
});
//文件下载
public BindingCommand fileDownLoadClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
loadUrlEvent.setValue("http://gdown.baidu.com/data/wisegame/dc8a46540c7960a2/baidushoujizhushou_16798087.apk");
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkFragment.java
================================================
package com.goldze.mvvmhabit.ui.network;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.app.AppViewModelFactory;
import com.goldze.mvvmhabit.databinding.FragmentNetworkBinding;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import me.goldze.mvvmhabit.base.BaseFragment;
import me.goldze.mvvmhabit.utils.MaterialDialogUtils;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter;
/**
* Created by goldze on 2017/7/17.
* 网络请求列表界面
*/
public class NetWorkFragment extends BaseFragment<FragmentNetworkBinding, NetWorkViewModel> {
@Override
public void initParam() {
super.initParam();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
public int initContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return R.layout.fragment_network;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public NetWorkViewModel initViewModel() {
//使用自定义的ViewModelFactory来创建ViewModel,如果不重写该方法,则默认会调用NetWorkViewModel(@NonNull Application application)构造方法
AppViewModelFactory factory = AppViewModelFactory.getInstance(getActivity().getApplication());
return ViewModelProviders.of(this, factory).get(NetWorkViewModel.class);
}
@Override
public void initData() {
//请求网络数据
viewModel.requestNetWork();
}
@Override
public void initViewObservable() {
//监听下拉刷新完成
viewModel.uc.finishRefreshing.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
//结束刷新
binding.twinklingRefreshLayout.finishRefreshing();
}
});
//监听上拉加载完成
viewModel.uc.finishLoadmore.observe(this, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
//结束刷新
binding.twinklingRefreshLayout.finishLoadmore();
}
});
//监听删除条目
viewModel.deleteItemLiveData.observe(this, new Observer<NetWorkItemViewModel>() {
@Override
public void onChanged(@Nullable final NetWorkItemViewModel netWorkItemViewModel) {
int index = viewModel.getItemPosition(netWorkItemViewModel);
//删除选择对话框
MaterialDialogUtils.showBasicDialog(getContext(), "提示", "是否删除【" + netWorkItemViewModel.entity.get().getName() + "】? position:" + index)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
ToastUtils.showShort("取消");
}
}).onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
viewModel.deleteItem(netWorkItemViewModel);
}
}).show();
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkItemViewModel.java
================================================
package com.goldze.mvvmhabit.ui.network;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.entity.DemoEntity;
import com.goldze.mvvmhabit.ui.network.detail.DetailFragment;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.databinding.ObservableField;
import me.goldze.mvvmhabit.base.ItemViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Created by goldze on 2017/7/17.
*/
public class NetWorkItemViewModel extends ItemViewModel<NetWorkViewModel> {
public ObservableField<DemoEntity.ItemsEntity> entity = new ObservableField<>();
public Drawable drawableImg;
public NetWorkItemViewModel(@NonNull NetWorkViewModel viewModel, DemoEntity.ItemsEntity entity) {
super(viewModel);
this.entity.set(entity);
//ImageView的占位图片,可以解决RecyclerView中图片错误问题
drawableImg = ContextCompat.getDrawable(viewModel.getApplication(), R.mipmap.ic_launcher);
}
/**
* 获取position的方式有很多种,indexOf是其中一种,常见的还有在Adapter中、ItemBinding.of回调里
*
* @return
*/
public int getPosition() {
return viewModel.getItemPosition(this);
}
//条目的点击事件
public BindingCommand itemClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//这里可以通过一个标识,做出判断,已达到跳入不同界面的逻辑
if (entity.get().getId() == -1) {
viewModel.deleteItemLiveData.setValue(NetWorkItemViewModel.this);
} else {
//跳转到详情界面,传入条目的实体对象
Bundle mBundle = new Bundle();
mBundle.putParcelable("entity", entity.get());
viewModel.startContainerActivity(DetailFragment.class.getCanonicalName(), mBundle);
}
}
});
//条目的长按事件
public BindingCommand itemLongClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//以前是使用Messenger发送事件,在NetWorkViewModel中完成删除逻辑
// Messenger.getDefault().send(NetWorkItemViewModel.this, NetWorkViewModel.TOKEN_NETWORKVIEWMODEL_DELTE_ITEM);
//现在ItemViewModel中存在ViewModel引用,可以直接拿到LiveData去做删除
ToastUtils.showShort(entity.get().getName());
}
});
// /**
// * 可以在xml中使用binding:currentView="@{viewModel.titleTextView}" 拿到这个控件的引用, 但是强烈不推荐这样做,避免内存泄漏
// **/
// private TextView tv;
// //将标题TextView控件回调到ViewModel中
// public BindingCommand<TextView> titleTextView = new BindingCommand(new BindingConsumer<TextView>() {
// @Override
// public void call(TextView tv) {
// NetWorkItemViewModel.this.tv = tv;
// }
// });
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkViewModel.java
================================================
package com.goldze.mvvmhabit.ui.network;
import android.app.Application;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.data.DemoRepository;
import com.goldze.mvvmhabit.entity.DemoEntity;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.observers.DisposableObserver;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.http.BaseResponse;
import me.goldze.mvvmhabit.http.ResponseThrowable;
import me.goldze.mvvmhabit.utils.RxUtils;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.tatarka.bindingcollectionadapter2.ItemBinding;
/**
* Created by goldze on 2017/7/17.
*/
public class NetWorkViewModel extends BaseViewModel<DemoRepository> {
public SingleLiveEvent<NetWorkItemViewModel> deleteItemLiveData = new SingleLiveEvent<>();
//封装一个界面发生改变的观察者
public UIChangeObservable uc = new UIChangeObservable();
public class UIChangeObservable {
//下拉刷新完成
public SingleLiveEvent finishRefreshing = new SingleLiveEvent<>();
//上拉加载完成
public SingleLiveEvent finishLoadmore = new SingleLiveEvent<>();
}
public NetWorkViewModel(@NonNull Application application, DemoRepository repository) {
super(application, repository);
}
//给RecyclerView添加ObservableList
public ObservableList<NetWorkItemViewModel> observableList = new ObservableArrayList<>();
//给RecyclerView添加ItemBinding
public ItemBinding<NetWorkItemViewModel> itemBinding = ItemBinding.of(BR.viewModel, R.layout.item_network);
//下拉刷新
public BindingCommand onRefreshCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
ToastUtils.showShort("下拉刷新");
requestNetWork();
}
});
//上拉加载
public BindingCommand onLoadMoreCommand = new BindingCommand(new BindingAction() {
@Override
public void call() {
if (observableList.size() > 50) {
ToastUtils.showLong("兄dei,你太无聊啦~崩是不可能的~");
uc.finishLoadmore.call();
return;
}
//模拟网络上拉加载更多
model.loadMore()
.compose(RxUtils.schedulersTransformer()) //线程调度
.doOnSubscribe(NetWorkViewModel.this) //请求与ViewModel周期同步
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
ToastUtils.showShort("上拉加载");
}
})
.subscribe(new Consumer<DemoEntity>() {
@Override
public void accept(DemoEntity entity) throws Exception {
for (DemoEntity.ItemsEntity itemsEntity : entity.getItems()) {
NetWorkItemViewModel itemViewModel = new NetWorkItemViewModel(NetWorkViewModel.this, itemsEntity);
//双向绑定动态添加Item
observableList.add(itemViewModel);
}
//刷新完成收回
uc.finishLoadmore.call();
}
});
}
});
/**
* 网络请求方法,在ViewModel中调用Model层,通过Okhttp+Retrofit+RxJava发起请求
*/
public void requestNetWork() {
//可以调用addSubscribe()添加Disposable,请求与View周期同步
model.demoGet()
.compose(RxUtils.schedulersTransformer()) //线程调度
.compose(RxUtils.exceptionTransformer()) // 网络错误的异常转换, 这里可以换成自己的ExceptionHandle
.doOnSubscribe(this)//请求与ViewModel周期同步
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
showDialog("正在请求...");
}
})
.subscribe(new DisposableObserver<BaseResponse<DemoEntity>>() {
@Override
public void onNext(BaseResponse<DemoEntity> response) {
//清除列表
observableList.clear();
//请求成功
if (response.getCode() == 1) {
for (DemoEntity.ItemsEntity entity : response.getResult().getItems()) {
NetWorkItemViewModel itemViewModel = new NetWorkItemViewModel(NetWorkViewModel.this, entity);
//双向绑定动态添加Item
observableList.add(itemViewModel);
}
} else {
//code错误时也可以定义Observable回调到View层去处理
ToastUtils.showShort("数据错误");
}
}
@Override
public void onError(Throwable throwable) {
//关闭对话框
dismissDialog();
//请求刷新完成收回
uc.finishRefreshing.call();
if (throwable instanceof ResponseThrowable) {
ToastUtils.showShort(((ResponseThrowable) throwable).message);
}
}
@Override
public void onComplete() {
//关闭对话框
dismissDialog();
//请求刷新完成收回
uc.finishRefreshing.call();
}
});
}
/**
* 删除条目
*
* @param netWorkItemViewModel
*/
public void deleteItem(NetWorkItemViewModel netWorkItemViewModel) {
//点击确定,在 observableList 绑定中删除,界面立即刷新
observableList.remove(netWorkItemViewModel);
}
/**
* 获取条目下标
*
* @param netWorkItemViewModel
* @return
*/
public int getItemPosition(NetWorkItemViewModel netWorkItemViewModel) {
return observableList.indexOf(netWorkItemViewModel);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailFragment.java
================================================
package com.goldze.mvvmhabit.ui.network.detail;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.FragmentDetailBinding;
import com.goldze.mvvmhabit.entity.DemoEntity;
import me.goldze.mvvmhabit.base.BaseFragment;
/**
* Created by goldze on 2017/7/17.
* 详情界面
*/
public class DetailFragment extends BaseFragment<FragmentDetailBinding, DetailViewModel> {
private DemoEntity.ItemsEntity entity;
@Override
public void initParam() {
//获取列表传入的实体
Bundle mBundle = getArguments();
if (mBundle != null) {
entity = mBundle.getParcelable("entity");
}
}
@Override
public int initContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return R.layout.fragment_detail;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
viewModel.setDemoEntity(entity);
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailViewModel.java
================================================
package com.goldze.mvvmhabit.ui.network.detail;
import android.app.Application;
import com.goldze.mvvmhabit.entity.DemoEntity;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableField;
import me.goldze.mvvmhabit.base.BaseViewModel;
/**
* Created by goldze on 2017/7/17.
*/
public class DetailViewModel extends BaseViewModel {
public ObservableField<DemoEntity.ItemsEntity> entity = new ObservableField<>();
public DetailViewModel(@NonNull Application application) {
super(application);
}
public void setDemoEntity(DemoEntity.ItemsEntity entity) {
this.entity.set(entity);
}
@Override
public void onDestroy() {
super.onDestroy();
entity = null;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleHeadViewModel.java
================================================
package com.goldze.mvvmhabit.ui.rv_multi;
import androidx.annotation.NonNull;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.base.MultiItemViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:
*/
public class MultiRecycleHeadViewModel extends MultiItemViewModel {
public MultiRecycleHeadViewModel(@NonNull BaseViewModel viewModel) {
super(viewModel);
}
//条目的点击事件
public BindingCommand itemClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
ToastUtils.showShort("我是头布局");
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleLeftItemViewModel.java
================================================
package com.goldze.mvvmhabit.ui.rv_multi;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableField;
import me.goldze.mvvmhabit.base.MultiItemViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:
*/
public class MultiRecycleLeftItemViewModel extends MultiItemViewModel<MultiRecycleViewModel> {
public ObservableField<String> text = new ObservableField<>("");
public MultiRecycleLeftItemViewModel(@NonNull MultiRecycleViewModel viewModel, String text) {
super(viewModel);
this.text.set(text);
}
//条目的点击事件
public BindingCommand itemClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//拿到position
int position = viewModel.observableList.indexOf(MultiRecycleLeftItemViewModel.this);
ToastUtils.showShort("position:" + position);
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleRightItemViewModel.java
================================================
package com.goldze.mvvmhabit.ui.rv_multi;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableField;
import me.goldze.mvvmhabit.base.MultiItemViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:
*/
public class MultiRecycleRightItemViewModel extends MultiItemViewModel<MultiRecycleViewModel> {
public ObservableField<String> text = new ObservableField<>("");
public MultiRecycleRightItemViewModel(@NonNull MultiRecycleViewModel viewModel, String text) {
super(viewModel);
this.text.set(text);
}
//条目的点击事件
public BindingCommand itemClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//拿到position
int position = viewModel.observableList.indexOf(MultiRecycleRightItemViewModel.this);
ToastUtils.showShort("position:" + position);
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewFragment.java
================================================
package com.goldze.mvvmhabit.ui.rv_multi;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.FragmentMultiRvBinding;
import androidx.annotation.Nullable;
import me.goldze.mvvmhabit.base.BaseFragment;
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:RecycleView多布局实现
*/
public class MultiRecycleViewFragment extends BaseFragment<FragmentMultiRvBinding, MultiRecycleViewModel> {
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_multi_rv;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
super.initData();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewModel.java
================================================
package com.goldze.mvvmhabit.ui.rv_multi;
import android.app.Application;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.base.MultiItemViewModel;
import me.tatarka.bindingcollectionadapter2.ItemBinding;
import me.tatarka.bindingcollectionadapter2.OnItemBind;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:
*/
public class MultiRecycleViewModel extends BaseViewModel {
private static final String MultiRecycleType_Head = "head";
private static final String MultiRecycleType_Left = "left";
private static final String MultiRecycleType_Right = "right";
public MultiRecycleViewModel(@NonNull Application application) {
super(application);
//模拟10个条目,数据源可以来自网络
for (int i = 0; i < 20; i++) {
if (i == 0) {
MultiItemViewModel item = new MultiRecycleHeadViewModel(this);
//条目类型为头布局
item.multiItemType(MultiRecycleType_Head);
observableList.add(item);
} else {
String text = "我是第" + i + "条";
if (i % 2 == 0) {
MultiItemViewModel item = new MultiRecycleLeftItemViewModel(this, text);
//条目类型为左布局
item.multiItemType(MultiRecycleType_Left);
observableList.add(item);
} else {
MultiItemViewModel item = new MultiRecycleRightItemViewModel(this, text);
//条目类型为右布局
item.multiItemType(MultiRecycleType_Right);
observableList.add(item);
}
}
}
}
//给RecyclerView添加ObservableList
public ObservableList<MultiItemViewModel> observableList = new ObservableArrayList<>();
//RecyclerView多布局添加ItemBinding
public ItemBinding<MultiItemViewModel> itemBinding = ItemBinding.of(new OnItemBind<MultiItemViewModel>() {
@Override
public void onItemBind(ItemBinding itemBinding, int position, MultiItemViewModel item) {
//通过item的类型, 动态设置Item加载的布局
String itemType = (String) item.getItemType();
if (MultiRecycleType_Head.equals(itemType)) {
//设置头布局
itemBinding.set(BR.viewModel, R.layout.item_multi_head);
} else if (MultiRecycleType_Left.equals(itemType)) {
//设置左布局
itemBinding.set(BR.viewModel, R.layout.item_multi_rv_left);
} else if (MultiRecycleType_Right.equals(itemType)) {
//设置右布局
itemBinding.set(BR.viewModel, R.layout.item_multi_rv_right);
}
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/activity/TabBarActivity.java
================================================
package com.goldze.mvvmhabit.ui.tab_bar.activity;
import android.os.Bundle;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.ActivityTabBarBinding;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar1Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar2Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar3Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar4Fragment;
import java.util.ArrayList;
import java.util.List;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import me.goldze.mvvmhabit.base.BaseActivity;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.majiajie.pagerbottomtabstrip.NavigationController;
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
/**
* 底部tab按钮的例子
* 所有例子仅做参考,理解如何使用才最重要。
* Created by goldze on 2018/7/18.
*/
public class TabBarActivity extends BaseActivity<ActivityTabBarBinding, BaseViewModel> {
private List<Fragment> mFragments;
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_tab_bar;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
//初始化Fragment
initFragment();
//初始化底部Button
initBottomTab();
}
private void initFragment() {
mFragments = new ArrayList<>();
mFragments.add(new TabBar1Fragment());
mFragments.add(new TabBar2Fragment());
mFragments.add(new TabBar3Fragment());
mFragments.add(new TabBar4Fragment());
//默认选中第一个
commitAllowingStateLoss(0);
}
private void initBottomTab() {
NavigationController navigationController = binding.pagerBottomTab.material()
.addItem(R.mipmap.yingyong, "应用")
.addItem(R.mipmap.huanzhe, "工作")
.addItem(R.mipmap.xiaoxi_select, "消息")
.addItem(R.mipmap.wode_select, "我的")
.setDefaultColor(ContextCompat.getColor(this, R.color.textColorVice))
.build();
//底部按钮的点击事件监听
navigationController.addTabItemSelectedListener(new OnTabItemSelectedListener() {
@Override
public void onSelected(int index, int old) {
// FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// transaction.replace(R.id.frameLayout, mFragments.get(index));
// transaction.commitAllowingStateLoss();
commitAllowingStateLoss(index);
}
@Override
public void onRepeat(int index) {
}
});
}
private void commitAllowingStateLoss(int position) {
hideAllFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(position + "");
if (currentFragment != null) {
transaction.show(currentFragment);
} else {
currentFragment = mFragments.get(position);
transaction.add(R.id.frameLayout, currentFragment, position + "");
}
transaction.commitAllowingStateLoss();
}
//隐藏所有Fragment
private void hideAllFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
for (int i = 0; i < mFragments.size(); i++) {
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(i + "");
if (currentFragment != null) {
transaction.hide(currentFragment);
}
}
transaction.commitAllowingStateLoss();
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar1Fragment.java
================================================
package com.goldze.mvvmhabit.ui.tab_bar.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.Nullable;
import me.goldze.mvvmhabit.base.BaseFragment;
/**
* Created by goldze on 2018/7/18.
*/
public class TabBar1Fragment extends BaseFragment {
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_tab_bar_1;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar2Fragment.java
================================================
package com.goldze.mvvmhabit.ui.tab_bar.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.Nullable;
import me.goldze.mvvmhabit.base.BaseFragment;
/**
* Created by goldze on 2018/7/18.
*/
public class TabBar2Fragment extends BaseFragment {
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_tab_bar_2;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar3Fragment.java
================================================
package com.goldze.mvvmhabit.ui.tab_bar.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.Nullable;
import me.goldze.mvvmhabit.base.BaseFragment;
/**
* Created by goldze on 2018/7/18.
*/
public class TabBar3Fragment extends BaseFragment{
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_tab_bar_3;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar4Fragment.java
================================================
package com.goldze.mvvmhabit.ui.tab_bar.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.Nullable;
import me.goldze.mvvmhabit.base.BaseFragment;
/**
* Created by goldze on 2018/7/18.
*/
public class TabBar4Fragment extends BaseFragment {
@Override
public int initContentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return R.layout.fragment_tab_bar_4;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/activity/ViewPagerActivity.java
================================================
package com.goldze.mvvmhabit.ui.viewpager.activity;
import android.os.Bundle;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import com.goldze.mvvmhabit.databinding.FragmentViewpagerBinding;
import com.goldze.mvvmhabit.ui.viewpager.adapter.ViewPagerBindingAdapter;
import com.goldze.mvvmhabit.ui.viewpager.vm.ViewPagerViewModel;
import com.google.android.material.tabs.TabLayout;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import me.goldze.mvvmhabit.base.BaseActivity;
import me.goldze.mvvmhabit.utils.ToastUtils;
/**
* ViewPager绑定的例子, 更多绑定方式,请参考 https://github.com/evant/binding-collection-adapter
* 所有例子仅做参考,千万不要把它当成一种标准,毕竟主打的不是例子,业务场景繁多,理解如何使用才最重要。
* Created by goldze on 2018/7/18.
*/
public class ViewPagerActivity extends BaseActivity<FragmentViewpagerBinding, ViewPagerViewModel> {
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.fragment_viewpager;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
@Override
public void initData() {
// 使用 TabLayout 和 ViewPager 相关联
binding.tabs.setupWithViewPager(binding.viewPager);
binding.viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(binding.tabs));
//给ViewPager设置adapter
binding.setAdapter(new ViewPagerBindingAdapter());
}
@Override
public void initViewObservable() {
viewModel.itemClickEvent.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String text) {
ToastUtils.showShort("position:" + text);
}
});
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/adapter/ViewPagerBindingAdapter.java
================================================
package com.goldze.mvvmhabit.ui.viewpager.adapter;
import android.view.ViewGroup;
import com.goldze.mvvmhabit.databinding.ItemViewpagerBinding;
import com.goldze.mvvmhabit.ui.viewpager.vm.ViewPagerItemViewModel;
import androidx.databinding.ViewDataBinding;
import me.tatarka.bindingcollectionadapter2.BindingViewPagerAdapter;
/**
* Created by goldze on 2018/6/21.
*/
public class ViewPagerBindingAdapter extends BindingViewPagerAdapter<ViewPagerItemViewModel> {
@Override
public void onBindBinding(final ViewDataBinding binding, int variableId, int layoutRes, final int position, ViewPagerItemViewModel item) {
super.onBindBinding(binding, variableId, layoutRes, position, item);
//这里可以强转成ViewPagerItemViewModel对应的ViewDataBinding,
ItemViewpagerBinding _binding = (ItemViewpagerBinding) binding;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerItemViewModel.java
================================================
package com.goldze.mvvmhabit.ui.viewpager.vm;
import androidx.annotation.NonNull;
import me.goldze.mvvmhabit.base.ItemViewModel;
import me.goldze.mvvmhabit.binding.command.BindingAction;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
/**
* 所有例子仅做参考,千万不要把它当成一种标准,毕竟主打的不是例子,业务场景繁多,理解如何使用才最重要。
* Created by goldze on 2018/7/18.
*/
public class ViewPagerItemViewModel extends ItemViewModel<ViewPagerViewModel> {
public String text;
public ViewPagerItemViewModel(@NonNull ViewPagerViewModel viewModel, String text) {
super(viewModel);
this.text = text;
}
public BindingCommand onItemClick = new BindingCommand(new BindingAction() {
@Override
public void call() {
//点击之后将逻辑转到activity中处理
viewModel.itemClickEvent.setValue(text);
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerViewModel.java
================================================
package com.goldze.mvvmhabit.ui.viewpager.vm;
import android.app.Application;
import com.goldze.mvvmhabit.BR;
import com.goldze.mvvmhabit.R;
import androidx.annotation.NonNull;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.binding.command.BindingConsumer;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.tatarka.bindingcollectionadapter2.BindingViewPagerAdapter;
import me.tatarka.bindingcollectionadapter2.ItemBinding;
/**
* 所有例子仅做参考,千万不要把它当成一种标准,毕竟主打的不是例子,业务场景繁多,理解如何使用才最重要。
* Created by goldze on 2018/7/18.
*/
public class ViewPagerViewModel extends BaseViewModel {
public SingleLiveEvent<String> itemClickEvent = new SingleLiveEvent<>();
public ViewPagerViewModel(@NonNull Application application) {
super(application);
//模拟3个ViewPager页面
for (int i = 1; i <= 3; i++) {
ViewPagerItemViewModel itemViewModel = new ViewPagerItemViewModel(this, "第" + i + "个页面");
items.add(itemViewModel);
}
}
//给ViewPager添加ObservableList
public ObservableList<ViewPagerItemViewModel> items = new ObservableArrayList<>();
//给ViewPager添加ItemBinding
public ItemBinding<ViewPagerItemViewModel> itemBinding = ItemBinding.of(BR.viewModel, R.layout.item_viewpager);
//给ViewPager添加PageTitle
public final BindingViewPagerAdapter.PageTitles<ViewPagerItemViewModel> pageTitles = new BindingViewPagerAdapter.PageTitles<ViewPagerItemViewModel>() {
@Override
public CharSequence getPageTitle(int position, ViewPagerItemViewModel item) {
return "条目" + position;
}
};
//ViewPager切换监听
public BindingCommand<Integer> onPageSelectedCommand = new BindingCommand<>(new BindingConsumer<Integer>() {
@Override
public void call(Integer index) {
ToastUtils.showShort("ViewPager切换:" + index);
}
});
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/vp_frg/ViewPagerGroupFragment.java
================================================
package com.goldze.mvvmhabit.ui.vp_frg;
import com.goldze.mvvmhabit.ui.base.fragment.BasePagerFragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar1Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar2Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar3Fragment;
import com.goldze.mvvmhabit.ui.tab_bar.fragment.TabBar4Fragment;
import java.util.ArrayList;
import java.util.List;
import androidx.fragment.app.Fragment;
/**
* Create Author:goldze
* Create Date:2019/01/25
* Description:ViewPager+Fragment的实现
*/
public class ViewPagerGroupFragment extends BasePagerFragment {
@Override
protected List<Fragment> pagerFragment() {
List<Fragment> list = new ArrayList<>();
list.add(new TabBar1Fragment());
list.add(new TabBar2Fragment());
list.add(new TabBar3Fragment());
list.add(new TabBar4Fragment());
return list;
}
@Override
protected List<String> pagerTitleString() {
List<String> list = new ArrayList<>();
list.add("page1");
list.add("page2");
list.add("page3");
list.add("page4");
return list;
}
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/utils/HttpsUtils.java
================================================
/*
* Copyright 2016 jeasonlzy(廖子尧)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.goldze.mvvmhabit.utils;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class HttpsUtils {
public static class SSLParams {
public SSLSocketFactory sSLSocketFactory;
public X509TrustManager trustManager;
}
public static SSLParams getSslSocketFactory() {
return getSslSocketFactoryBase(null, null, null);
}
/**
* https单向认证
* 可以额外配置信任服务端的证书策略,否则默认是按CA证书去验证的,若不是CA可信任的证书,则无法通过验证
*/
public static SSLParams getSslSocketFactory(X509TrustManager trustManager) {
return getSslSocketFactoryBase(trustManager, null, null);
}
/**
* https单向认证
* 用含有服务端公钥的证书校验服务端证书
*/
public static SSLParams getSslSocketFactory(InputStream... certificates) {
return getSslSocketFactoryBase(null, null, null, certificates);
}
/**
* https双向认证
* bksFile 和 password -> 客户端使用bks证书校验服务端证书
* certificates -> 用含有服务端公钥的证书校验服务端证书
*/
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, InputStream... certificates) {
return getSslSocketFactoryBase(null, bksFile, password, certificates);
}
/**
* https双向认证
* bksFile 和 password -> 客户端使用bks证书校验服务端证书
* X509TrustManager -> 如果需要自己校验,那么可以自己实现相关校验,如果不需要自己校验,那么传null即可
*/
public static SSLParams getSslSocketFactory(InputStream bksFile, String password, X509TrustManager trustManager) {
return getSslSocketFactoryBase(trustManager, bksFile, password);
}
private static SSLParams getSslSocketFactoryBase(X509TrustManager trustManager, InputStream bksFile, String password, InputStream... certificates) {
SSLParams sslParams = new SSLParams();
try {
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
TrustManager[] trustManagers = prepareTrustManager(certificates);
X509TrustManager manager;
if (trustManager != null) {
//优先使用用户自定义的TrustManager
manager = trustManager;
} else if (trustManagers != null) {
//然后使用默认的TrustManager
manager = chooseTrustManager(trustManagers);
} else {
//否则使用不安全的TrustManager
manager = UnSafeTrustManager;
}
// 创建TLS类型的SSLContext对象, that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
// 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
// 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书
sslContext.init(keyManagers, new TrustManager[]{manager}, null);
// 通过sslContext获取SSLSocketFactory对象
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
sslParams.trustManager = manager;
return sslParams;
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyManagementException e) {
throw new AssertionError(e);
}
}
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null) return null;
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientKeyStore, password.toCharArray());
return kmf.getKeyManagers();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0) return null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
// 创建一个默认类型的KeyStore,存储我们信任的证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certStream : certificates) {
String certificateAlias = Integer.toString(index++);
// 证书工厂根据证书文件的流生成证书 cert
Certificate cert = certificateFactory.generateCertificate(certStream);
// 将 cert 作为可信证书放入到keyStore中
keyStore.setCertificateEntry(certificateAlias, cert);
try {
if (certStream != null) certStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//我们创建一个默认类型的TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书
tmf.init(keyStore);
//通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书
return tmf.getTrustManagers();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
/**
* 为了解决客户端不信任服务器数字证书的问题,网络上大部分的解决方案都是让客户端不对证书做任何检查,
* 这是一种有很大安全漏洞的办法
*/
public static X509TrustManager UnSafeTrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
/**
* 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,
* 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。
* 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true
*/
public static HostnameVerifier UnSafeHostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
================================================
FILE: app/src/main/java/com/goldze/mvvmhabit/utils/RetrofitClient.java
================================================
package com.goldze.mvvmhabit.utils;
import android.content.Context;
import android.text.TextUtils;
import com.goldze.mvvmhabit.BuildConfig;
import java.io.File;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import me.goldze.mvvmhabit.http.cookie.CookieJarImpl;
import me.goldze.mvvmhabit.http.cookie.store.PersistentCookieStore;
import me.goldze.mvvmhabit.http.interceptor.BaseInterceptor;
import me.goldze.mvvmhabit.http.interceptor.CacheInterceptor;
import me.goldze.mvvmhabit.http.interceptor.logging.Level;
import me.goldze.mvvmhabit.http.interceptor.logging.LoggingInterceptor;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.Utils;
import okhttp3.Cache;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.internal.platform.Platform;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by goldze on 2017/5/10.
* RetrofitClient封装单例类, 实现网络请求
*/
public class RetrofitClient {
//超时时间
private static final int DEFAULT_TIMEOUT = 20;
//缓存时间
private static final int CACHE_TIMEOUT = 10 * 1024 * 1024;
//服务端根路径
public static String baseUrl = "https://www.oschina.net/";
private static Context mContext = Utils.getContext();
private static OkHttpClient okHttpClient;
private static Retrofit retrofit;
private Cache cache = null;
private File httpCacheDirectory;
private static class SingletonHolder {
private static RetrofitClient INSTANCE = new RetrofitClient();
}
public static RetrofitClient getInstance() {
return SingletonHolder.INSTANCE;
}
private RetrofitClient() {
this(baseUrl, null);
}
private RetrofitClient(String url, Map<String, String> headers) {
if (TextUtils.isEmpty(url)) {
url = baseUrl;
}
if (httpCacheDirectory == null) {
httpCacheDirectory = new File(mContext.getCacheDir(), "goldze_cache");
}
try {
if (cache == null) {
cache = new Cache(httpCacheDirectory, CACHE_TIMEOUT);
}
} catch (Exception e) {
KLog.e("Could not create http cache", e);
}
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory();
okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new PersistentCookieStore(mContext)))
// .cache(cache)
.addInterceptor(new BaseInterceptor(headers))
.addInterceptor(new CacheInterceptor(mContext))
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.addInterceptor(new LoggingInterceptor
.Builder()//构建者模式
.loggable(BuildConfig.DEBUG) //是否开启日志打印
.setLevel(Level.BASIC) //打印的等级
.log(Platform.INFO) // 打印类型
.request("Request") // request的Tag
.response("Response")// Response的Tag
.addHeader("log-header", "I am the log request header.") // 添加打印头, 注意 key 和 value 都不能是中文
.build()
)
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS))
// 这里你可以根据自己的机型设置同时连接的个数和时间,我这里8个,和每个保持时间为10s
.build();
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(url)
.build();
}
/**
* create you ApiService
* Create an implementation of the API endpoints defined by the {@code service} interface.
*/
public <T> T create(final Class<T> service) {
if (service == null) {
throw new RuntimeException("Api service is null!");
}
return retrofit.create(service);
}
/**
* /**
* execute your customer API
* For example:
* MyApiService service =
* RetrofitClient.getInstance(MainActivity.this).create(MyApiService.class);
* <p>
* RetrofitClient.getInstance(MainActivity.this)
* .execute(service.lgon("name", "password"), subscriber)
* * @param subscriber
*/
public static <T> T execute(Observable<T> observable, Observer<T> subscriber) {
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
return null;
}
}
================================================
FILE: app/src/main/res/drawable/login_clear_input.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/registered_delete_grey" android:state_pressed="false"/>
<item android:drawable="@mipmap/registered_delete_bule" android:state_pressed="true"/>
</selector>
================================================
FILE: app/src/main/res/layout/activity_demo.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.main.DemoViewModel" />
<variable
name="viewModel"
type="DemoViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#202020"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="网络访问"
binding:onClickCommand="@{viewModel.netWorkClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RecycleView多布局"
binding:onClickCommand="@{viewModel.rvMultiClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="底部Tab按钮"
binding:onClickCommand="@{viewModel.startTabBarClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ViewPager绑定"
binding:onClickCommand="@{viewModel.viewPagerBindingClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ViewPager+Fragment"
binding:onClickCommand="@{viewModel.viewPagerGroupBindingClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="表单提交"
binding:onClickCommand="@{viewModel.formSbmClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="表单编辑"
binding:onClickCommand="@{viewModel.formModifyClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="权限申请"
binding:onClickCommand="@{viewModel.permissionsClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="全局异常捕获"
binding:onClickCommand="@{viewModel.exceptionClick}" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="文件下载"
binding:onClickCommand="@{viewModel.fileDownLoadClick}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/activity_login.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.goldze.mvvmhabit.ui.login.LoginViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@mipmap/login_back"
android:scaleType="fitXY" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="20dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/logo" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="34dp"
android:background="@mipmap/user_edit"
android:gravity="center"
android:orientation="horizontal"
android:padding="16sp">
<ImageView
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@mipmap/user_icon" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@color/textColorHint" />
<EditText
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:hint="请输入用户名"
android:text="@={viewModel.userName}"
android:textColor="@color/textColor"
android:textColorHint="@color/textColorHint"
android:textSize="16sp"
binding:onFocusChangeCommand="@{viewModel.onFocusChangeCommand}" />
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:padding="6dp"
android:src="@mipmap/clean_edit"
android:visibility="@{viewModel.clearBtnVisibility}"
binding:onClickCommand="@{viewModel.clearUserNameOnClickCommand}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@mipmap/user_edit"
android:gravity="center"
android:orientation="horizontal"
android:padding="16sp">
<ImageView
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@mipmap/password_icon" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@color/textColorHint" />
<EditText
android:id="@+id/et_password"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:hint="请输入密码"
android:inputType="textPassword"
android:text="@={viewModel.password}"
android:textColor="@color/textColor"
android:textColorHint="@color/textColorHint"
android:textSize="16sp" />
<ImageView
android:id="@+id/iv_swich_passwrod"
android:layout_width="30dp"
android:layout_height="30dp"
android:padding="6dp"
android:src="@mipmap/show_psw_press"
binding:onClickCommand="@{viewModel.passwordShowSwitchOnClickCommand}" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:text="忘记密码"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@mipmap/btn_login"
android:orientation="vertical"
android:padding="6dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:text="登录"
android:textColor="@color/white"
android:textSize="18sp"
binding:onClickCommand="@{viewModel.loginOnClickCommand}" />
</LinearLayout>
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="模拟一个登陆操作,随便输入账号密码点击登录即可进入"
android:textColor="#EE1010" />
</LinearLayout>
</RelativeLayout>
</layout>
================================================
FILE: app/src/main/res/layout/activity_tab_bar.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="me.goldze.mvvmhabit.base.BaseViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
<me.majiajie.pagerbottomtabstrip.PageBottomTabLayout
android:id="@+id/pager_bottom_tab"
android:layout_width="match_parent"
android:layout_height="56dp"
app:elevation="8dp" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_base_pager.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="me.goldze.mvvmhabit.base.BaseViewModel" />
<variable
name="viewModel"
type="BaseViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorPrimary"
app:tabSelectedTextColor="@color/colorPrimary"
app:tabTextColor="@android:color/black" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_detail.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.network.detail.DetailViewModel" />
<variable
name="viewModel"
type="com.goldze.mvvmhabit.ui.network.detail.DetailViewModel"
/>
<import type="com.goldze.mvvmhabit.R" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:gravity="center"
android:orientation="vertical"
>
<ImageView
android:layout_width="280dp"
android:layout_height="140dp"
android:src="@mipmap/ic_launcher"
binding:url="@{viewModel.entity.img}"
binding:placeholderRes="@{R.mipmap.ic_launcher_round}"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="id"
android:textSize="18sp"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@{String.valueOf(viewModel.entity.id)}"
android:textSize="18sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="名称"
android:textSize="18sp"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@{viewModel.entity.name}"
android:textSize="18sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="日期"
android:textSize="18sp"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@{viewModel.entity.pubDate}"
android:textSize="18sp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="图片路径"
android:textSize="18sp"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@{viewModel.entity.img}"
android:textSize="18sp"
/>
</LinearLayout>
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_form.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.form.FormViewModel" />
<variable
name="viewModel"
type="com.goldze.mvvmhabit.ui.form.FormViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/include"
layout="@layout/layout_toolbar"
binding:toolbarViewModel="@{viewModel.toolbarViewModel}" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="姓名" />
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@={viewModel.entity.name}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="性别" />
<Spinner
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
binding:itemDatas="@{viewModel.sexItemDatas}"
binding:onItemSelectedCommand="@{viewModel.onSexSelectorCommand}"
binding:valueReply="@{viewModel.entity.sex}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="生日" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="@={viewModel.entity.bir}"
binding:onClickCommand="@{viewModel.onBirClickCommand}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="是否已婚" />
<Switch
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
binding:onCheckedChangeCommand="@{viewModel.onMarryCheckedChangeCommand}"
binding:switchState="@{viewModel.entity.marry}" />
</LinearLayout>
<Button
android:id="@+id/btn_cmt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="立即提交"
binding:onClickCommand="@{viewModel.onCmtClickCommand}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_multi_rv.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.rv_multi.MultiRecycleViewModel" />
<variable
name="viewModel"
type="MultiRecycleViewModel" />
<import type="me.goldze.mvvmhabit.binding.viewadapter.recyclerview.LayoutManagers" />
<import type="me.goldze.mvvmhabit.binding.viewadapter.recyclerview.LineManagers" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
binding:itemBinding="@{viewModel.itemBinding}"
binding:items="@{viewModel.observableList}"
binding:layoutManager="@{LayoutManagers.linear()}"
binding:lineManager="@{LineManagers.horizontal()}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_network.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.network.NetWorkViewModel" />
<variable
name="viewModel"
type="NetWorkViewModel" />
<import type="me.goldze.mvvmhabit.binding.viewadapter.recyclerview.LayoutManagers" />
<import type="me.goldze.mvvmhabit.binding.viewadapter.recyclerview.LineManagers" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout
android:id="@+id/twinklingRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
binding:onLoadMoreCommand="@{viewModel.onLoadMoreCommand}"
binding:onRefreshCommand="@{viewModel.onRefreshCommand}"
binding:tr_head_height="80dp"
binding:tr_wave_height="80dp">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
binding:itemBinding="@{viewModel.itemBinding}"
binding:items="@{viewModel.observableList}"
binding:layoutManager="@{LayoutManagers.linear()}"
binding:lineManager="@{LineManagers.horizontal()}" />
</com.lcodecore.tkrefreshlayout.TwinklingRefreshLayout>
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_tab_bar_1.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="me.goldze.mvvmhabit.base.BaseViewModel" />
<variable
name="viewModel"
type="BaseViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|left"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TabBar_1" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_tab_bar_2.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="me.goldze.mvvmhabit.base.BaseViewModel" />
<variable
name="viewModel"
type="BaseViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|right"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TabBar_2" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_tab_bar_3.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="me.goldze.mvvmhabit.base.BaseViewModel" />
<variable
name="viewModel"
type="BaseViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom|left"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TabBar_3" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_tab_bar_4.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="me.goldze.mvvmhabit.base.BaseViewModel" />
<variable
name="viewModel"
type="BaseViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom|right"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TabBar_4" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/fragment_viewpager.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.viewpager.vm.ViewPagerViewModel" />
<import type="com.goldze.mvvmhabit.ui.viewpager.adapter.ViewPagerBindingAdapter" />
<variable
name="viewModel"
type="ViewPagerViewModel" />
<variable
name="adapter"
type="ViewPagerBindingAdapter" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
binding:tabGravity="fill"
binding:tabIndicatorColor="@color/colorPrimary"
binding:tabSelectedTextColor="@color/colorPrimary"
binding:tabTextColor="@android:color/black" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F0F0F0" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
binding:adapter="@{adapter}"
binding:itemBinding="@{viewModel.itemBinding}"
binding:items="@{viewModel.items}"
binding:onPageSelectedCommand="@{viewModel.onPageSelectedCommand}"
binding:pageTitles="@{viewModel.pageTitles}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/item_multi_head.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.rv_multi.MultiRecycleHeadViewModel" />
<variable
name="viewModel"
type="MultiRecycleHeadViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="160dp"
android:background="?android:selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
binding:onClickCommand="@{viewModel.itemClick}">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是头布局"
android:textColor="@color/textColor"
android:textSize="18sp" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/item_multi_rv_left.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.rv_multi.MultiRecycleLeftItemViewModel" />
<variable
name="viewModel"
type="MultiRecycleLeftItemViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DDDDDD"
android:orientation="vertical"
android:padding="10dp"
binding:onClickCommand="@{viewModel.itemClick}">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.text}"
android:textColor="@color/textColor" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/item_multi_rv_right.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.rv_multi.MultiRecycleRightItemViewModel" />
<variable
name="viewModel"
type="MultiRecycleRightItemViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#909090"
android:gravity="right"
android:orientation="vertical"
android:padding="10dp"
binding:onClickCommand="@{viewModel.itemClick}">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.text}"
android:textColor="@color/textColor" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/item_network.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.network.NetWorkItemViewModel" />
<variable
name="viewModel"
type="com.goldze.mvvmhabit.ui.network.NetWorkItemViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp"
binding:onClickCommand="@{viewModel.itemClick}"
binding:onLongClickCommand="@{viewModel.itemLongClick}">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@{viewModel.drawableImg}"
binding:url="@{viewModel.entity.img}" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:text="@{viewModel.entity.id == -1 ? viewModel.getPosition() + viewModel.entity.name : viewModel.entity.name}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/item_viewpager.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<import type="com.goldze.mvvmhabit.ui.viewpager.vm.ViewPagerItemViewModel" />
<variable
name="viewModel"
type="ViewPagerItemViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:selectableItemBackground"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:text="@{viewModel.text}"
binding:onClickCommand="@{viewModel.onItemClick}" />
</LinearLayout>
</layout>
================================================
FILE: app/src/main/res/layout/layout_toolbar.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="toolbarViewModel"
type="com.goldze.mvvmhabit.ui.base.viewmodel.ToolbarViewModel" />
</data>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/white"
binding:contentInsetStart="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="?selectableItemBackground"
android:padding="12dp"
android:src="@mipmap/back"
binding:onClickCommand="@{toolbarViewModel.backOnClick}" />
<TextView
android:id="@+id/tv_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:ellipsize="end"
android:gravity="center"
android:maxEms="12"
android:singleLine="true"
android:text="@{toolbarViewModel.titleText}"
android:textColor="@color/textColor"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_right_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="?selectableItemBackground"
android:gravity="center"
android:padding="12dp"
android:text="@{toolbarViewModel.rightText}"
android:textColor="@color/textColor"
android:textSize="18sp"
android:visibility="@{toolbarViewModel.rightTextVisibleObservable}"
binding:onClickCommand="@{toolbarViewModel.rightTextOnClick}" />
<ImageView
android:id="@+id/iv_right_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="?selectableItemBackground"
android:gravity="center"
android:padding="12dp"
android:src="@mipmap/toolbar_more"
android:visibility="@{toolbarViewModel.rightIconVisibleObservable}"
binding:onClickCommand="@{toolbarViewModel.rightIconOnClick}" />
<View
style="@style/ViewLineStyle"
android:layout_alignParentBottom="true" />
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</layout>
================================================
FILE: app/src/main/res/values/attrs.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TwinklingRefreshLayout">
<attr name="tr_wave_height" format="dimension" />
<attr name="tr_head_height" format="dimension" />
<attr name="tr_bottom_height" format="dimension" />
<attr name="tr_overscroll_height" format="dimension" />
<attr name="tr_enable_loadmore" format="boolean" />
<attr name="tr_pureScrollMode_on" format="boolean" />
<attr name="tr_show_overlay_refreshview" format="boolean" />
<attr name="tr_headerView" format="dimension" />
<attr name="tr_bottomView" format="dimension" />
<attr name="onRefreshCommand" format="reference" />
<attr name="onLoadMoreCommand" format="reference" />
</declare-styleable>
</resources>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="textColor">#202020</color>
<color name="textColorHint">#A0A0A0</color>
<color name="textColorVice">#6C6C6C</color>
<color name="viewLineColor">#F0F0F0</color>
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">MVVMHabit-sample</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!--将ActionBar隐藏,这里使用ToolBar-->
<item name="windowActionBar">false</item>
<!-- 使用 API Level 22以上编译的话,要拿掉前綴字 -->
<item name="windowNoTitle">true</item>
<!--colorPrimary 对应ToolBar的颜色-->
<item name="colorPrimary">@color/colorPrimary</item>
<!--colorPrimaryDark对应状态栏的颜色-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<!--colorAccent 对应EditText编辑时、RadioButton选中、CheckBox等选中时的颜色。-->
<item name="colorAccent">@color/colorPrimaryDark</item>
<item name="android:windowBackground">@color/white</item>
</style>
<style name="ViewLineStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">1dp</item>
<item name="android:background">@color/viewLineColor</item>
</style>
</resources>
================================================
FILE: app/src/main/res/xml/network_security_config.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
================================================
FILE: app/src/test/java/com/goldze/mvvmhabit/ExampleUnitTest.java
================================================
package com.goldze.mvvmhabit;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "config.gradle"
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: config.gradle
================================================
ext {
//android开发版本配置
android = [
compileSdkVersion: 28,
buildToolsVersion: "28.0.0",
applicationId : "com.goldze.mvvmhabit",
minSdkVersion : 15,
targetSdkVersion : 28,
versionCode : 1,
versionName : "1.0",
]
//version配置
versions = [
"support-version": "1.0.0",
"junit-version" : "4.12",
]
//support配置
support = [
'support-v4' : "androidx.legacy:legacy-support-v4:${versions["support-version"]}",
'appcompat-v7' : "androidx.appcompat:appcompat:${versions["support-version"]}",
'recyclerview-v7' : "androidx.recyclerview:recyclerview:${versions["support-version"]}",
'support-v13' : "androidx.legacy:legacy-support-v13:${versions["support-version"]}",
'support-fragment' : "androidx.fragment:fragment:${versions["support-version"]}",
'design'
gitextract_gppaw7p9/ ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── UpdateLog.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── goldze/ │ │ └── mvvmhabit/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── goldze/ │ │ │ └── mvvmhabit/ │ │ │ ├── app/ │ │ │ │ ├── AppApplication.java │ │ │ │ ├── AppViewModelFactory.java │ │ │ │ └── Injection.java │ │ │ ├── binding/ │ │ │ │ └── twinklingrefreshlayout/ │ │ │ │ └── ViewAdapter.java │ │ │ ├── data/ │ │ │ │ ├── DemoRepository.java │ │ │ │ └── source/ │ │ │ │ ├── HttpDataSource.java │ │ │ │ ├── LocalDataSource.java │ │ │ │ ├── http/ │ │ │ │ │ ├── HttpDataSourceImpl.java │ │ │ │ │ └── service/ │ │ │ │ │ └── DemoApiService.java │ │ │ │ └── local/ │ │ │ │ └── LocalDataSourceImpl.java │ │ │ ├── entity/ │ │ │ │ ├── DemoEntity.java │ │ │ │ ├── FormEntity.java │ │ │ │ └── SpinnerItemData.java │ │ │ ├── ui/ │ │ │ │ ├── base/ │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ └── BaseFragmentPagerAdapter.java │ │ │ │ │ ├── fragment/ │ │ │ │ │ │ └── BasePagerFragment.java │ │ │ │ │ └── viewmodel/ │ │ │ │ │ └── ToolbarViewModel.java │ │ │ │ ├── form/ │ │ │ │ │ ├── FormFragment.java │ │ │ │ │ └── FormViewModel.java │ │ │ │ ├── login/ │ │ │ │ │ ├── LoginActivity.java │ │ │ │ │ └── LoginViewModel.java │ │ │ │ ├── main/ │ │ │ │ │ ├── DemoActivity.java │ │ │ │ │ └── DemoViewModel.java │ │ │ │ ├── network/ │ │ │ │ │ ├── NetWorkFragment.java │ │ │ │ │ ├── NetWorkItemViewModel.java │ │ │ │ │ ├── NetWorkViewModel.java │ │ │ │ │ └── detail/ │ │ │ │ │ ├── DetailFragment.java │ │ │ │ │ └── DetailViewModel.java │ │ │ │ ├── rv_multi/ │ │ │ │ │ ├── MultiRecycleHeadViewModel.java │ │ │ │ │ ├── MultiRecycleLeftItemViewModel.java │ │ │ │ │ ├── MultiRecycleRightItemViewModel.java │ │ │ │ │ ├── MultiRecycleViewFragment.java │ │ │ │ │ └── MultiRecycleViewModel.java │ │ │ │ ├── tab_bar/ │ │ │ │ │ ├── activity/ │ │ │ │ │ │ └── TabBarActivity.java │ │ │ │ │ └── fragment/ │ │ │ │ │ ├── TabBar1Fragment.java │ │ │ │ │ ├── TabBar2Fragment.java │ │ │ │ │ ├── TabBar3Fragment.java │ │ │ │ │ └── TabBar4Fragment.java │ │ │ │ ├── viewpager/ │ │ │ │ │ ├── activity/ │ │ │ │ │ │ └── ViewPagerActivity.java │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ └── ViewPagerBindingAdapter.java │ │ │ │ │ └── vm/ │ │ │ │ │ ├── ViewPagerItemViewModel.java │ │ │ │ │ └── ViewPagerViewModel.java │ │ │ │ └── vp_frg/ │ │ │ │ └── ViewPagerGroupFragment.java │ │ │ └── utils/ │ │ │ ├── HttpsUtils.java │ │ │ └── RetrofitClient.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── login_clear_input.xml │ │ ├── layout/ │ │ │ ├── activity_demo.xml │ │ │ ├── activity_login.xml │ │ │ ├── activity_tab_bar.xml │ │ │ ├── fragment_base_pager.xml │ │ │ ├── fragment_detail.xml │ │ │ ├── fragment_form.xml │ │ │ ├── fragment_multi_rv.xml │ │ │ ├── fragment_network.xml │ │ │ ├── fragment_tab_bar_1.xml │ │ │ ├── fragment_tab_bar_2.xml │ │ │ ├── fragment_tab_bar_3.xml │ │ │ ├── fragment_tab_bar_4.xml │ │ │ ├── fragment_viewpager.xml │ │ │ ├── item_multi_head.xml │ │ │ ├── item_multi_rv_left.xml │ │ │ ├── item_multi_rv_right.xml │ │ │ ├── item_network.xml │ │ │ ├── item_viewpager.xml │ │ │ └── layout_toolbar.xml │ │ ├── values/ │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── xml/ │ │ └── network_security_config.xml │ └── test/ │ └── java/ │ └── com/ │ └── goldze/ │ └── mvvmhabit/ │ └── ExampleUnitTest.java ├── build.gradle ├── config.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── mvvmhabit/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── me/ │ │ └── goldze/ │ │ └── mvvmhabit/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── me/ │ │ │ └── goldze/ │ │ │ └── mvvmhabit/ │ │ │ ├── base/ │ │ │ │ ├── AppManager.java │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseApplication.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BaseModel.java │ │ │ │ ├── BaseViewModel.java │ │ │ │ ├── ContainerActivity.java │ │ │ │ ├── IBaseView.java │ │ │ │ ├── IBaseViewModel.java │ │ │ │ ├── IModel.java │ │ │ │ ├── ItemViewModel.java │ │ │ │ ├── MultiItemViewModel.java │ │ │ │ └── ViewModelFactory.java │ │ │ ├── binding/ │ │ │ │ ├── command/ │ │ │ │ │ ├── BindingAction.java │ │ │ │ │ ├── BindingCommand.java │ │ │ │ │ ├── BindingConsumer.java │ │ │ │ │ ├── BindingFunction.java │ │ │ │ │ └── ResponseCommand.java │ │ │ │ └── viewadapter/ │ │ │ │ ├── checkbox/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── edittext/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── image/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── listview/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── mswitch/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── radiogroup/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── recyclerview/ │ │ │ │ │ ├── DividerLine.java │ │ │ │ │ ├── LayoutManagers.java │ │ │ │ │ ├── LineManagers.java │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── scrollview/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── spinner/ │ │ │ │ │ ├── IKeyAndValue.java │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── swiperefresh/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── view/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── viewgroup/ │ │ │ │ │ ├── IBindingItemViewModel.java │ │ │ │ │ └── ViewAdapter.java │ │ │ │ ├── viewpager/ │ │ │ │ │ └── ViewAdapter.java │ │ │ │ └── webview/ │ │ │ │ └── ViewAdapter.java │ │ │ ├── bus/ │ │ │ │ ├── Messenger.java │ │ │ │ ├── RxBus.java │ │ │ │ ├── RxBusSubscriber.java │ │ │ │ ├── RxSubscriptions.java │ │ │ │ ├── WeakAction.java │ │ │ │ └── event/ │ │ │ │ ├── SingleLiveEvent.java │ │ │ │ └── SnackbarMessage.java │ │ │ ├── crash/ │ │ │ │ ├── CaocConfig.java │ │ │ │ ├── CaocInitProvider.java │ │ │ │ ├── CustomActivityOnCrash.java │ │ │ │ └── DefaultErrorActivity.java │ │ │ ├── http/ │ │ │ │ ├── ApiDisposableObserver.java │ │ │ │ ├── BaseResponse.java │ │ │ │ ├── DownLoadManager.java │ │ │ │ ├── ExceptionHandle.java │ │ │ │ ├── NetworkUtil.java │ │ │ │ ├── ResponseThrowable.java │ │ │ │ ├── cookie/ │ │ │ │ │ ├── CookieJarImpl.java │ │ │ │ │ └── store/ │ │ │ │ │ ├── CookieStore.java │ │ │ │ │ ├── MemoryCookieStore.java │ │ │ │ │ ├── PersistentCookieStore.java │ │ │ │ │ └── SerializableHttpCookie.java │ │ │ │ ├── download/ │ │ │ │ │ ├── DownLoadStateBean.java │ │ │ │ │ ├── DownLoadSubscriber.java │ │ │ │ │ ├── ProgressCallBack.java │ │ │ │ │ └── ProgressResponseBody.java │ │ │ │ └── interceptor/ │ │ │ │ ├── BaseInterceptor.java │ │ │ │ ├── CacheInterceptor.java │ │ │ │ ├── ProgressInterceptor.java │ │ │ │ └── logging/ │ │ │ │ ├── I.java │ │ │ │ ├── Level.java │ │ │ │ ├── Logger.java │ │ │ │ ├── LoggingInterceptor.java │ │ │ │ └── Printer.java │ │ │ ├── utils/ │ │ │ │ ├── CloseUtils.java │ │ │ │ ├── ConvertUtils.java │ │ │ │ ├── ImageUtils.java │ │ │ │ ├── KLog.java │ │ │ │ ├── MaterialDialogUtils.java │ │ │ │ ├── RegexUtils.java │ │ │ │ ├── RxUtils.java │ │ │ │ ├── SDCardUtils.java │ │ │ │ ├── SPUtils.java │ │ │ │ ├── StringUtils.java │ │ │ │ ├── ToastUtils.java │ │ │ │ ├── Utils.java │ │ │ │ ├── compression/ │ │ │ │ │ ├── Luban.java │ │ │ │ │ ├── OnCompressListener.java │ │ │ │ │ └── Preconditions.java │ │ │ │ └── constant/ │ │ │ │ ├── MemoryConstants.java │ │ │ │ ├── RegexConstants.java │ │ │ │ └── TimeConstants.java │ │ │ └── widget/ │ │ │ └── ControlDistributeLinearLayout.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_container.xml │ │ │ └── customactivityoncrash_default_error_activity.xml │ │ └── values/ │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ └── strings.xml │ └── test/ │ └── java/ │ └── me/ │ └── goldze/ │ └── mvvmhabit/ │ └── ExampleUnitTest.java └── settings.gradle
SYMBOL INDEX (1154 symbols across 138 files)
FILE: app/src/androidTest/java/com/goldze/mvvmhabit/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 19) | @Test
FILE: app/src/main/java/com/goldze/mvvmhabit/app/AppApplication.java
class AppApplication (line 16) | public class AppApplication extends BaseApplication {
method onCreate (line 17) | @Override
method initCrash (line 30) | private void initCrash() {
FILE: app/src/main/java/com/goldze/mvvmhabit/app/AppViewModelFactory.java
class AppViewModelFactory (line 18) | public class AppViewModelFactory extends ViewModelProvider.NewInstanceFa...
method getInstance (line 24) | public static AppViewModelFactory getInstance(Application application) {
method destroyInstance (line 35) | @VisibleForTesting
method AppViewModelFactory (line 40) | private AppViewModelFactory(Application application, DemoRepository re...
method create (line 45) | @NonNull
FILE: app/src/main/java/com/goldze/mvvmhabit/app/Injection.java
class Injection (line 16) | public class Injection {
method provideDemoRepository (line 17) | public static DemoRepository provideDemoRepository() {
FILE: app/src/main/java/com/goldze/mvvmhabit/binding/twinklingrefreshlayout/ViewAdapter.java
class ViewAdapter (line 14) | public class ViewAdapter {
method onRefreshAndLoadMoreCommand (line 16) | @BindingAdapter(value = {"onRefreshCommand", "onLoadMoreCommand"}, req...
FILE: app/src/main/java/com/goldze/mvvmhabit/data/DemoRepository.java
class DemoRepository (line 17) | public class DemoRepository extends BaseModel implements HttpDataSource,...
method DemoRepository (line 23) | private DemoRepository(@NonNull HttpDataSource httpDataSource,
method getInstance (line 29) | public static DemoRepository getInstance(HttpDataSource httpDataSource,
method destroyInstance (line 41) | @VisibleForTesting
method login (line 47) | @Override
method loadMore (line 52) | @Override
method demoGet (line 57) | @Override
method demoPost (line 62) | @Override
method saveUserName (line 67) | @Override
method savePassword (line 72) | @Override
method getUserName (line 77) | @Override
method getPassword (line 82) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/HttpDataSource.java
type HttpDataSource (line 11) | public interface HttpDataSource {
method login (line 13) | Observable<Object> login();
method loadMore (line 16) | Observable<DemoEntity> loadMore();
method demoGet (line 18) | Observable<BaseResponse<DemoEntity>> demoGet();
method demoPost (line 20) | Observable<BaseResponse<DemoEntity>> demoPost(String catalog);
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/LocalDataSource.java
type LocalDataSource (line 6) | public interface LocalDataSource {
method saveUserName (line 10) | void saveUserName(String userName);
method savePassword (line 16) | void savePassword(String password);
method getUserName (line 21) | String getUserName();
method getPassword (line 26) | String getPassword();
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/http/HttpDataSourceImpl.java
class HttpDataSourceImpl (line 19) | public class HttpDataSourceImpl implements HttpDataSource {
method getInstance (line 23) | public static HttpDataSourceImpl getInstance(DemoApiService apiService) {
method destroyInstance (line 34) | public static void destroyInstance() {
method HttpDataSourceImpl (line 38) | private HttpDataSourceImpl(DemoApiService apiService) {
method login (line 42) | @Override
method loadMore (line 47) | @Override
method demoGet (line 67) | @Override
method demoPost (line 72) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/http/service/DemoApiService.java
type DemoApiService (line 16) | public interface DemoApiService {
method demoGet (line 17) | @GET("action/apiv2/banner?catalog=1")
method demoPost (line 20) | @FormUrlEncoded
FILE: app/src/main/java/com/goldze/mvvmhabit/data/source/local/LocalDataSourceImpl.java
class LocalDataSourceImpl (line 11) | public class LocalDataSourceImpl implements LocalDataSource {
method getInstance (line 14) | public static LocalDataSourceImpl getInstance() {
method destroyInstance (line 25) | public static void destroyInstance() {
method LocalDataSourceImpl (line 29) | private LocalDataSourceImpl() {
method saveUserName (line 33) | @Override
method savePassword (line 38) | @Override
method getUserName (line 43) | @Override
method getPassword (line 48) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/DemoEntity.java
class DemoEntity (line 12) | public class DemoEntity {
method getNextPageToken (line 20) | public String getNextPageToken() {
method setNextPageToken (line 24) | public void setNextPageToken(String nextPageToken) {
method getPrevPageToken (line 28) | public String getPrevPageToken() {
method setPrevPageToken (line 32) | public void setPrevPageToken(String prevPageToken) {
method getRequestCount (line 36) | public int getRequestCount() {
method setRequestCount (line 40) | public void setRequestCount(int requestCount) {
method getResponseCount (line 44) | public int getResponseCount() {
method setResponseCount (line 48) | public void setResponseCount(int responseCount) {
method getTotalResults (line 52) | public int getTotalResults() {
method setTotalResults (line 56) | public void setTotalResults(int totalResults) {
method getItems (line 60) | public List<ItemsEntity> getItems() {
method setItems (line 64) | public void setItems(List<ItemsEntity> items) {
class ItemsEntity (line 68) | public static class ItemsEntity implements Parcelable{
method getDetail (line 77) | public String getDetail() {
method setDetail (line 81) | public void setDetail(String detail) {
method getHref (line 85) | public String getHref() {
method setHref (line 89) | public void setHref(String href) {
method getId (line 93) | public int getId() {
method setId (line 97) | public void setId(int id) {
method getImg (line 101) | public String getImg() {
method setImg (line 105) | public void setImg(String img) {
method getName (line 109) | public String getName() {
method setName (line 113) | public void setName(String name) {
method getPubDate (line 117) | public String getPubDate() {
method setPubDate (line 121) | public void setPubDate(String pubDate) {
method getType (line 125) | public int getType() {
method setType (line 129) | public void setType(int type) {
method describeContents (line 133) | @Override
method writeToParcel (line 138) | @Override
method ItemsEntity (line 149) | public ItemsEntity() {
method ItemsEntity (line 152) | protected ItemsEntity(Parcel in) {
method createFromParcel (line 163) | @Override
method newArray (line 168) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/FormEntity.java
class FormEntity (line 12) | public class FormEntity extends BaseObservable implements Parcelable {
method getId (line 20) | public String getId() {
method setId (line 24) | public void setId(String id) {
method getName (line 28) | public String getName() {
method setName (line 32) | public void setName(String name) {
method getSex (line 36) | public String getSex() {
method setSex (line 40) | public void setSex(String sex) {
method getBir (line 44) | public String getBir() {
method setBir (line 48) | public void setBir(String bir) {
method getHobby (line 52) | public String getHobby() {
method setHobby (line 56) | public void setHobby(String hobby) {
method FormEntity (line 60) | public FormEntity() {
method getMarry (line 63) | public Boolean getMarry() {
method setMarry (line 67) | public void setMarry(Boolean marry) {
method describeContents (line 71) | @Override
method writeToParcel (line 76) | @Override
method FormEntity (line 86) | protected FormEntity(Parcel in) {
method createFromParcel (line 96) | @Override
method newArray (line 101) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/entity/SpinnerItemData.java
class SpinnerItemData (line 11) | public class SpinnerItemData implements IKeyAndValue {
method SpinnerItemData (line 17) | public SpinnerItemData(String key, String value) {
method getKey (line 22) | @Override
method getValue (line 27) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/adapter/BaseFragmentPagerAdapter.java
class BaseFragmentPagerAdapter (line 14) | public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {
method BaseFragmentPagerAdapter (line 19) | public BaseFragmentPagerAdapter(FragmentManager fm, List<Fragment> lis...
method getItem (line 25) | @Override
method getCount (line 30) | @Override
method getPageTitle (line 36) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/fragment/BasePagerFragment.java
class BasePagerFragment (line 25) | public abstract class BasePagerFragment extends BaseFragment<FragmentBas...
method pagerFragment (line 30) | protected abstract List<Fragment> pagerFragment();
method pagerTitleString (line 32) | protected abstract List<String> pagerTitleString();
method initContentView (line 34) | @Override
method initVariableId (line 39) | @Override
method initData (line 44) | @Override
method initViewObservable (line 55) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/base/viewmodel/ToolbarViewModel.java
class ToolbarViewModel (line 22) | public class ToolbarViewModel<M extends BaseModel> extends BaseViewModel...
method ToolbarViewModel (line 34) | public ToolbarViewModel(@NonNull Application application) {
method ToolbarViewModel (line 38) | public ToolbarViewModel(@NonNull Application application, M model) {
method setTitleText (line 48) | public void setTitleText(String text) {
method setRightText (line 57) | public void setRightText(String text) {
method setRightTextVisible (line 66) | public void setRightTextVisible(int visibility) {
method setRightIconVisible (line 75) | public void setRightIconVisible(int visibility) {
method call (line 83) | @Override
method call (line 90) | @Override
method call (line 96) | @Override
method rightTextOnClick (line 105) | protected void rightTextOnClick() {
method rightIconOnClick (line 111) | protected void rightIconOnClick() {
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/form/FormFragment.java
class FormFragment (line 28) | public class FormFragment extends BaseFragment<FragmentFormBinding, Form...
method initParam (line 32) | @Override
method initContentView (line 41) | @Override
method initVariableId (line 46) | @Override
method initData (line 51) | @Override
method initViewObservable (line 61) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/form/FormViewModel.java
class FormViewModel (line 28) | public class FormViewModel extends ToolbarViewModel {
class UIChangeObservable (line 36) | public class UIChangeObservable {
method UIChangeObservable (line 40) | public UIChangeObservable() {
method FormViewModel (line 45) | public FormViewModel(@NonNull Application application) {
method onCreate (line 49) | @Override
method initToolbar (line 62) | public void initToolbar() {
method rightTextOnClick (line 74) | @Override
method setFormEntity (line 79) | public void setFormEntity(FormEntity entity) {
method call (line 87) | @Override
method call (line 94) | @Override
method call (line 102) | @Override
method call (line 109) | @Override
method setBir (line 116) | public void setBir(int year, int month, int dayOfMonth) {
method onDestroy (line 123) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginActivity.java
class LoginActivity (line 20) | public class LoginActivity extends BaseActivity<ActivityLoginBinding, Lo...
method initContentView (line 22) | @Override
method initVariableId (line 27) | @Override
method initViewModel (line 32) | @Override
method initViewObservable (line 39) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginViewModel.java
class LoginViewModel (line 27) | public class LoginViewModel extends BaseViewModel<DemoRepository> {
class UIChangeObservable (line 37) | public class UIChangeObservable {
method LoginViewModel (line 42) | public LoginViewModel(@NonNull Application application, DemoRepository...
method call (line 51) | @Override
method call (line 58) | @Override
method call (line 66) | @Override
method call (line 77) | @Override
method login (line 86) | private void login() {
method onDestroy (line 120) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoActivity.java
class DemoActivity (line 26) | public class DemoActivity extends BaseActivity<ActivityDemoBinding, Demo...
method initParam (line 27) | @Override
method initContentView (line 33) | @Override
method initVariableId (line 38) | @Override
method initViewObservable (line 43) | @Override
method requestCameraPermissions (line 64) | private void requestCameraPermissions() {
method downFile (line 80) | private void downFile(String url) {
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoViewModel.java
class DemoViewModel (line 24) | public class DemoViewModel extends BaseViewModel {
method DemoViewModel (line 30) | public DemoViewModel(@NonNull Application application) {
method call (line 36) | @Override
method call (line 43) | @Override
method call (line 50) | @Override
method call (line 57) | @Override
method call (line 64) | @Override
method call (line 71) | @Override
method call (line 78) | @Override
method call (line 95) | @Override
method call (line 103) | @Override
method call (line 111) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkFragment.java
class NetWorkFragment (line 29) | public class NetWorkFragment extends BaseFragment<FragmentNetworkBinding...
method initParam (line 30) | @Override
method initContentView (line 36) | @Override
method initVariableId (line 41) | @Override
method initViewModel (line 46) | @Override
method initData (line 53) | @Override
method initViewObservable (line 59) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkItemViewModel.java
class NetWorkItemViewModel (line 22) | public class NetWorkItemViewModel extends ItemViewModel<NetWorkViewModel> {
method NetWorkItemViewModel (line 26) | public NetWorkItemViewModel(@NonNull NetWorkViewModel viewModel, DemoE...
method getPosition (line 38) | public int getPosition() {
method call (line 44) | @Override
method call (line 59) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkViewModel.java
class NetWorkViewModel (line 31) | public class NetWorkViewModel extends BaseViewModel<DemoRepository> {
class UIChangeObservable (line 36) | public class UIChangeObservable {
method NetWorkViewModel (line 43) | public NetWorkViewModel(@NonNull Application application, DemoReposito...
method call (line 53) | @Override
method call (line 61) | @Override
method requestNetWork (line 96) | public void requestNetWork() {
method deleteItem (line 152) | public void deleteItem(NetWorkItemViewModel netWorkItemViewModel) {
method getItemPosition (line 163) | public int getItemPosition(NetWorkItemViewModel netWorkItemViewModel) {
method onDestroy (line 167) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailFragment.java
class DetailFragment (line 19) | public class DetailFragment extends BaseFragment<FragmentDetailBinding, ...
method initParam (line 23) | @Override
method initContentView (line 32) | @Override
method initVariableId (line 37) | @Override
method initData (line 42) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailViewModel.java
class DetailViewModel (line 15) | public class DetailViewModel extends BaseViewModel {
method DetailViewModel (line 18) | public DetailViewModel(@NonNull Application application) {
method setDemoEntity (line 22) | public void setDemoEntity(DemoEntity.ItemsEntity entity) {
method onDestroy (line 26) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleHeadViewModel.java
class MultiRecycleHeadViewModel (line 16) | public class MultiRecycleHeadViewModel extends MultiItemViewModel {
method MultiRecycleHeadViewModel (line 18) | public MultiRecycleHeadViewModel(@NonNull BaseViewModel viewModel) {
method call (line 24) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleLeftItemViewModel.java
class MultiRecycleLeftItemViewModel (line 17) | public class MultiRecycleLeftItemViewModel extends MultiItemViewModel<Mu...
method MultiRecycleLeftItemViewModel (line 20) | public MultiRecycleLeftItemViewModel(@NonNull MultiRecycleViewModel vi...
method call (line 27) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleRightItemViewModel.java
class MultiRecycleRightItemViewModel (line 17) | public class MultiRecycleRightItemViewModel extends MultiItemViewModel<M...
method MultiRecycleRightItemViewModel (line 20) | public MultiRecycleRightItemViewModel(@NonNull MultiRecycleViewModel v...
method call (line 27) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewFragment.java
class MultiRecycleViewFragment (line 21) | public class MultiRecycleViewFragment extends BaseFragment<FragmentMulti...
method initContentView (line 22) | @Override
method initVariableId (line 27) | @Override
method initData (line 32) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewModel.java
class MultiRecycleViewModel (line 22) | public class MultiRecycleViewModel extends BaseViewModel {
method MultiRecycleViewModel (line 27) | public MultiRecycleViewModel(@NonNull Application application) {
method onItemBind (line 57) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/activity/TabBarActivity.java
class TabBarActivity (line 30) | public class TabBarActivity extends BaseActivity<ActivityTabBarBinding, ...
method initContentView (line 33) | @Override
method initVariableId (line 38) | @Override
method initData (line 43) | @Override
method initFragment (line 51) | private void initFragment() {
method initBottomTab (line 61) | private void initBottomTab() {
method commitAllowingStateLoss (line 84) | private void commitAllowingStateLoss(int position) {
method hideAllFragment (line 98) | private void hideAllFragment() {
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar1Fragment.java
class TabBar1Fragment (line 17) | public class TabBar1Fragment extends BaseFragment {
method initContentView (line 18) | @Override
method initVariableId (line 23) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar2Fragment.java
class TabBar2Fragment (line 17) | public class TabBar2Fragment extends BaseFragment {
method initContentView (line 18) | @Override
method initVariableId (line 23) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar3Fragment.java
class TabBar3Fragment (line 17) | public class TabBar3Fragment extends BaseFragment{
method initContentView (line 18) | @Override
method initVariableId (line 23) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar4Fragment.java
class TabBar4Fragment (line 17) | public class TabBar4Fragment extends BaseFragment {
method initContentView (line 18) | @Override
method initVariableId (line 23) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/activity/ViewPagerActivity.java
class ViewPagerActivity (line 23) | public class ViewPagerActivity extends BaseActivity<FragmentViewpagerBin...
method initContentView (line 25) | @Override
method initVariableId (line 30) | @Override
method initData (line 36) | @Override
method initViewObservable (line 45) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/adapter/ViewPagerBindingAdapter.java
class ViewPagerBindingAdapter (line 15) | public class ViewPagerBindingAdapter extends BindingViewPagerAdapter<Vie...
method onBindBinding (line 17) | @Override
method destroyItem (line 24) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerItemViewModel.java
class ViewPagerItemViewModel (line 13) | public class ViewPagerItemViewModel extends ItemViewModel<ViewPagerViewM...
method ViewPagerItemViewModel (line 16) | public ViewPagerItemViewModel(@NonNull ViewPagerViewModel viewModel, S...
method call (line 22) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerViewModel.java
class ViewPagerViewModel (line 24) | public class ViewPagerViewModel extends BaseViewModel {
method ViewPagerViewModel (line 26) | public ViewPagerViewModel(@NonNull Application application) {
method getPageTitle (line 41) | @Override
method call (line 48) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/ui/vp_frg/ViewPagerGroupFragment.java
class ViewPagerGroupFragment (line 20) | public class ViewPagerGroupFragment extends BasePagerFragment {
method pagerFragment (line 21) | @Override
method pagerTitleString (line 31) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/utils/HttpsUtils.java
class HttpsUtils (line 38) | public class HttpsUtils {
class SSLParams (line 40) | public static class SSLParams {
method getSslSocketFactory (line 45) | public static SSLParams getSslSocketFactory() {
method getSslSocketFactory (line 53) | public static SSLParams getSslSocketFactory(X509TrustManager trustMana...
method getSslSocketFactory (line 61) | public static SSLParams getSslSocketFactory(InputStream... certificate...
method getSslSocketFactory (line 70) | public static SSLParams getSslSocketFactory(InputStream bksFile, Strin...
method getSslSocketFactory (line 79) | public static SSLParams getSslSocketFactory(InputStream bksFile, Strin...
method getSslSocketFactoryBase (line 83) | private static SSLParams getSslSocketFactoryBase(X509TrustManager trus...
method prepareKeyManager (line 115) | private static KeyManager[] prepareKeyManager(InputStream bksFile, Str...
method prepareTrustManager (line 129) | private static TrustManager[] prepareTrustManager(InputStream... certi...
method chooseTrustManager (line 161) | private static X509TrustManager chooseTrustManager(TrustManager[] trus...
method checkClientTrusted (line 175) | @Override
method checkServerTrusted (line 179) | @Override
method getAcceptedIssuers (line 183) | @Override
method verify (line 195) | @Override
FILE: app/src/main/java/com/goldze/mvvmhabit/utils/RetrofitClient.java
class RetrofitClient (line 36) | public class RetrofitClient {
class SingletonHolder (line 52) | private static class SingletonHolder {
method getInstance (line 56) | public static RetrofitClient getInstance() {
method RetrofitClient (line 60) | private RetrofitClient() {
method RetrofitClient (line 64) | private RetrofitClient(String url, Map<String, String> headers) {
method create (line 116) | public <T> T create(final Class<T> service) {
method execute (line 135) | public static <T> T execute(Observable<T> observable, Observer<T> subs...
FILE: app/src/test/java/com/goldze/mvvmhabit/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
FILE: mvvmhabit/src/androidTest/java/me/goldze/mvvmhabit/ExampleInstrumentedTest.java
class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
method useAppContext (line 19) | @Test
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/AppManager.java
class AppManager (line 13) | public class AppManager {
method AppManager (line 19) | private AppManager() {
method getAppManager (line 27) | public static AppManager getAppManager() {
method getActivityStack (line 34) | public static Stack<Activity> getActivityStack() {
method getFragmentStack (line 38) | public static Stack<Fragment> getFragmentStack() {
method addActivity (line 46) | public void addActivity(Activity activity) {
method removeActivity (line 56) | public void removeActivity(Activity activity) {
method isActivity (line 66) | public boolean isActivity() {
method currentActivity (line 76) | public Activity currentActivity() {
method finishActivity (line 84) | public void finishActivity() {
method finishActivity (line 92) | public void finishActivity(Activity activity) {
method finishActivity (line 103) | public void finishActivity(Class<?> cls) {
method finishAllActivity (line 115) | public void finishAllActivity() {
method getActivity (line 129) | public Activity getActivity(Class<?> cls) {
method addFragment (line 143) | public void addFragment(Fragment fragment) {
method removeFragment (line 153) | public void removeFragment(Fragment fragment) {
method isFragment (line 163) | public boolean isFragment() {
method currentFragment (line 173) | public Fragment currentFragment() {
method AppExit (line 185) | public void AppExit() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseActivity.java
class BaseActivity (line 30) | public abstract class BaseActivity<V extends ViewDataBinding, VM extends...
method onCreate (line 36) | @Override
method onDestroy (line 53) | @Override
method initViewDataBinding (line 69) | private void initViewDataBinding(Bundle savedInstanceState) {
method refreshLayout (line 96) | public void refreshLayout() {
method registorUIChangeLiveDataCallBack (line 107) | protected void registorUIChangeLiveDataCallBack() {
method showDialog (line 156) | public void showDialog(String title) {
method dismissDialog (line 166) | public void dismissDialog() {
method startActivity (line 177) | public void startActivity(Class<?> clz) {
method startActivity (line 187) | public void startActivity(Class<?> clz, Bundle bundle) {
method startContainerActivity (line 200) | public void startContainerActivity(String canonicalName) {
method startContainerActivity (line 210) | public void startContainerActivity(String canonicalName, Bundle bundle) {
method initParam (line 222) | @Override
method initContentView (line 232) | public abstract int initContentView(Bundle savedInstanceState);
method initVariableId (line 239) | public abstract int initVariableId();
method initViewModel (line 246) | public VM initViewModel() {
method initData (line 250) | @Override
method initViewObservable (line 255) | @Override
method createViewModel (line 267) | public <T extends ViewModel> T createViewModel(FragmentActivity activi...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseApplication.java
class BaseApplication (line 14) | public class BaseApplication extends Application {
method onCreate (line 17) | @Override
method setApplication (line 28) | public static synchronized void setApplication(@NonNull Application ap...
method getInstance (line 70) | public static Application getInstance() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseFragment.java
class BaseFragment (line 30) | public abstract class BaseFragment<V extends ViewDataBinding, VM extends...
method onCreate (line 36) | @Override
method onDestroy (line 42) | @Override
method onCreateView (line 47) | @Nullable
method onDestroyView (line 54) | @Override
method onViewCreated (line 67) | @Override
method initViewDataBinding (line 85) | private void initViewDataBinding() {
method registorUIChangeLiveDataCallBack (line 112) | protected void registorUIChangeLiveDataCallBack() {
method showDialog (line 161) | public void showDialog(String title) {
method dismissDialog (line 171) | public void dismissDialog() {
method startActivity (line 182) | public void startActivity(Class<?> clz) {
method startActivity (line 192) | public void startActivity(Class<?> clz, Bundle bundle) {
method startContainerActivity (line 205) | public void startContainerActivity(String canonicalName) {
method startContainerActivity (line 215) | public void startContainerActivity(String canonicalName, Bundle bundle) {
method refreshLayout (line 229) | public void refreshLayout() {
method initParam (line 235) | @Override
method initContentView (line 245) | public abstract int initContentView(LayoutInflater inflater, @Nullable...
method initVariableId (line 252) | public abstract int initVariableId();
method initViewModel (line 259) | public VM initViewModel() {
method initData (line 263) | @Override
method initViewObservable (line 268) | @Override
method isBackPressed (line 273) | public boolean isBackPressed() {
method createViewModel (line 284) | public <T extends ViewModel> T createViewModel(Fragment fragment, Clas...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseModel.java
class BaseModel (line 6) | public class BaseModel implements IModel {
method BaseModel (line 8) | public BaseModel() {
method onCleared (line 11) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseViewModel.java
class BaseViewModel (line 25) | public class BaseViewModel<M extends BaseModel> extends AndroidViewModel...
method BaseViewModel (line 33) | public BaseViewModel(@NonNull Application application) {
method BaseViewModel (line 37) | public BaseViewModel(@NonNull Application application, M model) {
method addSubscribe (line 43) | protected void addSubscribe(Disposable disposable) {
method injectLifecycleProvider (line 55) | public void injectLifecycleProvider(LifecycleProvider lifecycle) {
method getLifecycleProvider (line 59) | public LifecycleProvider getLifecycleProvider() {
method getUC (line 63) | public UIChangeLiveData getUC() {
method showDialog (line 70) | public void showDialog() {
method showDialog (line 74) | public void showDialog(String title) {
method dismissDialog (line 78) | public void dismissDialog() {
method startActivity (line 87) | public void startActivity(Class<?> clz) {
method startActivity (line 97) | public void startActivity(Class<?> clz, Bundle bundle) {
method startContainerActivity (line 111) | public void startContainerActivity(String canonicalName) {
method startContainerActivity (line 121) | public void startContainerActivity(String canonicalName, Bundle bundle) {
method finish (line 133) | public void finish() {
method onBackPressed (line 140) | public void onBackPressed() {
method onAny (line 144) | @Override
method onCreate (line 148) | @Override
method onDestroy (line 152) | @Override
method onStart (line 156) | @Override
method onStop (line 160) | @Override
method onResume (line 164) | @Override
method onPause (line 168) | @Override
method registerRxBus (line 172) | @Override
method removeRxBus (line 176) | @Override
method onCleared (line 180) | @Override
method accept (line 192) | @Override
class UIChangeLiveData (line 197) | public final class UIChangeLiveData extends SingleLiveEvent {
method getShowDialogEvent (line 205) | public SingleLiveEvent<String> getShowDialogEvent() {
method getDismissDialogEvent (line 209) | public SingleLiveEvent<Void> getDismissDialogEvent() {
method getStartActivityEvent (line 213) | public SingleLiveEvent<Map<String, Object>> getStartActivityEvent() {
method getStartContainerActivityEvent (line 217) | public SingleLiveEvent<Map<String, Object>> getStartContainerActivit...
method getFinishEvent (line 221) | public SingleLiveEvent<Void> getFinishEvent() {
method getOnBackPressedEvent (line 225) | public SingleLiveEvent<Void> getOnBackPressedEvent() {
method createLiveData (line 229) | private <T> SingleLiveEvent<T> createLiveData(SingleLiveEvent<T> liv...
method observe (line 236) | @Override
class ParameterField (line 242) | public static final class ParameterField {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ContainerActivity.java
class ContainerActivity (line 21) | public class ContainerActivity extends RxAppCompatActivity {
method onCreate (line 27) | @Override
method onSaveInstanceState (line 47) | @Override
method initFromIntent (line 53) | protected Fragment initFromIntent(Intent data) {
method onBackPressed (line 80) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IBaseView.java
type IBaseView (line 7) | public interface IBaseView {
method initParam (line 11) | void initParam();
method initData (line 15) | void initData();
method initViewObservable (line 20) | void initViewObservable();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IBaseViewModel.java
type IBaseViewModel (line 13) | public interface IBaseViewModel extends LifecycleObserver {
method onAny (line 15) | @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
method onCreate (line 18) | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
method onDestroy (line 21) | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
method onStart (line 24) | @OnLifecycleEvent(Lifecycle.Event.ON_START)
method onStop (line 27) | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
method onResume (line 30) | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
method onPause (line 33) | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
method registerRxBus (line 39) | void registerRxBus();
method removeRxBus (line 44) | void removeRxBus();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IModel.java
type IModel (line 6) | public interface IModel {
method onCleared (line 10) | void onCleared();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ItemViewModel.java
class ItemViewModel (line 11) | public class ItemViewModel<VM extends BaseViewModel> {
method ItemViewModel (line 14) | public ItemViewModel(@NonNull VM viewModel) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/MultiItemViewModel.java
class MultiItemViewModel (line 12) | public class MultiItemViewModel<VM extends BaseViewModel> extends ItemVi...
method getItemType (line 15) | public Object getItemType() {
method multiItemType (line 19) | public void multiItemType(@NonNull Object multiType) {
method MultiItemViewModel (line 23) | public MultiItemViewModel(@NonNull VM viewModel) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ViewModelFactory.java
class ViewModelFactory (line 16) | public class ViewModelFactory extends ViewModelProvider.NewInstanceFacto...
method getInstance (line 22) | public static ViewModelFactory getInstance(Application application) {
method ViewModelFactory (line 35) | private ViewModelFactory(Application application) {
method create (line 39) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingAction.java
type BindingAction (line 7) | public interface BindingAction {
method call (line 8) | void call();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingCommand.java
class BindingCommand (line 8) | public class BindingCommand<T> {
method BindingCommand (line 13) | public BindingCommand(BindingAction execute) {
method BindingCommand (line 20) | public BindingCommand(BindingConsumer<T> execute) {
method BindingCommand (line 28) | public BindingCommand(BindingAction execute, BindingFunction<Boolean> ...
method BindingCommand (line 37) | public BindingCommand(BindingConsumer<T> execute, BindingFunction<Bool...
method execute (line 45) | public void execute() {
method execute (line 56) | public void execute(T parameter) {
method canExecute0 (line 67) | private boolean canExecute0() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingConsumer.java
type BindingConsumer (line 8) | public interface BindingConsumer<T> {
method call (line 9) | void call(T t);
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingFunction.java
type BindingFunction (line 8) | public interface BindingFunction<T> {
method call (line 9) | T call();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/ResponseCommand.java
class ResponseCommand (line 9) | public class ResponseCommand<T, R> {
method ResponseCommand (line 20) | public ResponseCommand(BindingFunction<R> execute) {
method ResponseCommand (line 25) | public ResponseCommand(Function<T, R> execute) {
method ResponseCommand (line 30) | public ResponseCommand(BindingFunction<R> execute, BindingFunction<Boo...
method ResponseCommand (line 36) | public ResponseCommand(Function<T, R> execute, BindingFunction<Boolean...
method execute (line 42) | public R execute() {
method canExecute (line 49) | private boolean canExecute() {
method execute (line 57) | public R execute(T parameter) throws Exception {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/checkbox/ViewAdapter.java
class ViewAdapter (line 13) | public class ViewAdapter {
method setCheckedChanged (line 17) | @SuppressWarnings("unchecked")
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/edittext/ViewAdapter.java
class ViewAdapter (line 16) | public class ViewAdapter {
method requestFocusCommand (line 20) | @BindingAdapter(value = {"requestFocus"}, requireAll = false)
method addTextChangedListener (line 34) | @BindingAdapter(value = {"textChanged"}, requireAll = false)
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/image/ViewAdapter.java
class ViewAdapter (line 14) | public final class ViewAdapter {
method setImageUri (line 15) | @BindingAdapter(value = {"url", "placeholderRes"}, requireAll = false)
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/listview/ViewAdapter.java
class ViewAdapter (line 18) | public final class ViewAdapter {
method onScrollChangeCommand (line 20) | @SuppressWarnings("unchecked")
method onItemClickCommand (line 47) | @BindingAdapter(value = {"onItemClickCommand"}, requireAll = false)
method onLoadMoreCommand (line 60) | @BindingAdapter({"onLoadMoreCommand"})
class OnScrollListener (line 66) | public static class OnScrollListener implements AbsListView.OnScrollLi...
method OnScrollListener (line 71) | public OnScrollListener(ListView listView, final BindingCommand<Inte...
method onScrollStateChanged (line 83) | @Override
method onScroll (line 88) | @Override
class ListViewScrollDataWrapper (line 101) | public static class ListViewScrollDataWrapper {
method ListViewScrollDataWrapper (line 107) | public ListViewScrollDataWrapper(int scrollState, int firstVisibleIt...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/mswitch/ViewAdapter.java
class ViewAdapter (line 13) | public class ViewAdapter {
method setSwitchState (line 19) | @BindingAdapter("switchState")
method onCheckedChangeCommand (line 30) | @BindingAdapter("onCheckedChangeCommand")
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/radiogroup/ViewAdapter.java
class ViewAdapter (line 13) | public class ViewAdapter {
method onCheckedChangedCommand (line 14) | @BindingAdapter(value = {"onCheckedChangedCommand"}, requireAll = false)
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/DividerLine.java
class DividerLine (line 15) | public class DividerLine extends RecyclerView.ItemDecoration {
type LineDrawMode (line 31) | public enum LineDrawMode {
method DividerLine (line 35) | public DividerLine(Context context) {
method DividerLine (line 43) | public DividerLine(Context context, LineDrawMode mode) {
method DividerLine (line 48) | public DividerLine(Context context, int dividerSize, LineDrawMode mode) {
method getDividerSize (line 53) | public int getDividerSize() {
method setDividerSize (line 57) | public void setDividerSize(int dividerSize) {
method getMode (line 61) | public LineDrawMode getMode() {
method setMode (line 65) | public void setMode(LineDrawMode mode) {
method onDrawOver (line 77) | @Override
method drawVertical (line 104) | private void drawVertical(Canvas c, RecyclerView parent, RecyclerView....
method drawHorizontal (line 126) | private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerVie...
method getItemOffsets (line 147) | @Override
method dip2px (line 160) | public static int dip2px(Context context, float dipValue) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/LayoutManagers.java
class LayoutManagers (line 16) | public class LayoutManagers {
method LayoutManagers (line 17) | protected LayoutManagers() {
type LayoutManagerFactory (line 20) | public interface LayoutManagerFactory {
method create (line 21) | RecyclerView.LayoutManager create(RecyclerView recyclerView);
method linear (line 27) | public static LayoutManagerFactory linear() {
method linear (line 39) | public static LayoutManagerFactory linear(@Orientation final int orien...
method grid (line 51) | public static LayoutManagerFactory grid(final int spanCount) {
method grid (line 63) | public static LayoutManagerFactory grid(final int spanCount, @Orientat...
method staggeredGrid (line 75) | public static LayoutManagerFactory staggeredGrid(final int spanCount, ...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/LineManagers.java
class LineManagers (line 8) | public class LineManagers {
method LineManagers (line 9) | protected LineManagers() {
type LineManagerFactory (line 12) | public interface LineManagerFactory {
method create (line 13) | RecyclerView.ItemDecoration create(RecyclerView recyclerView);
method both (line 17) | public static LineManagerFactory both() {
method horizontal (line 26) | public static LineManagerFactory horizontal() {
method vertical (line 35) | public static LineManagerFactory vertical() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/ViewAdapter.java
class ViewAdapter (line 15) | public class ViewAdapter {
method setLineManager (line 17) | @BindingAdapter("lineManager")
method setLayoutManager (line 22) | @BindingAdapter("layoutManager")
method onScrollChangeCommand (line 27) | @BindingAdapter(value = {"onScrollChangeCommand", "onScrollStateChange...
method onLoadMoreCommand (line 54) | @SuppressWarnings("unchecked")
method setItemAnimator (line 62) | @BindingAdapter("itemAnimator")
class OnScrollListener (line 67) | public static class OnScrollListener extends RecyclerView.OnScrollList...
method OnScrollListener (line 73) | public OnScrollListener(final BindingCommand<Integer> onLoadMoreComm...
method onScrolled (line 84) | @Override
method onScrollStateChanged (line 97) | @Override
class ScrollDataWrapper (line 105) | public static class ScrollDataWrapper {
method ScrollDataWrapper (line 110) | public ScrollDataWrapper(float scrollX, float scrollY, int state) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/scrollview/ViewAdapter.java
class ViewAdapter (line 13) | public final class ViewAdapter {
method onScrollChangeCommand (line 15) | @SuppressWarnings("unchecked")
method onScrollChangeCommand (line 28) | @SuppressWarnings("unchecked")
class ScrollDataWrapper (line 41) | public static class ScrollDataWrapper {
method ScrollDataWrapper (line 45) | public ScrollDataWrapper(float scrollX, float scrollY) {
class NestScrollDataWrapper (line 51) | public static class NestScrollDataWrapper {
method NestScrollDataWrapper (line 57) | public NestScrollDataWrapper(int scrollX, int scrollY, int oldScroll...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/spinner/IKeyAndValue.java
type IKeyAndValue (line 7) | public interface IKeyAndValue {
method getKey (line 8) | String getKey();
method getValue (line 10) | String getValue();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/spinner/ViewAdapter.java
class ViewAdapter (line 18) | public class ViewAdapter {
method onItemSelectedCommand (line 27) | @BindingAdapter(value = {"itemDatas", "valueReply", "resource", "dropD...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/swiperefresh/ViewAdapter.java
class ViewAdapter (line 11) | public class ViewAdapter {
method onRefreshCommand (line 13) | @BindingAdapter({"onRefreshCommand"})
method setRefreshing (line 26) | @BindingAdapter({"refreshing"})
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/view/ViewAdapter.java
class ViewAdapter (line 17) | public class ViewAdapter {
method onClickCommand (line 27) | @BindingAdapter(value = {"onClickCommand", "isThrottleFirst"}, require...
method onLongClickCommand (line 56) | @BindingAdapter(value = {"onLongClickCommand"}, requireAll = false)
method replyCurrentView (line 75) | @BindingAdapter(value = {"currentView"}, requireAll = false)
method requestFocusCommand (line 85) | @BindingAdapter({"requestFocus"})
method onFocusChangeCommand (line 98) | @BindingAdapter({"onFocusChangeCommand"})
method isVisible (line 113) | @BindingAdapter(value = {"isVisible"}, requireAll = false)
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewgroup/IBindingItemViewModel.java
type IBindingItemViewModel (line 8) | public interface IBindingItemViewModel<V extends ViewDataBinding> {
method injecDataBinding (line 9) | void injecDataBinding(V binding);
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewgroup/ViewAdapter.java
class ViewAdapter (line 15) | public final class ViewAdapter {
method addViews (line 17) | @BindingAdapter({"itemView", "observableList"})
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewpager/ViewAdapter.java
class ViewAdapter (line 10) | public class ViewAdapter {
method onScrollChangeCommand (line 11) | @BindingAdapter(value = {"onPageScrolledCommand", "onPageSelectedComma...
class ViewPagerDataWrapper (line 44) | public static class ViewPagerDataWrapper {
method ViewPagerDataWrapper (line 50) | public ViewPagerDataWrapper(float position, float positionOffset, in...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/webview/ViewAdapter.java
class ViewAdapter (line 11) | public class ViewAdapter {
method loadHtml (line 12) | @BindingAdapter({"render"})
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/Messenger.java
class Messenger (line 16) | public class Messenger {
method getDefault (line 24) | public static Messenger getDefault() {
method overrideDefault (line 32) | public static void overrideDefault(Messenger newWeakMessenger) {
method reset (line 36) | public static void reset() {
method register (line 46) | public void register(Object recipient, BindingAction action) {
method register (line 57) | public void register(Object recipient, boolean receiveDerivedMessagesT...
method register (line 70) | public void register(Object recipient, Object token, BindingAction act...
method register (line 84) | public void register(Object recipient, Object token, boolean receiveDe...
method register (line 126) | public <T> void register(Object recipient, Class<T> tClass, BindingCon...
method register (line 139) | public <T> void register(Object recipient, boolean receiveDerivedMessa...
method register (line 154) | public <T> void register(Object recipient, Object token, Class<T> tCla...
method register (line 170) | public <T> void register(Object recipient, Object token, boolean recei...
method cleanup (line 207) | private void cleanup() {
method sendNoMsg (line 216) | public void sendNoMsg(Object token) {
method sendNoMsgToTarget (line 227) | public void sendNoMsgToTarget(Object target) {
method sendNoMsgToTargetWithToken (line 241) | public void sendNoMsgToTargetWithToken(Object token, Object target) {
method send (line 251) | public <T> void send(T message) {
method send (line 263) | public <T> void send(T message, Object token) {
method sendToTarget (line 277) | public <T, R> void sendToTarget(T message, R target) {
method unregister (line 289) | public void unregister(Object recipient) {
method unregister (line 296) | public <T> void unregister(Object recipient, Object token) {
method sendToList (line 303) | private static <T> void sendToList(
method unregisterFromLists (line 330) | private static void unregisterFromLists(Object recipient, HashMap<Type...
method unregisterFromLists (line 351) | private static <T> void unregisterFromLists(
method unregisterFromLists (line 379) | private static void unregisterFromLists(
method unregisterFromLists (line 408) | private static <T> void unregisterFromLists(
method unregisterFromLists (line 438) | private static void unregisterFromLists(
method classImplements (line 468) | private static boolean classImplements(Type instanceType, Type interfa...
method cleanupList (line 483) | private static void cleanupList(HashMap<Type, List<WeakActionAndToken>...
method sendToTargetOrType (line 504) | private void sendToTargetOrType(Type messageTargetType, Object token) {
method sendToList (line 535) | private static void sendToList(
method sendToTargetOrType (line 561) | private <T> void sendToTargetOrType(T message, Type messageTargetType,...
class WeakActionAndToken (line 594) | private class WeakActionAndToken {
method WeakActionAndToken (line 598) | public WeakActionAndToken(WeakAction action, Object token) {
method getAction (line 603) | public WeakAction getAction() {
method setAction (line 607) | public void setAction(WeakAction action) {
method getToken (line 611) | public Object getToken() {
method setToken (line 615) | public void setToken(Object token) {
class NotMsgType (line 620) | public static class NotMsgType {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxBus.java
class RxBus (line 16) | public class RxBus {
method RxBus (line 22) | public RxBus() {
method getDefault (line 27) | public static RxBus getDefault() {
method post (line 41) | public void post(Object event) {
method toObservable (line 48) | public <T> Observable<T> toObservable(Class<T> eventType) {
method hasObservers (line 55) | public boolean hasObservers() {
method reset (line 59) | public void reset() {
method postSticky (line 70) | public void postSticky(Object event) {
method toObservableSticky (line 80) | public <T> Observable<T> toObservableSticky(final Class<T> eventType) {
method getStickyEvent (line 101) | public <T> T getStickyEvent(Class<T> eventType) {
method removeStickyEvent (line 110) | public <T> T removeStickyEvent(Class<T> eventType) {
method removeAllStickyEvents (line 119) | public void removeAllStickyEvents() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxBusSubscriber.java
class RxBusSubscriber (line 8) | public abstract class RxBusSubscriber<T> extends DisposableObserver<T> {
method onNext (line 10) | @Override
method onComplete (line 19) | @Override
method onError (line 23) | @Override
method onEvent (line 28) | protected abstract void onEvent(T t);
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxSubscriptions.java
class RxSubscriptions (line 9) | public class RxSubscriptions {
method isDisposed (line 12) | public static boolean isDisposed() {
method add (line 16) | public static void add(Disposable s) {
method remove (line 22) | public static void remove(Disposable s) {
method clear (line 28) | public static void clear() {
method dispose (line 32) | public static void dispose() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/WeakAction.java
class WeakAction (line 12) | public class WeakAction<T> {
method WeakAction (line 19) | public WeakAction(Object target, BindingAction action) {
method WeakAction (line 25) | public WeakAction(Object target, BindingConsumer<T> consumer) {
method execute (line 30) | public void execute() {
method execute (line 36) | public void execute(T parameter) {
method markForDeletion (line 43) | public void markForDeletion() {
method getBindingAction (line 50) | public BindingAction getBindingAction() {
method getBindingConsumer (line 54) | public BindingConsumer getBindingConsumer() {
method isLive (line 58) | public boolean isLive() {
method getTarget (line 69) | public Object getTarget() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/event/SingleLiveEvent.java
class SingleLiveEvent (line 40) | public class SingleLiveEvent<T> extends MutableLiveData<T> {
method observe (line 45) | @MainThread
method setValue (line 63) | @MainThread
method call (line 72) | @MainThread
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/event/SnackbarMessage.java
class SnackbarMessage (line 30) | public class SnackbarMessage extends SingleLiveEvent<Integer> {
method observe (line 32) | public void observe(LifecycleOwner owner, final SnackbarObserver obser...
type SnackbarObserver (line 44) | public interface SnackbarObserver {
method onNewMessage (line 49) | void onNewMessage(@StringRes int snackbarMessageResourceId);
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CaocConfig.java
class CaocConfig (line 32) | public class CaocConfig implements Serializable {
method getBackgroundMode (line 55) | @BackgroundMode
method setBackgroundMode (line 60) | public void setBackgroundMode(@BackgroundMode int backgroundMode) {
method isEnabled (line 64) | public boolean isEnabled() {
method setEnabled (line 68) | public void setEnabled(boolean enabled) {
method isShowErrorDetails (line 72) | public boolean isShowErrorDetails() {
method setShowErrorDetails (line 76) | public void setShowErrorDetails(boolean showErrorDetails) {
method isShowRestartButton (line 80) | public boolean isShowRestartButton() {
method setShowRestartButton (line 84) | public void setShowRestartButton(boolean showRestartButton) {
method isTrackActivities (line 88) | public boolean isTrackActivities() {
method setTrackActivities (line 92) | public void setTrackActivities(boolean trackActivities) {
method getMinTimeBetweenCrashesMs (line 96) | public int getMinTimeBetweenCrashesMs() {
method setMinTimeBetweenCrashesMs (line 100) | public void setMinTimeBetweenCrashesMs(int minTimeBetweenCrashesMs) {
method getErrorDrawable (line 104) | @Nullable
method setErrorDrawable (line 110) | public void setErrorDrawable(@Nullable @DrawableRes Integer errorDrawa...
method getErrorActivityClass (line 114) | @Nullable
method setErrorActivityClass (line 119) | public void setErrorActivityClass(@Nullable Class<? extends Activity> ...
method getRestartActivityClass (line 123) | @Nullable
method setRestartActivityClass (line 128) | public void setRestartActivityClass(@Nullable Class<? extends Activity...
method getEventListener (line 132) | @Nullable
method setEventListener (line 137) | public void setEventListener(@Nullable CustomActivityOnCrash.EventList...
class Builder (line 141) | public static class Builder {
method create (line 144) | @NonNull
method backgroundMode (line 173) | @NonNull
method enabled (line 185) | @NonNull
method showErrorDetails (line 197) | @NonNull
method showRestartButton (line 211) | @NonNull
method trackActivities (line 222) | @NonNull
method minTimeBetweenCrashesMs (line 234) | @NonNull
method errorDrawable (line 245) | @NonNull
method errorActivity (line 255) | @NonNull
method restartActivity (line 266) | @NonNull
method eventListener (line 280) | @NonNull
method get (line 290) | @NonNull
method apply (line 295) | public void apply() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CaocInitProvider.java
class CaocInitProvider (line 28) | public class CaocInitProvider extends ContentProvider {
method onCreate (line 30) | public boolean onCreate() {
method query (line 35) | @Nullable
method getType (line 41) | @Nullable
method insert (line 47) | @Nullable
method delete (line 53) | @Override
method update (line 58) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CustomActivityOnCrash.java
class CustomActivityOnCrash (line 51) | public final class CustomActivityOnCrash {
method install (line 86) | @RestrictTo(RestrictTo.Scope.LIBRARY)
method getStackTraceFromIntent (line 265) | @NonNull
method getConfigFromIntent (line 276) | @NonNull
method getActivityLogFromIntent (line 287) | @Nullable
method getAllErrorDetailsFromIntent (line 299) | @NonNull
method restartApplicationWithIntent (line 346) | public static void restartApplicationWithIntent(@NonNull Activity acti...
method restartApplication (line 365) | public static void restartApplication(@NonNull Activity activity, @Non...
method closeApplication (line 378) | public static void closeApplication(@NonNull Activity activity, @NonNu...
method getConfig (line 394) | @RestrictTo(RestrictTo.Scope.LIBRARY)
method setConfig (line 406) | @RestrictTo(RestrictTo.Scope.LIBRARY)
method isStackTraceLikelyConflictive (line 420) | private static boolean isStackTraceLikelyConflictive(@NonNull Throwabl...
method getBuildDateAsString (line 439) | @Nullable
method getVersionName (line 469) | @NonNull
method getDeviceModelName (line 485) | @NonNull
method capitalize (line 502) | @NonNull
method guessRestartActivityClass (line 524) | @Nullable
method getRestartActivityClassWithIntentFilter (line 546) | @SuppressWarnings("unchecked")
method getLauncherActivity (line 573) | @SuppressWarnings("unchecked")
method guessErrorActivityClass (line 597) | @NonNull
method getErrorActivityClassWithIntentFilter (line 619) | @SuppressWarnings("unchecked")
method killCurrentProcess (line 643) | private static void killCurrentProcess() {
method setLastCrashTimestamp (line 653) | @SuppressLint("ApplySharedPref") //This must be done immediately since...
method getLastCrashTimestamp (line 663) | private static long getLastCrashTimestamp(@NonNull Context context) {
method hasCrashedInTheLastSeconds (line 673) | private static boolean hasCrashedInTheLastSeconds(@NonNull Context con...
type EventListener (line 684) | public interface EventListener extends Serializable {
method onLaunchErrorActivity (line 685) | void onLaunchErrorActivity();
method onRestartAppFromErrorActivity (line 687) | void onRestartAppFromErrorActivity();
method onCloseAppFromErrorActivity (line 689) | void onCloseAppFromErrorActivity();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/DefaultErrorActivity.java
class DefaultErrorActivity (line 39) | public final class DefaultErrorActivity extends AppCompatActivity {
method onCreate (line 41) | @SuppressLint("PrivateResource")
method copyErrorToClipboard (line 118) | private void copyErrorToClipboard() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ApiDisposableObserver.java
class ApiDisposableObserver (line 14) | public abstract class ApiDisposableObserver<T> extends DisposableObserve...
method onResult (line 15) | public abstract void onResult(T t);
method onComplete (line 17) | @Override
method onError (line 22) | @Override
method onStart (line 34) | @Override
method onNext (line 45) | @Override
class CodeRule (line 98) | public static final class CodeRule {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/BaseResponse.java
class BaseResponse (line 7) | public class BaseResponse<T> {
method getCode (line 12) | public int getCode() {
method setCode (line 16) | public void setCode(int code) {
method getResult (line 20) | public T getResult() {
method setResult (line 24) | public void setResult(T result) {
method isOk (line 28) | public boolean isOk() {
method getMessage (line 32) | public String getMessage() {
method setMessage (line 36) | public void setMessage(String message) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/DownLoadManager.java
class DownLoadManager (line 25) | public class DownLoadManager {
method DownLoadManager (line 30) | private DownLoadManager() {
method getInstance (line 39) | public static DownLoadManager getInstance() {
method load (line 47) | public void load(String downUrl, final ProgressCallBack callBack) {
method buildNetWork (line 62) | private void buildNetWork() {
type ApiService (line 75) | private interface ApiService {
method download (line 76) | @Streaming
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ExceptionHandle.java
class ExceptionHandle (line 19) | public class ExceptionHandle {
method handleException (line 28) | public static ResponseThrowable handleException(Throwable e) {
class ERROR (line 94) | class ERROR {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/NetworkUtil.java
class NetworkUtil (line 16) | public class NetworkUtil {
method isNetworkAvailable (line 30) | public static boolean isNetworkAvailable(Context context) {
method getLocalIpAddress (line 45) | public static String getLocalIpAddress() {
method getNetState (line 69) | public static int getNetState(Context context) {
method connectionNetwork (line 96) | static private boolean connectionNetwork() {
method is3G (line 120) | public static boolean is3G(Context context) {
method isWifi (line 136) | public static boolean isWifi(Context context) {
method is2G (line 152) | public static boolean is2G(Context context) {
method isWifiEnabled (line 168) | public static boolean isWifiEnabled(Context context) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ResponseThrowable.java
class ResponseThrowable (line 7) | public class ResponseThrowable extends Exception {
method ResponseThrowable (line 11) | public ResponseThrowable(Throwable throwable, int code) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/CookieJarImpl.java
class CookieJarImpl (line 14) | public class CookieJarImpl implements CookieJar {
method CookieJarImpl (line 18) | public CookieJarImpl(CookieStore cookieStore) {
method saveFromResponse (line 25) | @Override
method loadForRequest (line 30) | @Override
method getCookieStore (line 35) | public CookieStore getCookieStore() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/CookieStore.java
type CookieStore (line 11) | public interface CookieStore {
method saveCookie (line 14) | void saveCookie(HttpUrl url, List<Cookie> cookie);
method saveCookie (line 17) | void saveCookie(HttpUrl url, Cookie cookie);
method loadCookie (line 20) | List<Cookie> loadCookie(HttpUrl url);
method getAllCookie (line 23) | List<Cookie> getAllCookie();
method getCookie (line 26) | List<Cookie> getCookie(HttpUrl url);
method removeCookie (line 29) | boolean removeCookie(HttpUrl url, Cookie cookie);
method removeCookie (line 32) | boolean removeCookie(HttpUrl url);
method removeAllCookie (line 35) | boolean removeAllCookie();
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/MemoryCookieStore.java
class MemoryCookieStore (line 14) | public class MemoryCookieStore implements CookieStore {
method saveCookie (line 18) | @Override
method saveCookie (line 33) | @Override
method loadCookie (line 46) | @Override
method getAllCookie (line 56) | @Override
method getCookie (line 66) | @Override
method removeCookie (line 74) | @Override
method removeCookie (line 80) | @Override
method removeAllCookie (line 85) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/PersistentCookieStore.java
class PersistentCookieStore (line 28) | public class PersistentCookieStore implements CookieStore {
method PersistentCookieStore (line 37) | public PersistentCookieStore(Context context) {
method getCookieToken (line 62) | private String getCookieToken(Cookie cookie) {
method isCookieExpired (line 67) | private static boolean isCookieExpired(Cookie cookie) {
method loadCookie (line 72) | @Override
method saveCookie (line 89) | @Override
method saveCookie (line 104) | @Override
method saveCookie (line 123) | private void saveCookie(HttpUrl url, Cookie cookie, String name) {
method removeCookie (line 134) | @Override
method removeCookie (line 153) | @Override
method removeAllCookie (line 173) | @Override
method getAllCookie (line 182) | @Override
method getCookie (line 190) | @Override
method encodeCookie (line 204) | private String encodeCookie(SerializableHttpCookie cookie) {
method decodeCookie (line 223) | private Cookie decodeCookie(String cookieString) {
method byteArrayToHexString (line 244) | private String byteArrayToHexString(byte[] bytes) {
method hexStringToByteArray (line 262) | private byte[] hexStringToByteArray(String hexString) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/SerializableHttpCookie.java
class SerializableHttpCookie (line 10) | public class SerializableHttpCookie implements Serializable {
method SerializableHttpCookie (line 16) | public SerializableHttpCookie(Cookie cookie) {
method getCookie (line 20) | public Cookie getCookie() {
method writeObject (line 28) | private void writeObject(ObjectOutputStream out) throws IOException {
method readObject (line 40) | private void readObject(ObjectInputStream in) throws IOException, Clas...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/DownLoadStateBean.java
class DownLoadStateBean (line 12) | public class DownLoadStateBean implements Serializable, Parcelable {
method DownLoadStateBean (line 17) | public DownLoadStateBean(long total, long bytesLoaded) {
method DownLoadStateBean (line 22) | public DownLoadStateBean(long total, long bytesLoaded, String tag) {
method getTotal (line 28) | public long getTotal() {
method setTotal (line 32) | public void setTotal(long total) {
method getBytesLoaded (line 36) | public long getBytesLoaded() {
method setBytesLoaded (line 40) | public void setBytesLoaded(long bytesLoaded) {
method getTag (line 44) | public String getTag() {
method setTag (line 48) | public void setTag(String tag) {
method describeContents (line 52) | @Override
method writeToParcel (line 57) | @Override
method DownLoadStateBean (line 64) | protected DownLoadStateBean(Parcel in) {
method createFromParcel (line 71) | @Override
method newArray (line 76) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/DownLoadSubscriber.java
class DownLoadSubscriber (line 9) | public class DownLoadSubscriber<T> extends DisposableObserver<T> {
method DownLoadSubscriber (line 12) | public DownLoadSubscriber(ProgressCallBack fileCallBack) {
method onStart (line 16) | @Override
method onComplete (line 23) | @Override
method onError (line 29) | @Override
method onNext (line 35) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/ProgressCallBack.java
class ProgressCallBack (line 22) | public abstract class ProgressCallBack<T> {
method ProgressCallBack (line 28) | public ProgressCallBack(String destFileDir, String destFileName) {
method onSuccess (line 34) | public abstract void onSuccess(T t);
method progress (line 36) | public abstract void progress(long progress, long total);
method onStart (line 38) | public void onStart() {
method onCompleted (line 41) | public void onCompleted() {
method onError (line 44) | public abstract void onError(Throwable e);
method saveFile (line 46) | public void saveFile(ResponseBody body) {
method subscribeLoadProgress (line 82) | public void subscribeLoadProgress() {
method unsubscribe (line 98) | public void unsubscribe() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/ProgressResponseBody.java
class ProgressResponseBody (line 18) | public class ProgressResponseBody extends ResponseBody {
method ProgressResponseBody (line 24) | public ProgressResponseBody(ResponseBody responseBody) {
method ProgressResponseBody (line 28) | public ProgressResponseBody(ResponseBody responseBody, String tag) {
method contentType (line 33) | @Override
method contentLength (line 38) | @Override
method source (line 43) | @Override
method source (line 51) | private Source source(Source source) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/BaseInterceptor.java
class BaseInterceptor (line 14) | public class BaseInterceptor implements Interceptor {
method BaseInterceptor (line 17) | public BaseInterceptor(Map<String, String> headers) {
method intercept (line 21) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/CacheInterceptor.java
class CacheInterceptor (line 17) | public class CacheInterceptor implements Interceptor {
method CacheInterceptor (line 21) | public CacheInterceptor(Context context) {
method intercept (line 25) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/ProgressInterceptor.java
class ProgressInterceptor (line 13) | public class ProgressInterceptor implements Interceptor {
method intercept (line 15) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/I.java
class I (line 11) | class I {
method I (line 13) | protected I() {
method log (line 17) | static void log(int type, String tag, String msg) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Level.java
type Level (line 7) | public enum Level {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Logger.java
type Logger (line 8) | @SuppressWarnings({"WeakerAccess", "unused"})
method log (line 10) | void log(int level, String tag, String msg);
method log (line 13) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/LoggingInterceptor.java
class LoggingInterceptor (line 24) | public class LoggingInterceptor implements Interceptor {
method LoggingInterceptor (line 29) | private LoggingInterceptor(Builder builder) {
method intercept (line 34) | @Override
class Builder (line 107) | @SuppressWarnings("unused")
method Builder (line 119) | public Builder() {
method getType (line 123) | int getType() {
method getLevel (line 127) | Level getLevel() {
method getHeaders (line 131) | Headers getHeaders() {
method getTag (line 135) | String getTag(boolean isRequest) {
method getLogger (line 143) | Logger getLogger() {
method addHeader (line 153) | public Builder addHeader(String name, String value) {
method setLevel (line 163) | public Builder setLevel(Level level) {
method tag (line 174) | public Builder tag(String tag) {
method request (line 185) | public Builder request(String tag) {
method response (line 196) | public Builder response(String tag) {
method loggable (line 205) | public Builder loggable(boolean isDebug) {
method log (line 215) | public Builder log(int type) {
method logger (line 225) | public Builder logger(Logger logger) {
method build (line 230) | public LoggingInterceptor build() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Printer.java
class Printer (line 21) | class Printer {
method Printer (line 47) | protected Printer() {
method isEmpty (line 51) | private static boolean isEmpty(String line) {
method printJsonRequest (line 55) | static void printJsonRequest(LoggingInterceptor.Builder builder, Reque...
method printJsonResponse (line 80) | static void printJsonResponse(LoggingInterceptor.Builder builder, long...
method printFileRequest (line 96) | static void printFileRequest(LoggingInterceptor.Builder builder, Reque...
method printFileResponse (line 120) | static void printFileResponse(LoggingInterceptor.Builder builder, long...
method getRequest (line 133) | private static String[] getRequest(Request request, Level level) {
method getResponse (line 142) | private static String[] getResponse(String header, long tookMs, int co...
method slashSegments (line 154) | private static String slashSegments(List<String> segments) {
method dotHeaders (line 162) | private static String dotHeaders(String header) {
method logLines (line 185) | private static void logLines(int type, String tag, String[] lines, Log...
method bodyToString (line 202) | private static String bodyToString(final Request request) {
method getJsonString (line 215) | static String getJsonString(String msg) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/CloseUtils.java
class CloseUtils (line 10) | public final class CloseUtils {
method CloseUtils (line 12) | private CloseUtils() {
method closeIO (line 21) | public static void closeIO(final Closeable... closeables) {
method closeIOQuietly (line 39) | public static void closeIOQuietly(final Closeable... closeables) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ConvertUtils.java
class ConvertUtils (line 27) | public final class ConvertUtils {
method ConvertUtils (line 29) | private ConvertUtils() {
method bytes2HexString (line 43) | public static String bytes2HexString(final byte[] bytes) {
method hexString2Bytes (line 63) | public static byte[] hexString2Bytes(String hexString) {
method hex2Dec (line 84) | private static int hex2Dec(final char hexChar) {
method chars2Bytes (line 100) | public static byte[] chars2Bytes(final char[] chars) {
method bytes2Chars (line 116) | public static char[] bytes2Chars(final byte[] bytes) {
method memorySize2Byte (line 140) | public static long memorySize2Byte(final long memorySize, @MemoryConst...
method byte2MemorySize (line 158) | public static double byte2MemorySize(final long byteNum, @MemoryConsta...
method byte2FitMemorySize (line 170) | @SuppressLint("DefaultLocale")
method timeSpan2Millis (line 199) | public static long timeSpan2Millis(final long timeSpan, @TimeConstants...
method millis2TimeSpan (line 217) | public static long millis2TimeSpan(final long millis, @TimeConstants.U...
method millis2FitTimeSpan (line 237) | @SuppressLint("DefaultLocale")
method bytes2Bits (line 260) | public static String bytes2Bits(final byte[] bytes) {
method bits2Bytes (line 276) | public static byte[] bits2Bytes(String bits) {
method input2OutputStream (line 302) | public static ByteArrayOutputStream input2OutputStream(final InputStre...
method output2InputStream (line 326) | public ByteArrayInputStream output2InputStream(final OutputStream out) {
method inputStream2Bytes (line 337) | public static byte[] inputStream2Bytes(final InputStream is) {
method bytes2InputStream (line 348) | public static InputStream bytes2InputStream(final byte[] bytes) {
method outputStream2Bytes (line 359) | public static byte[] outputStream2Bytes(final OutputStream out) {
method bytes2OutputStream (line 370) | public static OutputStream bytes2OutputStream(final byte[] bytes) {
method inputStream2String (line 392) | public static String inputStream2String(final InputStream is, final St...
method string2InputStream (line 409) | public static InputStream string2InputStream(final String string, fina...
method outputStream2String (line 426) | public static String outputStream2String(final OutputStream out, final...
method string2OutputStream (line 443) | public static OutputStream string2OutputStream(final String string, fi...
method bitmap2Bytes (line 460) | public static byte[] bitmap2Bytes(final Bitmap bitmap, final Bitmap.Co...
method bytes2Bitmap (line 473) | public static Bitmap bytes2Bitmap(final byte[] bytes) {
method drawable2Bitmap (line 483) | public static Bitmap drawable2Bitmap(final Drawable drawable) {
method bitmap2Drawable (line 510) | public static Drawable bitmap2Drawable(final Bitmap bitmap) {
method drawable2Bytes (line 521) | public static byte[] drawable2Bytes(final Drawable drawable, final Bit...
method bytes2Drawable (line 531) | public static Drawable bytes2Drawable(final byte[] bytes) {
method view2Bitmap (line 541) | public static Bitmap view2Bitmap(final View view) {
method dp2px (line 561) | public static int dp2px(final float dpValue) {
method px2dp (line 572) | public static int px2dp(final float pxValue) {
method sp2px (line 583) | public static int sp2px(final float spValue) {
method px2sp (line 594) | public static int px2sp(final float pxValue) {
method isSpace (line 605) | private static boolean isSpace(final String s) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ImageUtils.java
class ImageUtils (line 62) | public class ImageUtils {
method saveImage (line 86) | public static void saveImage(Context context, String fileName, Bitmap ...
method saveImage (line 91) | public static void saveImage(Context context, String fileName,
method saveImageToSD (line 110) | public static void saveImageToSD(Context ctx, String filePath,
method saveBackgroundImage (line 129) | public static void saveBackgroundImage(Context ctx, String filePath,
method scanPhoto (line 151) | private static void scanPhoto(Context ctx, String imgFileName) {
method getBitmap (line 167) | public static Bitmap getBitmap(Context context, String fileName) {
method getBitmapByPath (line 192) | public static Bitmap getBitmapByPath(String filePath) {
method getBitmapByPath (line 196) | public static Bitmap getBitmapByPath(String filePath,
method getBitmapByFile (line 223) | public static Bitmap getBitmapByFile(File file) {
method getTempFileName (line 248) | public static String getTempFileName() {
method getCamerPath (line 260) | public static String getCamerPath() {
method getAbsolutePathFromNoStandardUri (line 271) | public static String getAbsolutePathFromNoStandardUri(Uri mUri) {
method getAbsoluteImagePath (line 296) | @SuppressWarnings("deprecation")
method loadImgThumbnail (line 325) | @SuppressWarnings("deprecation")
method loadImgThumbnail (line 348) | public static Bitmap loadImgThumbnail(String filePath, int w, int h) {
method getLatestImage (line 358) | public static String getLatestImage(Activity context) {
method scaleImageSize (line 385) | public static int[] scaleImageSize(int[] img_size, int square_size) {
method createImageThumbnail (line 408) | public static void createImageThumbnail(Context context,
method zoomBitmap (line 439) | public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
method scaleBitmap (line 454) | public static Bitmap scaleBitmap(Bitmap bitmap) {
method reDrawBitMap (line 484) | public static Bitmap reDrawBitMap(Activity context, Bitmap bitmap) {
method drawableToBitmap (line 517) | public static Bitmap drawableToBitmap(Drawable drawable) {
method getRoundedCornerBitmap (line 538) | public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float round...
method createReflectionImageWithOrigin (line 566) | public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {
method bitmapToDrawable (line 607) | public static Drawable bitmapToDrawable(Bitmap bitmap) {
method getImageType (line 618) | public static String getImageType(File file) {
method getImageType (line 646) | public static String getImageType(InputStream in) {
method getImageType (line 666) | public static String getImageType(byte[] bytes) {
method isJPEG (line 682) | private static boolean isJPEG(byte[] b) {
method isGIF (line 689) | private static boolean isGIF(byte[] b) {
method isPNG (line 697) | private static boolean isPNG(byte[] b) {
method isBMP (line 706) | private static boolean isBMP(byte[] b) {
method getImagePath (line 719) | public static String getImagePath(Uri uri, Activity context) {
method loadPicasaImageFromGalley (line 737) | public static Bitmap loadPicasaImageFromGalley(final Uri uri,
method compressBitmap (line 779) | public static File compressBitmap(String url, String storageDir, Strin...
method zoomBitmap (line 798) | public static Bitmap zoomBitmap(Bitmap source, float expectWidth, floa...
method revitionImageSize (line 822) | public static Bitmap revitionImageSize(File file) throws IOException {
method compressImage (line 847) | public static Bitmap compressImage(Bitmap image) {
method convertToFile (line 869) | public static File convertToFile(Bitmap bitmap, String storageDir, Str...
method checkTargetCacheDir (line 885) | public static File checkTargetCacheDir(String storageDir) {
method createFile (line 904) | public static File createFile(File folder, String prefix, String suffi...
method compressWithRx (line 915) | public static void compressWithRx(List<String> files, Observer observe...
method compressWithRx (line 942) | public static void compressWithRx(String url, Consumer consumer) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/KLog.java
class KLog (line 11) | public class KLog {
method init (line 27) | public static void init(boolean isShowLog) {
method v (line 31) | public static void v() {
method v (line 35) | public static void v(Object msg) {
method v (line 39) | public static void v(String tag, String msg) {
method d (line 43) | public static void d() {
method d (line 47) | public static void d(Object msg) {
method d (line 51) | public static void d(String tag, Object msg) {
method i (line 55) | public static void i() {
method i (line 59) | public static void i(Object msg) {
method i (line 63) | public static void i(String tag, Object msg) {
method w (line 67) | public static void w() {
method w (line 71) | public static void w(Object msg) {
method w (line 75) | public static void w(String tag, Object msg) {
method e (line 79) | public static void e() {
method e (line 83) | public static void e(Object msg) {
method e (line 87) | public static void e(String tag, Object msg) {
method a (line 91) | public static void a() {
method a (line 95) | public static void a(Object msg) {
method a (line 99) | public static void a(String tag, Object msg) {
method json (line 104) | public static void json(String jsonFormat) {
method json (line 108) | public static void json(String tag, String jsonFormat) {
method printLog (line 113) | private static void printLog(int type, String tagStr, Object objectMsg) {
method printLine (line 221) | private static void printLine(String tag, boolean isTop) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/MaterialDialogUtils.java
class MaterialDialogUtils (line 26) | public class MaterialDialogUtils {
method showThemed (line 28) | public void showThemed(Context context, String
method showIndeterminateProgressDialog (line 83) | public static MaterialDialog.Builder showIndeterminateProgressDialog(C...
method showBasicDialog (line 112) | public static MaterialDialog.Builder showBasicDialog(final Context con...
method showBasicDialogNoTitle (line 140) | public static MaterialDialog.Builder showBasicDialogNoTitle(final Cont...
method showBasicDialogNoCancel (line 157) | public static MaterialDialog.Builder showBasicDialogNoCancel(final Con...
method showBasicDialog (line 173) | public static MaterialDialog.Builder showBasicDialog(final Context con...
method showBasicDialogPositive (line 189) | public static MaterialDialog.Builder showBasicDialogPositive(final Con...
method getSelectDialog (line 206) | public static MaterialDialog.Builder getSelectDialog(Context context, ...
method showBasicListDialog (line 223) | public static MaterialDialog.Builder showBasicListDialog(final Context...
method showSingleListDialog (line 248) | public static MaterialDialog.Builder showSingleListDialog(final Contex...
method showMultiListDialog (line 275) | public static MaterialDialog.Builder showMultiListDialog(final Context...
method showCustomDialog (line 312) | public static void showCustomDialog(final Context context, String titl...
method showInputDialog (line 374) | public static MaterialDialog.Builder showInputDialog(final Context con...
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/RegexUtils.java
class RegexUtils (line 17) | public final class RegexUtils {
method RegexUtils (line 21) | private RegexUtils() {
method isMobileSimple (line 35) | public static boolean isMobileSimple(final CharSequence input) {
method isMobileExact (line 45) | public static boolean isMobileExact(final CharSequence input) {
method isMobileExact (line 56) | public static boolean isMobileExact(final CharSequence input, List<Str...
method isTel (line 81) | public static boolean isTel(final CharSequence input) {
method isIDCard15 (line 91) | public static boolean isIDCard15(final CharSequence input) {
method isIDCard18 (line 101) | public static boolean isIDCard18(final CharSequence input) {
method isIDCard18Exact (line 111) | public static boolean isIDCard18Exact(final CharSequence input) {
method isEmail (line 178) | public static boolean isEmail(final CharSequence input) {
method isURL (line 188) | public static boolean isURL(final CharSequence input) {
method isZh (line 198) | public static boolean isZh(final CharSequence input) {
method isUsername (line 211) | public static boolean isUsername(final CharSequence input) {
method isDate (line 221) | public static boolean isDate(final CharSequence input) {
method isIP (line 231) | public static boolean isIP(final CharSequence input) {
method isMatch (line 242) | public static boolean isMatch(final String regex, final CharSequence i...
method getMatches (line 253) | public static List<String> getMatches(final String regex, final CharSe...
method getSplits (line 271) | public static String[] getSplits(final String input, final String rege...
method getReplaceFirst (line 287) | public static String getReplaceFirst(final String input,
method getReplaceAll (line 305) | public static String getReplaceAll(final String input,
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/RxUtils.java
class RxUtils (line 23) | public class RxUtils {
method bindToLifecycle (line 29) | public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull Con...
method bindToLifecycle (line 42) | public static LifecycleTransformer bindToLifecycle(@NonNull Fragment l...
method bindToLifecycle (line 55) | public static LifecycleTransformer bindToLifecycle(@NonNull LifecycleP...
method schedulersTransformer (line 62) | public static ObservableTransformer schedulersTransformer() {
method exceptionTransformer (line 72) | public static ObservableTransformer exceptionTransformer() {
class HttpResponseFunc (line 84) | private static class HttpResponseFunc<T> implements Function<Throwable...
method apply (line 85) | @Override
class HandleFuc (line 91) | private static class HandleFuc<T> implements Function<BaseResponse<T>,...
method apply (line 92) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/SDCardUtils.java
class SDCardUtils (line 16) | public final class SDCardUtils {
method SDCardUtils (line 18) | private SDCardUtils() {
method isSDCardEnable (line 27) | public static boolean isSDCardEnable() {
method getSDCardPath (line 37) | public static String getSDCardPath() {
method getDataPath (line 70) | public static String getDataPath() {
method getFreeSpace (line 80) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
method getSDCardInfo (line 95) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
class SDCardInfo (line 111) | public static class SDCardInfo {
method toString (line 121) | @Override
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/SPUtils.java
class SPUtils (line 17) | public final class SPUtils {
method getInstance (line 27) | public static SPUtils getInstance() {
method getInstance (line 37) | public static SPUtils getInstance(String spName) {
method SPUtils (line 47) | private SPUtils(final String spName) {
method put (line 57) | public void put(@NonNull final String key, @NonNull final String value) {
method getString (line 67) | public String getString(@NonNull final String key) {
method getString (line 78) | public String getString(@NonNull final String key, @NonNull final Stri...
method put (line 88) | public void put(@NonNull final String key, final int value) {
method getInt (line 98) | public int getInt(@NonNull final String key) {
method getInt (line 109) | public int getInt(@NonNull final String key, final int defaultValue) {
method put (line 119) | public void put(@NonNull final String key, final long value) {
method getLong (line 129) | public long getLong(@NonNull final String key) {
method getLong (line 140) | public long getLong(@NonNull final String key, final long defaultValue) {
method put (line 150) | public void put(@NonNull final String key, final float value) {
method getFloat (line 160) | public float getFloat(@NonNull final String key) {
method getFloat (line 171) | public float getFloat(@NonNull final String key, final float defaultVa...
method put (line 181) | public void put(@NonNull final String key, final boolean value) {
method getBoolean (line 191) | public boolean getBoolean(@NonNull final String key) {
method getBoolean (line 202) | public boolean getBoolean(@NonNull final String key, final boolean def...
method put (line 212) | public void put(@NonNull final String key, @NonNull final Set<String> ...
method getStringSet (line 222) | public Set<String> getStringSet(@NonNull final String key) {
method getStringSet (line 233) | public Set<String> getStringSet(@NonNull final String key, @NonNull fi...
method getAll (line 242) | public Map<String, ?> getAll() {
method contains (line 252) | public boolean contains(@NonNull final String key) {
method remove (line 261) | public void remove(@NonNull final String key) {
method clear (line 268) | public void clear() {
method isSpace (line 272) | private static boolean isSpace(final String s) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/StringUtils.java
class StringUtils (line 7) | public final class StringUtils {
method StringUtils (line 9) | private StringUtils() {
method isEmpty (line 19) | public static boolean isEmpty(final CharSequence s) {
method isTrimEmpty (line 29) | public static boolean isTrimEmpty(final String s) {
method isSpace (line 39) | public static boolean isSpace(final String s) {
method equals (line 56) | public static boolean equals(final CharSequence a, final CharSequence ...
method equalsIgnoreCase (line 79) | public static boolean equalsIgnoreCase(final String a, final String b) {
method null2Length0 (line 89) | public static String null2Length0(final String s) {
method length (line 99) | public static int length(final CharSequence s) {
method upperFirstLetter (line 109) | public static String upperFirstLetter(final String s) {
method lowerFirstLetter (line 120) | public static String lowerFirstLetter(final String s) {
method reverse (line 131) | public static String reverse(final String s) {
method toDBC (line 151) | public static String toDBC(final String s) {
method toSBC (line 172) | public static String toSBC(final String s) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ToastUtils.java
class ToastUtils (line 26) | public final class ToastUtils {
method ToastUtils (line 39) | private ToastUtils() {
method setGravity (line 50) | public static void setGravity(int gravity, int xOffset, int yOffset) {
method setView (line 61) | public static void setView(@LayoutRes int layoutId) {
method setView (line 71) | public static void setView(@Nullable View view) {
method getView (line 80) | public static View getView() {
method setBackgroundColor (line 96) | public static void setBackgroundColor(@ColorInt int backgroundColor) {
method setBgResource (line 105) | public static void setBgResource(@DrawableRes int bgResource) {
method setMessageColor (line 114) | public static void setMessageColor(@ColorInt int messageColor) {
method showShortSafe (line 123) | public static void showShortSafe(final CharSequence text) {
method showShortSafe (line 137) | public static void showShortSafe(final @StringRes int resId) {
method showShortSafe (line 152) | public static void showShortSafe(final @StringRes int resId, final Obj...
method showShortSafe (line 167) | public static void showShortSafe(final String format, final Object... ...
method showLongSafe (line 181) | public static void showLongSafe(final CharSequence text) {
method showLongSafe (line 195) | public static void showLongSafe(final @StringRes int resId) {
method showLongSafe (line 210) | public static void showLongSafe(final @StringRes int resId, final Obje...
method showLongSafe (line 225) | public static void showLongSafe(final String format, final Object... a...
method showShort (line 239) | public static void showShort(CharSequence text) {
method showShort (line 248) | public static void showShort(@StringRes int resId) {
method showShort (line 258) | public static void showShort(@StringRes int resId, Object... args) {
method showShort (line 268) | public static void showShort(String format, Object... args) {
method showLong (line 277) | public static void showLong(CharSequence text) {
method showLong (line 286) | public static void showLong(@StringRes int resId) {
method showLong (line 296) | public static void showLong(@StringRes int resId, Object... args) {
method showLong (line 306) | public static void showLong(String format, Object... args) {
method showCustomShortSafe (line 313) | public static void showCustomShortSafe() {
method showCustomLongSafe (line 325) | public static void showCustomLongSafe() {
method showCustomShort (line 337) | public static void showCustomShort() {
method showCustomLong (line 344) | public static void showCustomLong() {
method show (line 354) | private static void show(@StringRes int resId, int duration) {
method show (line 365) | private static void show(@StringRes int resId, int duration, Object......
method show (line 376) | private static void show(String format, int duration, Object... args) {
method show (line 386) | private static void show(CharSequence text, int duration) {
method cancel (line 421) | public static void cancel() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/Utils.java
class Utils (line 12) | public final class Utils {
method Utils (line 17) | private Utils() {
method init (line 26) | public static void init(@NonNull final Context context) {
method getContext (line 35) | public static Context getContext() {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/Luban.java
class Luban (line 27) | public class Luban {
method Luban (line 45) | private Luban(File cacheDir) {
method getPhotoCacheDir (line 57) | private static synchronized File getPhotoCacheDir(Context context) {
method getPhotoCacheDir (line 70) | private static File getPhotoCacheDir(Context context, String cacheName) {
method get (line 93) | public static Luban get(Context context) {
method launch (line 98) | public Luban launch() {
method load (line 166) | public Luban load(String file) {
method load (line 171) | public Luban load(List<String> listFile) {
method setCompressListener (line 176) | public Luban setCompressListener(OnCompressListener listener) {
method putGear (line 181) | public Luban putGear(int gear) {
method setFilename (line 189) | public Luban setFilename(String filename) {
method asObservable (line 194) | public Observable<File> asObservable() {
method asListObservable (line 230) | public Observable<File> asListObservable() {
method thirdCompress (line 266) | private File thirdCompress(@NonNull File file) {
method firstCompress (line 326) | private File firstCompress(@NonNull File file) {
method getImageSize (line 373) | public int[] getImageSize(String imagePath) {
method compress (line 395) | private Bitmap compress(String imagePath, int width, int height) {
method getImageSpinAngle (line 437) | private int getImageSpinAngle(String path) {
method compress (line 470) | private File compress(String largeImagePath, String thumbFilePath, int...
method rotatingImage (line 485) | private static Bitmap rotatingImage(int angle, Bitmap bitmap) {
method saveImage (line 502) | private File saveImage(String filePath, Bitmap bitmap, long size) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/OnCompressListener.java
type OnCompressListener (line 5) | public interface OnCompressListener {
method onStart (line 10) | void onStart();
method onSuccess (line 15) | void onSuccess(File file);
method onError (line 20) | void onError(Throwable e);
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/Preconditions.java
class Preconditions (line 5) | final class Preconditions {
method checkNotNull (line 14) | static <T> T checkNotNull(T reference) {
method checkNotNull (line 30) | static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/MemoryConstants.java
class MemoryConstants (line 12) | public final class MemoryConstants {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/RegexConstants.java
class RegexConstants (line 7) | public final class RegexConstants {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/TimeConstants.java
class TimeConstants (line 12) | public final class TimeConstants {
FILE: mvvmhabit/src/main/java/me/goldze/mvvmhabit/widget/ControlDistributeLinearLayout.java
class ControlDistributeLinearLayout (line 15) | public class ControlDistributeLinearLayout extends LinearLayout {
method ControlDistributeLinearLayout (line 19) | public ControlDistributeLinearLayout(Context context, AttributeSet att...
method ControlDistributeLinearLayout (line 25) | public ControlDistributeLinearLayout(Context context, AttributeSet att...
method ControlDistributeLinearLayout (line 29) | public ControlDistributeLinearLayout(Context context) {
method onInterceptTouchEvent (line 36) | @Override
method isDistributeEvent (line 41) | public boolean isDistributeEvent() {
method setDistributeEvent (line 45) | public void setDistributeEvent(boolean distributeEvent) {
FILE: mvvmhabit/src/test/java/me/goldze/mvvmhabit/ExampleUnitTest.java
class ExampleUnitTest (line 12) | public class ExampleUnitTest {
method addition_isCorrect (line 13) | @Test
Condensed preview — 190 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (620K chars).
[
{
"path": ".gitattributes",
"chars": 65,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto"
},
{
"path": ".gitignore",
"chars": 172,
"preview": "*.iml\n.gradle\nkey.jks\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n/.idea\n.DS_Store\n/build\n/captures\n.externa"
},
{
"path": "LICENSE",
"chars": 11307,
"preview": "Apache License\n Version 2.0, January 2004\n http://www.apache.org/licens"
},
{
"path": "README.md",
"chars": 25523,
"preview": "## 最新日志\n**v4.0.0:2021年07月16日**\n\n- 迁移AndroidX分支作为主线分支;\n- 升级第三方框架依赖版本;\n- 升级gradle插件版本支持;\n- 优化框架代码,解决已知Bug;\n- 修改文档说明。\n#### "
},
{
"path": "UpdateLog.md",
"chars": 499,
"preview": "## 更新日志\n**v4.0.0:2021年07月16日**\n\n- 迁移AndroidX分支作为主线分支;\n- 升级第三方框架依赖版本;\n- 升级gradle插件版本支持;\n- 优化框架代码,解决已知Bug;\n- 修改文档说明。\n***\n*"
},
{
"path": "app/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "app/build.gradle",
"chars": 1456,
"preview": "apply plugin: 'com.android.application'\n\nandroid {\n compileSdkVersion rootProject.ext.android.compileSdkVersion\n d"
},
{
"path": "app/proguard-rules.pro",
"chars": 9398,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
},
{
"path": "app/src/androidTest/java/com/goldze/mvvmhabit/ExampleInstrumentedTest.java",
"chars": 744,
"preview": "package com.goldze.mvvmhabit;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimpo"
},
{
"path": "app/src/main/AndroidManifest.xml",
"chars": 1594,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/app/AppApplication.java",
"chars": 1459,
"preview": "package com.goldze.mvvmhabit.app;\n\nimport com.goldze.mvvmhabit.BuildConfig;\nimport com.goldze.mvvmhabit.R;\nimport com.go"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/app/AppViewModelFactory.java",
"chars": 1891,
"preview": "package com.goldze.mvvmhabit.app;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\n\nimport com.g"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/app/Injection.java",
"chars": 1042,
"preview": "package com.goldze.mvvmhabit.app;\n\nimport com.goldze.mvvmhabit.data.DemoRepository;\nimport com.goldze.mvvmhabit.data.sou"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/binding/twinklingrefreshlayout/ViewAdapter.java",
"chars": 1287,
"preview": "package com.goldze.mvvmhabit.binding.twinklingrefreshlayout;\n\nimport com.lcodecore.tkrefreshlayout.RefreshListenerAdapte"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/DemoRepository.java",
"chars": 2454,
"preview": "package com.goldze.mvvmhabit.data;\n\nimport com.goldze.mvvmhabit.data.source.HttpDataSource;\nimport com.goldze.mvvmhabit."
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/source/HttpDataSource.java",
"chars": 468,
"preview": "package com.goldze.mvvmhabit.data.source;\n\nimport com.goldze.mvvmhabit.entity.DemoEntity;\n\nimport io.reactivex.Observabl"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/source/LocalDataSource.java",
"chars": 377,
"preview": "package com.goldze.mvvmhabit.data.source;\n\n/**\n * Created by goldze on 2019/3/26.\n */\npublic interface LocalDataSource {"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/source/http/HttpDataSourceImpl.java",
"chars": 2459,
"preview": "package com.goldze.mvvmhabit.data.source.http;\n\nimport com.goldze.mvvmhabit.data.source.HttpDataSource;\nimport com.goldz"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/source/http/service/DemoApiService.java",
"chars": 618,
"preview": "package com.goldze.mvvmhabit.data.source.http.service;\n\nimport com.goldze.mvvmhabit.entity.DemoEntity;\n\nimport io.reacti"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/data/source/local/LocalDataSourceImpl.java",
"chars": 1278,
"preview": "package com.goldze.mvvmhabit.data.source.local;\n\nimport com.goldze.mvvmhabit.data.source.LocalDataSource;\n\nimport me.gol"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/entity/DemoEntity.java",
"chars": 4006,
"preview": "package com.goldze.mvvmhabit.entity;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.List;\n\n/"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/entity/FormEntity.java",
"chars": 2224,
"preview": "package com.goldze.mvvmhabit.entity;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.databindi"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/entity/SpinnerItemData.java",
"chars": 682,
"preview": "package com.goldze.mvvmhabit.entity;\n\nimport me.goldze.mvvmhabit.binding.viewadapter.spinner.IKeyAndValue;\n\n/**\n * Creat"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/base/adapter/BaseFragmentPagerAdapter.java",
"chars": 1025,
"preview": "package com.goldze.mvvmhabit.ui.base.adapter;\n\nimport java.util.List;\n\nimport androidx.fragment.app.Fragment;\nimport and"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/base/fragment/BasePagerFragment.java",
"chars": 1790,
"preview": "package com.goldze.mvvmhabit.ui.base.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport and"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/base/viewmodel/ToolbarViewModel.java",
"chars": 2794,
"preview": "package com.goldze.mvvmhabit.ui.base.viewmodel;\n\nimport android.app.Application;\nimport android.view.View;\n\nimport andro"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/form/FormFragment.java",
"chars": 2964,
"preview": "package com.goldze.mvvmhabit.ui.form;\n\nimport android.app.DatePickerDialog;\nimport android.os.Bundle;\nimport android.vie"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/form/FormViewModel.java",
"chars": 3757,
"preview": "package com.goldze.mvvmhabit.ui.form;\n\nimport android.app.Application;\nimport android.text.TextUtils;\nimport android.vie"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginActivity.java",
"chars": 2325,
"preview": "package com.goldze.mvvmhabit.ui.login;\n\nimport android.os.Bundle;\nimport android.text.method.HideReturnsTransformationMe"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/login/LoginViewModel.java",
"chars": 4156,
"preview": "package com.goldze.mvvmhabit.ui.login;\n\nimport android.app.Application;\nimport android.text.TextUtils;\nimport android.vi"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoActivity.java",
"chars": 3766,
"preview": "package com.goldze.mvvmhabit.ui.main;\n\nimport android.Manifest;\nimport android.app.ProgressDialog;\nimport android.conten"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/main/DemoViewModel.java",
"chars": 3958,
"preview": "package com.goldze.mvvmhabit.ui.main;\n\nimport android.app.Application;\nimport android.os.Bundle;\n\nimport com.goldze.mvvm"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkFragment.java",
"chars": 3652,
"preview": "package com.goldze.mvvmhabit.ui.network;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport andro"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkItemViewModel.java",
"chars": 2832,
"preview": "package com.goldze.mvvmhabit.ui.network;\n\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\n\nimport c"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/network/NetWorkViewModel.java",
"chars": 6580,
"preview": "package com.goldze.mvvmhabit.ui.network;\n\nimport android.app.Application;\n\nimport com.goldze.mvvmhabit.BR;\nimport com.go"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailFragment.java",
"chars": 1103,
"preview": "package com.goldze.mvvmhabit.ui.network.detail;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport an"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/network/detail/DetailViewModel.java",
"chars": 745,
"preview": "package com.goldze.mvvmhabit.ui.network.detail;\n\nimport android.app.Application;\n\nimport com.goldze.mvvmhabit.entity.Dem"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleHeadViewModel.java",
"chars": 794,
"preview": "package com.goldze.mvvmhabit.ui.rv_multi;\n\nimport androidx.annotation.NonNull;\nimport me.goldze.mvvmhabit.base.BaseViewM"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleLeftItemViewModel.java",
"chars": 1080,
"preview": "package com.goldze.mvvmhabit.ui.rv_multi;\n\nimport androidx.annotation.NonNull;\nimport androidx.databinding.ObservableFie"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleRightItemViewModel.java",
"chars": 1083,
"preview": "package com.goldze.mvvmhabit.ui.rv_multi;\n\nimport androidx.annotation.NonNull;\nimport androidx.databinding.ObservableFie"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewFragment.java",
"chars": 971,
"preview": "package com.goldze.mvvmhabit.ui.rv_multi;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android."
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/rv_multi/MultiRecycleViewModel.java",
"chars": 2861,
"preview": "package com.goldze.mvvmhabit.ui.rv_multi;\n\nimport android.app.Application;\n\nimport com.goldze.mvvmhabit.BR;\nimport com.g"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/activity/TabBarActivity.java",
"chars": 3835,
"preview": "package com.goldze.mvvmhabit.ui.tab_bar.activity;\n\nimport android.os.Bundle;\n\nimport com.goldze.mvvmhabit.BR;\nimport com"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar1Fragment.java",
"chars": 665,
"preview": "package com.goldze.mvvmhabit.ui.tab_bar.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport "
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar2Fragment.java",
"chars": 666,
"preview": "package com.goldze.mvvmhabit.ui.tab_bar.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport "
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar3Fragment.java",
"chars": 665,
"preview": "package com.goldze.mvvmhabit.ui.tab_bar.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport "
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/tab_bar/fragment/TabBar4Fragment.java",
"chars": 665,
"preview": "package com.goldze.mvvmhabit.ui.tab_bar.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport "
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/activity/ViewPagerActivity.java",
"chars": 1702,
"preview": "package com.goldze.mvvmhabit.ui.viewpager.activity;\n\nimport android.os.Bundle;\n\nimport com.goldze.mvvmhabit.BR;\nimport c"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/adapter/ViewPagerBindingAdapter.java",
"chars": 1000,
"preview": "package com.goldze.mvvmhabit.ui.viewpager.adapter;\n\nimport android.view.ViewGroup;\n\nimport com.goldze.mvvmhabit.databind"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerItemViewModel.java",
"chars": 834,
"preview": "package com.goldze.mvvmhabit.ui.viewpager.vm;\n\nimport androidx.annotation.NonNull;\nimport me.goldze.mvvmhabit.base.ItemV"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/viewpager/vm/ViewPagerViewModel.java",
"chars": 2090,
"preview": "package com.goldze.mvvmhabit.ui.viewpager.vm;\n\nimport android.app.Application;\n\nimport com.goldze.mvvmhabit.BR;\nimport c"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/ui/vp_frg/ViewPagerGroupFragment.java",
"chars": 1166,
"preview": "package com.goldze.mvvmhabit.ui.vp_frg;\n\nimport com.goldze.mvvmhabit.ui.base.fragment.BasePagerFragment;\nimport com.gold"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/utils/HttpsUtils.java",
"chars": 7709,
"preview": "/*\n * Copyright 2016 jeasonlzy(廖子尧)\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
},
{
"path": "app/src/main/java/com/goldze/mvvmhabit/utils/RetrofitClient.java",
"chars": 5021,
"preview": "package com.goldze.mvvmhabit.utils;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.goldze.m"
},
{
"path": "app/src/main/res/drawable/login_clear_input.xml",
"chars": 304,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app/src/main/res/layout/activity_demo.xml",
"chars": 2760,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.main.DemoView"
},
{
"path": "app/src/main/res/layout/activity_login.xml",
"chars": 6518,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:bind"
},
{
"path": "app/src/main/res/layout/activity_tab_bar.xml",
"chars": 1089,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:app="
},
{
"path": "app/src/main/res/layout/fragment_base_pager.xml",
"chars": 1358,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"me.goldze.mvvmhabit.base.BaseViewMode"
},
{
"path": "app/src/main/res/layout/fragment_detail.xml",
"chars": 4506,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.network.detai"
},
{
"path": "app/src/main/res/layout/fragment_form.xml",
"chars": 4221,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.form.FormView"
},
{
"path": "app/src/main/res/layout/fragment_multi_rv.xml",
"chars": 1128,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.rv_multi.Mult"
},
{
"path": "app/src/main/res/layout/fragment_network.xml",
"chars": 1648,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.network.NetWo"
},
{
"path": "app/src/main/res/layout/fragment_tab_bar_1.xml",
"chars": 681,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"me.goldze.mvvmhabit.base.BaseViewMode"
},
{
"path": "app/src/main/res/layout/fragment_tab_bar_2.xml",
"chars": 682,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"me.goldze.mvvmhabit.base.BaseViewMode"
},
{
"path": "app/src/main/res/layout/fragment_tab_bar_3.xml",
"chars": 684,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"me.goldze.mvvmhabit.base.BaseViewMode"
},
{
"path": "app/src/main/res/layout/fragment_tab_bar_4.xml",
"chars": 685,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"me.goldze.mvvmhabit.base.BaseViewMode"
},
{
"path": "app/src/main/res/layout/fragment_viewpager.xml",
"chars": 1779,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.viewpager.vm."
},
{
"path": "app/src/main/res/layout/item_multi_head.xml",
"chars": 1104,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.rv_multi.Mult"
},
{
"path": "app/src/main/res/layout/item_multi_rv_left.xml",
"chars": 901,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.rv_multi.Mult"
},
{
"path": "app/src/main/res/layout/item_multi_rv_right.xml",
"chars": 935,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.rv_multi.Mult"
},
{
"path": "app/src/main/res/layout/item_network.xml",
"chars": 1370,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.network.NetWo"
},
{
"path": "app/src/main/res/layout/item_viewpager.xml",
"chars": 959,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout>\n\n <data>\n\n <import type=\"com.goldze.mvvmhabit.ui.viewpager.vm."
},
{
"path": "app/src/main/res/layout/layout_toolbar.xml",
"chars": 3394,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:bind"
},
{
"path": "app/src/main/res/values/attrs.xml",
"chars": 808,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"TwinklingRefreshLayout\">\n <attr n"
},
{
"path": "app/src/main/res/values/colors.xml",
"chars": 396,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#3F51B5</color>\n <color name=\"color"
},
{
"path": "app/src/main/res/values/strings.xml",
"chars": 79,
"preview": "<resources>\n <string name=\"app_name\">MVVMHabit-sample</string>\n</resources>\n"
},
{
"path": "app/src/main/res/values/styles.xml",
"chars": 976,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
},
{
"path": "app/src/main/res/xml/network_security_config.xml",
"chars": 145,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<network-security-config>\n <base-config cleartextTrafficPermitted=\"true\" />\n</"
},
{
"path": "app/src/test/java/com/goldze/mvvmhabit/ExampleUnitTest.java",
"chars": 398,
"preview": "package com.goldze.mvvmhabit;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test"
},
{
"path": "build.gradle",
"chars": 829,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\napply from: \"config."
},
{
"path": "config.gradle",
"chars": 3804,
"preview": "ext {\n //android开发版本配置\n android = [\n compileSdkVersion: 28,\n buildToolsVersion: \"28.0.0\",\n "
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 232,
"preview": "#Tue Apr 09 21:09:52 CST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradle.properties",
"chars": 819,
"preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "mvvmhabit/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "mvvmhabit/build.gradle",
"chars": 2698,
"preview": "apply plugin: 'com.android.library'\nandroid {\n compileSdkVersion rootProject.ext.android.compileSdkVersion\n defaul"
},
{
"path": "mvvmhabit/proguard-rules.pro",
"chars": 916,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
},
{
"path": "mvvmhabit/src/androidTest/java/me/goldze/mvvmhabit/ExampleInstrumentedTest.java",
"chars": 747,
"preview": "package me.goldze.mvvmhabit;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimpor"
},
{
"path": "mvvmhabit/src/main/AndroidManifest.xml",
"chars": 720,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\n package=\"me.goldze.mvvmhabit\">\n\n <uses-perm"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/AppManager.java",
"chars": 4500,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.app.Activity;\n\nimport java.util.Stack;\n\nimport androidx.fragment.app.F"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseActivity.java",
"chars": 7980,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.afollestad.mater"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseApplication.java",
"chars": 2041,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.os.Bundle"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseFragment.java",
"chars": 8391,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutIn"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseModel.java",
"chars": 207,
"preview": "package me.goldze.mvvmhabit.base;\n\n/**\n * Created by goldze on 2017/6/15.\n */\npublic class BaseModel implements IModel {"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/BaseViewModel.java",
"chars": 6564,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.app.Application;\nimport android.os.Bundle;\n\nimport com.trello.rxlifecy"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ContainerActivity.java",
"chars": 3270,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.WindowMa"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IBaseView.java",
"chars": 282,
"preview": "package me.goldze.mvvmhabit.base;\n\n/**\n * Created by goldze on 2017/6/15.\n */\n\npublic interface IBaseView {\n /**\n "
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IBaseViewModel.java",
"chars": 953,
"preview": "package me.goldze.mvvmhabit.base;\n\n\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.LifecycleObserver;\nim"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/IModel.java",
"chars": 205,
"preview": "package me.goldze.mvvmhabit.base;\n\n/**\n * Created by goldze on 2017/6/15.\n */\npublic interface IModel {\n /**\n * V"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ItemViewModel.java",
"chars": 312,
"preview": "package me.goldze.mvvmhabit.base;\n\n\nimport androidx.annotation.NonNull;\n\n/**\n * ItemViewModel\n * Created by goldze on 20"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/MultiItemViewModel.java",
"chars": 555,
"preview": "package me.goldze.mvvmhabit.base;\n\n\nimport androidx.annotation.NonNull;\n\n/**\n * Create Author:goldze\n * Create Date:2019"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/base/ViewModelFactory.java",
"chars": 2462,
"preview": "package me.goldze.mvvmhabit.base;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\n\nimport java."
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingAction.java",
"chars": 134,
"preview": "package me.goldze.mvvmhabit.binding.command;\n\n/**\n * A zero-argument action.\n */\n\npublic interface BindingAction {\n v"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingCommand.java",
"chars": 1627,
"preview": "package me.goldze.mvvmhabit.binding.command;\n\n\n/**\n * About : kelin的ReplyCommand\n * 执行的命令回调, 用于ViewModel与xml之间的数据绑定\n */\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingConsumer.java",
"chars": 181,
"preview": "package me.goldze.mvvmhabit.binding.command;\n\n/**\n * A one-argument action.\n *\n * @param <T> the first argument type\n */"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/BindingFunction.java",
"chars": 187,
"preview": "package me.goldze.mvvmhabit.binding.command;\n\n/**\n * Represents a function with zero arguments.\n *\n * @param <T> the res"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/command/ResponseCommand.java",
"chars": 1498,
"preview": "package me.goldze.mvvmhabit.binding.command;\n\nimport io.reactivex.functions.Function;\n\n/**\n * About : kelin的ResponseComm"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/checkbox/ViewAdapter.java",
"chars": 858,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.checkbox;\n\nimport android.widget.CheckBox;\nimport android.widget.Compoun"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/edittext/ViewAdapter.java",
"chars": 1796,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.edittext;\n\nimport android.content.Context;\nimport android.text.Editable;"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/image/ViewAdapter.java",
"chars": 770,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.image;\n\nimport android.text.TextUtils;\nimport android.widget.ImageView;\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/listview/ViewAdapter.java",
"chars": 4531,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.listview;\n\nimport android.view.View;\nimport android.widget.AbsListView;\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/mswitch/ViewAdapter.java",
"chars": 1164,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.mswitch;\n\nimport android.widget.CompoundButton;\nimport android.widget.Sw"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/radiogroup/ViewAdapter.java",
"chars": 928,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.radiogroup;\n\nimport android.widget.RadioButton;\nimport android.widget.Ra"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/DividerLine.java",
"chars": 5279,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.recyclerview;\n\nimport android.content.Context;\nimport android.content.re"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/LayoutManagers.java",
"chars": 3153,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.recyclerview;\n\nimport java.lang.annotation.Retention;\nimport java.lang.a"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/LineManagers.java",
"chars": 1334,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.recyclerview;\n\nimport androidx.recyclerview.widget.RecyclerView;\n\n/**\n *"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/recyclerview/ViewAdapter.java",
"chars": 4634,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.recyclerview;\n\nimport java.util.concurrent.TimeUnit;\n\nimport androidx.da"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/scrollview/ViewAdapter.java",
"chars": 2391,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.scrollview;\n\nimport android.view.ViewTreeObserver;\nimport android.widget"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/spinner/IKeyAndValue.java",
"chars": 245,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.spinner;\n\n/**\n * Created by goldze on 2017/6/18.\n * 下拉Spinner控件的键值对, 实现该"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/spinner/ViewAdapter.java",
"chars": 2582,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.spinner;\n\nimport android.text.TextUtils;\nimport android.view.View;\nimpor"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/swiperefresh/ViewAdapter.java",
"chars": 984,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.swiperefresh;\n\nimport androidx.databinding.BindingAdapter;\nimport androi"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/view/ViewAdapter.java",
"chars": 4335,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.view;\n\nimport android.view.View;\n\nimport com.jakewharton.rxbinding2.view"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewgroup/IBindingItemViewModel.java",
"chars": 257,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.viewgroup;\n\nimport androidx.databinding.ViewDataBinding;\n\n/**\n * Created"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewgroup/ViewAdapter.java",
"chars": 1149,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.viewgroup;\n\nimport android.view.LayoutInflater;\nimport android.view.View"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/viewpager/ViewAdapter.java",
"chars": 2283,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.viewpager;\n\nimport androidx.databinding.BindingAdapter;\nimport androidx."
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/binding/viewadapter/webview/ViewAdapter.java",
"chars": 477,
"preview": "package me.goldze.mvvmhabit.binding.viewadapter.webview;\n\nimport android.text.TextUtils;\nimport android.webkit.WebView;\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/Messenger.java",
"chars": 23176,
"preview": "package me.goldze.mvvmhabit.bus;\n\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collection"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxBus.java",
"chars": 3055,
"preview": "package me.goldze.mvvmhabit.bus;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport io.reacti"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxBusSubscriber.java",
"chars": 561,
"preview": "package me.goldze.mvvmhabit.bus;\n\nimport io.reactivex.observers.DisposableObserver;\n\n/**\n * 为RxBus使用的Subscriber, 主要提供nex"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/RxSubscriptions.java",
"chars": 772,
"preview": "package me.goldze.mvvmhabit.bus;\n\nimport io.reactivex.disposables.CompositeDisposable;\nimport io.reactivex.disposables.D"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/WeakAction.java",
"chars": 1646,
"preview": "package me.goldze.mvvmhabit.bus;\n\nimport java.lang.ref.WeakReference;\n\nimport me.goldze.mvvmhabit.binding.command.Bindin"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/event/SingleLiveEvent.java",
"chars": 2468,
"preview": "/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/bus/event/SnackbarMessage.java",
"chars": 1731,
"preview": "/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CaocConfig.java",
"chars": 10972,
"preview": "/*\n * Copyright 2014-2017 Eduard Ereza Martínez\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n *"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CaocInitProvider.java",
"chars": 1800,
"preview": "/*\n * Copyright 2014-2017 Eduard Ereza Martínez\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n *"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/CustomActivityOnCrash.java",
"chars": 32563,
"preview": "/*\n * Copyright 2014-2017 Eduard Ereza Martínez\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n *"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/crash/DefaultErrorActivity.java",
"chars": 5890,
"preview": "/*\n * Copyright 2014-2017 Eduard Ereza Martínez\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n *"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ApiDisposableObserver.java",
"chars": 3703,
"preview": "package me.goldze.mvvmhabit.http;\n\nimport io.reactivex.observers.DisposableObserver;\nimport me.goldze.mvvmhabit.base.App"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/BaseResponse.java",
"chars": 680,
"preview": "package me.goldze.mvvmhabit.http;\n\n/**\n * Created by goldze on 2017/5/10.\n * 该类仅供参考,实际业务返回的固定字段, 根据需求来定义,\n */\npublic cla"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/DownLoadManager.java",
"chars": 2446,
"preview": "package me.goldze.mvvmhabit.http;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.reactivex.Observable;\nimport io.reac"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ExceptionHandle.java",
"chars": 3769,
"preview": "package me.goldze.mvvmhabit.http;\n\nimport com.google.gson.JsonParseException;\nimport com.google.gson.stream.MalformedJso"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/NetworkUtil.java",
"chars": 6031,
"preview": "package me.goldze.mvvmhabit.http;\n\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport androi"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/ResponseThrowable.java",
"chars": 301,
"preview": "package me.goldze.mvvmhabit.http;\n\n/**\n * Created by goldze on 2017/5/11.\n */\n\npublic class ResponseThrowable extends Ex"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/CookieJarImpl.java",
"chars": 914,
"preview": "package me.goldze.mvvmhabit.http.cookie;\n\n\nimport java.util.List;\n\nimport me.goldze.mvvmhabit.http.cookie.store.CookieSt"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/CookieStore.java",
"chars": 772,
"preview": "package me.goldze.mvvmhabit.http.cookie.store;\n\nimport java.util.List;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/MemoryCookieStore.java",
"chars": 2704,
"preview": "package me.goldze.mvvmhabit.http.cookie.store;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.L"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/PersistentCookieStore.java",
"chars": 9405,
"preview": "package me.goldze.mvvmhabit.http.cookie.store;\n\nimport android.content.Context;\nimport android.content.SharedPreferences"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/cookie/store/SerializableHttpCookie.java",
"chars": 2138,
"preview": "package me.goldze.mvvmhabit.http.cookie.store;\n\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport jav"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/DownLoadStateBean.java",
"chars": 1882,
"preview": "package me.goldze.mvvmhabit.http.download;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.io.Seri"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/DownLoadSubscriber.java",
"chars": 887,
"preview": "package me.goldze.mvvmhabit.http.download;\n\nimport io.reactivex.observers.DisposableObserver;\n\n/**\n * Created by goldze "
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/ProgressCallBack.java",
"chars": 2886,
"preview": "package me.goldze.mvvmhabit.http.download;\n\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileNotFoundEx"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/download/ProgressResponseBody.java",
"chars": 1727,
"preview": "package me.goldze.mvvmhabit.http.download;\n\nimport java.io.IOException;\n\nimport me.goldze.mvvmhabit.bus.RxBus;\nimport ok"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/BaseInterceptor.java",
"chars": 910,
"preview": "package me.goldze.mvvmhabit.http.interceptor;\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.Set;\n\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/CacheInterceptor.java",
"chars": 1627,
"preview": "package me.goldze.mvvmhabit.http.interceptor;\n\nimport android.content.Context;\n\nimport java.io.IOException;\n\nimport me.g"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/ProgressInterceptor.java",
"chars": 594,
"preview": "package me.goldze.mvvmhabit.http.interceptor;\n\nimport java.io.IOException;\n\nimport me.goldze.mvvmhabit.http.download.Pro"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/I.java",
"chars": 635,
"preview": "package me.goldze.mvvmhabit.http.interceptor.logging;\n\n\nimport java.util.logging.Level;\n\nimport okhttp3.internal.platfor"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Level.java",
"chars": 559,
"preview": "package me.goldze.mvvmhabit.http.interceptor.logging;\n\n/**\n * @author ihsan on 21/02/2017.\n */\n\npublic enum Level {\n "
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Logger.java",
"chars": 453,
"preview": "package me.goldze.mvvmhabit.http.interceptor.logging;\n\nimport okhttp3.internal.platform.Platform;\n\n/**\n * @author ihsan "
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/LoggingInterceptor.java",
"chars": 6616,
"preview": "package me.goldze.mvvmhabit.http.interceptor.logging;\n\nimport android.text.TextUtils;\n\nimport java.io.IOException;\nimpor"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/http/interceptor/logging/Printer.java",
"chars": 10594,
"preview": "package me.goldze.mvvmhabit.http.interceptor.logging;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport o"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/CloseUtils.java",
"chars": 1173,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * Created by goldze on 2"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ConvertUtils.java",
"chars": 17723,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.annotation.SuppressLint;\nimport android.graphics.Bitmap;\nimport andro"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ImageUtils.java",
"chars": 30549,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android."
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/KLog.java",
"chars": 6503,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport org.json.JSONArray;\n"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/MaterialDialogUtils.java",
"chars": 13455,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport andro"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/RegexUtils.java",
"chars": 10530,
"preview": "package me.goldze.mvvmhabit.utils;\n\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nim"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/RxUtils.java",
"chars": 3143,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.content.Context;\n\nimport com.trello.rxlifecycle2.LifecycleProvider;\ni"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/SDCardUtils.java",
"chars": 4238,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.Envi"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/SPUtils.java",
"chars": 6234,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport ja"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/StringUtils.java",
"chars": 4756,
"preview": "package me.goldze.mvvmhabit.utils;\n\n/**\n * Created by goldze on 2017/5/14.\n * 字符串相关工具类\n */\npublic final class StringUtil"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/ToastUtils.java",
"chars": 10447,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Looper;"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/Utils.java",
"chars": 878,
"preview": "package me.goldze.mvvmhabit.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\n\nimport andr"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/Luban.java",
"chars": 19068,
"preview": "package me.goldze.mvvmhabit.utils.compression;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport a"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/OnCompressListener.java",
"chars": 502,
"preview": "package me.goldze.mvvmhabit.utils.compression;\n\nimport java.io.File;\n\npublic interface OnCompressListener {\n\n /**\n "
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/compression/Preconditions.java",
"chars": 1254,
"preview": "package me.goldze.mvvmhabit.utils.compression;\n\nimport androidx.annotation.Nullable;\n\nfinal class Preconditions {\n\n /"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/MemoryConstants.java",
"chars": 674,
"preview": "package me.goldze.mvvmhabit.utils.constant;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Retentio"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/RegexConstants.java",
"chars": 3631,
"preview": "package me.goldze.mvvmhabit.utils.constant;\n\n/**\n * Created by goldze on 2017/5/14.\n * 正则相关常量\n */\npublic final class Reg"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/utils/constant/TimeConstants.java",
"chars": 736,
"preview": "package me.goldze.mvvmhabit.utils.constant;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Retentio"
},
{
"path": "mvvmhabit/src/main/java/me/goldze/mvvmhabit/widget/ControlDistributeLinearLayout.java",
"chars": 1436,
"preview": "package me.goldze.mvvmhabit.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
},
{
"path": "mvvmhabit/src/main/res/layout/activity_container.xml",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "mvvmhabit/src/main/res/layout/customactivityoncrash_default_error_activity.xml",
"chars": 2627,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "mvvmhabit/src/main/res/values/attrs.xml",
"chars": 8236,
"preview": "<resources>\n\n <!-- require boolean value to decide whether requestFocus for view. -->\n <attr name=\"requestFocus\" f"
},
{
"path": "mvvmhabit/src/main/res/values/colors.xml",
"chars": 486,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"white\">#FFFFFF</color>\n <color name=\"black\">#0000"
},
{
"path": "mvvmhabit/src/main/res/values/dimens.xml",
"chars": 387,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Default screen margins, per the Android Design guidelines. -"
},
{
"path": "mvvmhabit/src/main/res/values/strings.xml",
"chars": 888,
"preview": "<resources>\n <string name=\"app_name\">mvvmhabit</string>\n <string name=\"customactivityoncrash_error_activity_error_"
},
{
"path": "mvvmhabit/src/test/java/me/goldze/mvvmhabit/ExampleUnitTest.java",
"chars": 397,
"preview": "package me.goldze.mvvmhabit;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test,"
},
{
"path": "settings.gradle",
"chars": 29,
"preview": "include ':app', ':mvvmhabit'\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the goldze/MVVMHabit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 190 files (566.8 KB), approximately 140.7k tokens, and a symbol index with 1154 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.