[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "## Look at here\n\n- → Did you conform to the [Rules](https://github.com/JessYanCoding/MVPArms/issues/150)?\n- → Did you read the [Wiki](https://github.com/JessYanCoding/MVPArms/wiki) **Carefully**?\n- → Did you search in Google?\n- → Did you search in openned&closed Issues?\n- → **Receive only bugs and suggestions**\n\n### Environment\n\n- [x] MVPArms Version: <!-- like: v2.3.1 -->\n- [x] AndroidStudio Version: <!-- like: v3.0.0 -->\n- [x] Gradle Plugin Version: <!-- like: v3.0.0 -->\n- [x] Target Android Version: <!-- like: Android 5.0 -->\n- [x] Device Model: <!-- like: Nexus 6 -->\n\n\n### Bug Description:\n<!-- 不接受框架之外的任何问题, 比如说 Retrofit 怎么使用, 不接受基础的问题以及 Google 或者百度能搜索到的问题, 比如说 Gradle 怎么下载不了三方库, 不接受已经回答过的 issues, 比如说 DaggerAppComponent, DaggerUserComponent 文件怎么不存在, 提问前最好先看下 https://github.com/JessYanCoding/MVPArms/issues/150, 当发现此 issues 不符合要求, 会在未被告知的情况下直接被 close!-->\n\n\n### Related Code:\n```java\n  \n\n```\n\n### Bug Log:\n```log\n\n\n```\n\n### Others:\n"
  },
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.iml\n.idea\n\n# Keystore files\n*.jks\n\n# MacOS\n.DS_Store\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: android\njdk: oraclejdk8\nbefore_install:\n  - yes | sdkmanager \"platforms;android-28\"\n\nenv:\n  global:\n    - ANDROID_API_LEVEL=28\n    - ANDROID_BUILD_TOOLS_VERSION=28.0.3\n    - TRAVIS_SECURE_ENV_VARS=true\n\nandroid:\n  components:\n    # The BuildTools version used by your project\n    - tools\n    - platform-tools\n    - build-tools-$ANDROID_BUILD_TOOLS_VERSION\n    - extra-android-m2repository\n    - extra-google-android-support\n\n    # The SDK version used to compile your project\n    - android-$ANDROID_API_LEVEL\n  licenses:\n    - '.+'\n\nscript:\n  - ./gradlew clean\n  #    - ./gradlew install\n  #    - ./gradlew bintrayUpload\n  - ./gradlew assembleDebug"
  },
  {
    "path": "CHANGELOG.md",
    "content": "[UpdateLog](https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog)"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting jess.yan.effort@gmail.com. All complaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\nIf you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request targeting the branch `master`.\n\nWhen submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible.\n\n## License\n\nBy contributing your code, you agree to license your contribution under the terms of the APLv2: https://github.com/JessYanCoding/MVPArms/blob/master/LICENSE\n\nAll files are released with the Apache 2.0 license.\n\nIf you are adding a new file it should have a header like this:\n\n```\n/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n ```"
  },
  {
    "path": "CONTRIBUTING_APP.md",
    "content": "**如果您使用或基于 MVPArms 开发过开源的 APP 或者 Framework, 恳请您将项目地址 [Pull Request](https://github.com/JessYanCoding/MVPArms/pull/new/master) 到这个页面, 方便更多人学习的同时, 也能为您的开源项目引入更多的流量, 也衷心的希望大家在学习 MVPArms 获得自我提升的同时, 也能帮助其他朋友更快的成长, 将开源精神传递下去!**\n\n**同时您也可以给自己的开源项目打上 mvparms 的标签，这样大家就能在 [Topics](https://github.com/topics/mvparms) 中找到您的开源项目**\n\n> **Tips: 以下项目并不能百分百保证完全按照框架的正规流程和正确配置, 大家可以作为参考, 但主要还是以官方 Demo 为准**\n\n<!-- 格式为: [**项目名字** : 项目描述](项目地址) -->\n### App\n#### Kotlin\n* [**养眼** : 这是一个基于 **MVPArms** 使用 **kotlin** 开发的 **看图 App** (**程序媛建议路过**) ](https://github.com/miaoMiaoDaShi/YangYanNew)\n* [**NoblesSpiritsKotlin** : 这是一个基于 **MVPArms** 使用 **kotlin** 开发的 **Mall App**](https://github.com/haife/NoblesSpiritsKotlin)\n\n#### Java\n* [**Hands-Chopping** : 这是一个基于 **MVPArms + ArmsComponent** 开发的包含 **Steam** 和 **杉果** 的组件化客户端](https://github.com/noterpopo/Hands-Chopping)\n* [**YeLearns** : 这是一个基于 **MVPArms** 开发的包含 **玩安卓、DIYcode、干货、微信资讯、游明星空** 等多个模块的客户端](https://github.com/yeyueduxing/YeLearns)\n* [**LQRBiliBlili** : 这是一个基于 **MVPArms** 开发的高仿 **bilibili** 安卓客户端 (**!!!请注意, 此项目在 GlobalConfiguration 中的部分配置是不正确的, 特别是对 Retrofit 的配置, 如非特殊需求, 请不要再一次给 Retrofit 设置新的 OkHttpClient, 框架内部已提供有 OkHttpClient, 请以官方 Demo 为准**)](https://github.com/GitLqr/LQRBiliBlili)\n* [**DiyCode** : 这是一个基于 **MVPArms** 开发的 **DiyCode** 社区客户端](https://github.com/linsneider/DiyCodeAndroid)\n* [**Ganamrs** : 这是一个基于 **MVPArms** 开发的 **Gank** 开源客户端](https://github.com/lianhuo/Ganamrs)\n* [**P2P** : 这是一个基于 **MVPArms** 开发的 **金融** 客户端](https://github.com/Everglowzz/P2P)\n* [**ZackShop** : 这是一个基于 **MVPArms** 开发的 **仿京东** 客户端](https://github.com/zhangqian666/shop-front-android)\n\n### Framework\n* [**MVPFrames** : 这个项目是将 **MVPArms** 框架和 **MVPArt** 框架合并成一个通用型项目, 并增加了数据库](https://github.com/DesignQu/MVPFrames)\n* [**MVVMArms** : Android MVVM Architecture Components based on **MVPArms** and **Android Architecture Components**.](https://github.com/xiaobailong24/MVVMArms)\n* [**smartframework-android-atlas** : 这是一个将 **MVPArms** 框架和 **Atlas** 框架相结合的组件化 **MVP** 框架](https://github.com/smarthane/smartframework-android-atlas)\n* [**smartframework-android** : 这是一个将 **MVPArms** 框架和 **VirtualAPK** 框架相结合的插件化 **MVP** 框架](https://github.com/smarthane/smartframework-android)\n* [**Atoms-mvp** : 这是一个参考 **MVPArms** 框架, 将自己对框架的理解相结合的 **MVP** 框架](https://github.com/xwc520/Atoms-mvp)\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "MVPArms.md",
    "content": "![Logo](image/arms_banner_v1.0.jpg)\n![Official](image/official.jpeg)\n\n<p align=\"center\">\n   <a href=\"https://bintray.com/jessyancoding/maven/MVPArms/_latestVersion\">\n    <img src=\"https://img.shields.io/badge/Jcenter-v2.5.2-brightgreen.svg?style=flat-square\" alt=\"Latest Stable Version\" />\n  </a>\n  <a href=\"https://travis-ci.org/JessYanCoding/MVPArms\">\n    <img src=\"https://travis-ci.org/JessYanCoding/MVPArms.svg?branch=master\" alt=\"Build Status\" />\n  </a>\n  <a href=\"https://developer.android.com/about/versions/android-4.0.html\">\n    <img src=\"https://img.shields.io/badge/API-14%2B-blue.svg?style=flat-square\" alt=\"Min Sdk Version\" />\n  </a>\n  <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">\n    <img src=\"http://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square\" alt=\"License\" />\n  </a>\n  <a href=\"https://www.jianshu.com/u/1d0c0bc634db\">\n    <img src=\"https://img.shields.io/badge/Author-JessYan-orange.svg?style=flat-square\" alt=\"Author\" />\n  </a>\n  <a href=\"https://shang.qq.com/wpa/qunwpa?idkey=7e59e59145e6c7c68932ace10f52790636451f01d1ecadb6a652b1df234df753\">\n    <img src=\"https://img.shields.io/badge/QQ%E7%BE%A4-455850365%20%7C%20301733278-orange.svg?style=flat-square\" alt=\"QQ Group\" />\n  </a>\n</p>\n\n<h2 align=\"center\">一个整合了大量主流开源项目高度可配置化的 Android MVP 快速集成框架</h2>\n\n## Usage\n> New Project (**以下步骤太麻烦? 现在可直接在新建的新工程中使用新功能 [一键生成 app Module](https://github.com/JessYanCoding/MVPArms-Module-Template), 让您免于项目繁琐的配置，快速开启 MVPArms 的世界**)\n>> 如果您想构建一个全新的项目，直接将整个项目 **clone** (或者下载) 下来，再将 **demo** 作为主 **Module** (建议将 **arms Module** 删除，并使用 **Gradle** [远程依赖](https://github.com/JessYanCoding/MVPArms/wiki#1.1) 本框架，便于更新，删除前请务必先查看 [这里](https://github.com/JessYanCoding/MVPArms/wiki/Issues#2))，最后将项目包名改成自己的包名，**demo Module** 包含可以直接使用的包结构，一个主流的 `MVP`+`Dagger2`+`Retrofit`+`RxJava` 框架就这样轻松的构建成功了，现在您再参考 **Mvp** 包下的 **UserActivity** 的格式，[使用 Template 一键生成 MVP、Dagger2 相关的所有类](https://github.com/JessYanCoding/MVPArmsTemplate)，配合查阅 [Wiki 文档](https://github.com/JessYanCoding/MVPArms/wiki) 慢慢掌握本框架，看再多文章不如早点在项目中使用它，在实践中学习总是最快的\n \n> Old Project\n>> [老项目想引入此框架，可以参考 Wiki 文档，写的非常详细](https://github.com/JessYanCoding/MVPArms/wiki)\n\n## Wiki\n[详细使用方法及扩展功能，请参照 Wiki (**开发前必看!!!**)](https://github.com/JessYanCoding/MVPArms/wiki)\n\n## Notice\n\n* [**MVPArms 官方组件化方案 ArmsComponent**](https://github.com/JessYanCoding/ArmsComponent/wiki)\n\n* [MVPArms 学习项目](https://github.com/JessYanCoding/MVPArms/blob/master/CONTRIBUTING_APP.md)\n\n* [意见收集](https://github.com/JessYanCoding/MVPArms/issues/40)\n\n* [更新日志](https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog)\n\n* [常见 Issues](https://github.com/JessYanCoding/MVPArms/wiki/Issues)\n\n* [我们为什么要把 Dagger2，MVP 以及 RxJava 引入项目中?](http://www.jianshu.com/p/91c2bb8e6369)\n\n* 看了上面的文章，对为什么使用这些技术应该比较了解了，使用这些技术对项目后期的维护和迭代特别是大型项目非常有帮助，但是在开发前期每写一个页面要多写很多  `MVP`、`Dagger2` 的类和接口，这对于开发前期确实比较头疼，现在本框架已经可以通过 [Template](https://github.com/JessYanCoding/MVPArmsTemplate) 自动生成一些 `MVP`，`Dagger2` 的模版代码，现在大家可以非常轻松的使用本框架.\n\n* 使用此框架自带自动屏幕适配功能 (可不使用)，请参考 [AndroidAutoSize 使用方法](https://github.com/JessYanCoding/AndroidAutoSize).\n\n* 作为通用框架，本框架不提供与 **UI** 有关的任何第三方库.\n\n## Functionality & Libraries\n1. [`Mvp` 是 Google 官方出品的 `Mvp` 架构项目，含有多个不同的架构分支(此为 Dagger 分支).](https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger/)\n2. [`Dagger2` 是 Google 根据 Square 的 Dagger1 出品的依赖注入框架，通过 Apt 编译时生成代码，性能优于使用运行时反射技术的依赖注入框架.](https://github.com/google/dagger)\n3. [`RxJava` 提供优雅的响应式 API 解决异步请求以及事件处理.](https://github.com/ReactiveX/RxJava)\n4. [`RxAndroid` 为 Android 提供响应式 API.](https://github.com/ReactiveX/RxAndroid)\n5. [`Rxlifecycle`，在 Android 上使用 `RxJava` 都知道的一个坑，就是生命周期的解除订阅，这个框架通过绑定 Activity 和 Fragment 的生命周期完美解决该问题.](https://github.com/trello/RxLifecycle)\n6. [`RxCache` 是使用注解，为 `Retrofit` 加入二级缓存 (内存，磁盘) 的缓存库.](https://github.com/VictorAlbertos/RxCache)\n7. [`RxErroHandler` 是 `RxJava` 的错误处理库，可在出现错误后重试.](https://github.com/JessYanCoding/RxErrorHandler)\n8. [`RxPermissions` 用于处理 Android 运行时权限的响应式库.](https://github.com/tbruyelle/RxPermissions)\n9. [`Retrofit` 是 Square 出品的网络请求库，极大的减少了 Http 请求的代码和步骤.](https://github.com/square/retrofit)\n10. [`Okhttp` 同样 Square 出品，不多介绍，做 Android 的都应该知道.](https://github.com/square/okhttp)\n11. [`AndroidAutoSize` 是今日头条屏幕适配方案终极版，一个极低成本的 Android 屏幕适配方案，该库没有引入到 `Arms`，所以框架使用者可自由选择屏幕适配方案.](https://github.com/JessYanCoding/AndroidAutoSize)\n12. [`Gson` 是 Google 官方的 Json Convert 框架.](https://github.com/google/gson)\n13. [`Butterknife` 是 JakeWharton 大神出品的 View 注入框架.](https://github.com/JakeWharton/butterknife)\n14. [`AndroidEventBus` 是一个轻量级的 EventBus，该库没有引入到 `Arms`，所以框架使用者可自由选择 EventBus.](https://github.com/hehonghui/AndroidEventBus)\n15. [`Timber` 是 JakeWharton 大神出品的 Log 框架容器，内部代码极少，但是思想非常不错.](https://github.com/JakeWharton/timber)\n16. [`Glide` 是本框架默认封装到扩展库 `arms-imageloader-glide` 中的图片加载库，可参照着 Wiki 更改为其他的图片加载库，`Glide` 的 API 和 `Picasso` 差不多，缓存机制比 `Picasso` 复杂，速度快，适合处理大型图片流，支持 gif 图片，`Fresco` 太大了！在 5.0 以下优势很大，5.0 以上系统默认使用的内存管理和 `Fresco` 类似.](https://github.com/bumptech/glide)\n17. [`LeakCanary` 是 Square 出品的专门用来检测 `Android` 和 `Java` 的内存泄漏，并通过通知栏提示内存泄漏信息.](https://github.com/square/leakcanary)\n\n## Who is using MVPArms?\n\n**MVPArms** 从诞生之初, 一直真诚的为开发者做着力所能及的事, 从详细的 [**Wiki**文档](https://github.com/JessYanCoding/MVPArms/wiki) 到高效的 [代码生成器](https://github.com/JessYanCoding/MVPArmsTemplate), 无一不透露着 **MVPArms** 对开发者诚挚的付出和关怀\n\n**MVPArms** 经过近两年时间殷勤的耕耘, 逐渐变得成熟, 稳定, 这不得不归功于 **MVPArms** 大家庭中每一位成员一直以来真诚的反馈和建议, 在此由衷的感谢他们为 **MVPArms** 做出的不可磨灭的贡献  \n\n但是 **MVPArms** 远不止于此, 还有更多的路要走, 还会继续成长, 变得更加强大, 现在我们诚挚的邀请您也成为咱们 **MVPArms** 大家庭中的一员  \n\n**天府通** | **小顶家装 工长端** | **小顶家装 工人端** | **小顶家装 材料端** | **小顶网** |\n:-------------------------------------------------------------------:|:----------:|:---------------:|:--------:|:--------------:|\n[<img src=\"image/tianfutong_logo.png\" width=\"80\" height=\"80\">](https://android.myapp.com/myapp/detail.htm?apkName=com.chinarainbow.tft) | [<img src=\"image/xiaoding_foreman_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/xiaoding_worker_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/xiaoding_material_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/top_net_work_logo.png\" width=\"80\" height=\"80\">](http://www.dgg.net/appload.htm) |\n**天天视频** | **天天直播** | **中斗通航** | **中斗祥云** | **麋鹿旅行** |\n[<img src=\"image/tiantian_video_logo.png\" width=\"80\" height=\"80\">](http://sj.qq.com/myapp/detail.htm?apkName=com.dzwh.ttys) | [<img src=\"image/tiantian_live_logo.png\" width=\"80\" height=\"80\">](http://www.25pp.com/android/detail_7611392/) | [<img src=\"image/tong_hang_logo.png\" width=\"80\" height=\"80\">](https://fir.im/3176) | <img src=\"image/xiang_yun_logo.png\" width=\"80\" height=\"80\">  | [<img src=\"image/mi_lu_logo.png\" width=\"80\" height=\"80\">](http://android.myapp.com/myapp/detail.htm?apkName=com.elk.tourist) |\n**汇财富** | **觅窝** | **晒墨宝** | **智播**  | **(Your App ...)** |\n[<img src=\"image/hui_cai_fu_logo.png\" width=\"80\" height=\"80\">](http://android.myapp.com/myapp/detail.htm?apkName=com.tahone.client) | [<img src=\"image/mi_wo_logo.png\" width=\"80\" height=\"80\">](http://miwo.ai/) | [<img src=\"image/shaimobao_logo.png\" width=\"80\" height=\"80\">](http://sj.qq.com/myapp/search.htm?kw=%E6%99%92%E5%A2%A8%E5%AE%9D)  | [<img src=\"image/zhibo_logo.png\" width=\"80\" height=\"80\">](http://www.zhibocloud.cn/) | <img src=\"image/android_logo.png\" width=\"80\" height=\"80\"> |  \n \n\n## Acknowledgements \n感谢本框架所使用到的所有三方库的 **Author** ,以及所有为 **Open Source** 做无私贡献的 **Developer** 和 **Organizations** ,使我们能更好的工作和学习,本人也会将业余时间回报给开源社区\n\n## Donate\n如果您认可 **MVPArms** 的代码质量,并使用 **MVPArms** 在实际开发中切实的提升了您的工作效率和开发能力,请您点击右上角 **Star** 支持一下谢谢!\n\n## About Me\n* **Email**: <jess.yan.effort@gmail.com>  \n* **Home**: <http://jessyan.me>\n* **掘金**: <https://juejin.im/user/57a9dbd9165abd0061714613>\n* **简书**: <https://www.jianshu.com/u/1d0c0bc634db>\n\n## License\n``` \n Copyright 2016, jessyan       \n  \n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at \n \n       http://www.apache.org/licenses/LICENSE-2.0 \n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n```\n"
  },
  {
    "path": "MVP_generator_solution",
    "content": "MVPArms框架自动生成MVP及Dagger2相关文件解决方案\n\n第二代模版已经开源到 https://github.com/JessYanCoding/MVPArmsTemplate ,一键生成所有文件\n\n(设置)Setting -> Editor ->  File and Code Templates -> Files 然后点击左上角绿色的+号\n\n\n下面有7个Template,将分隔符上Name: 后的字符复制到Name输入框里,将分隔符里的内容复制进下面的大输入框,复制完后在继续点+\n创建下一个,重复之前的操作,一共创建7个Template,点击右下角的ok按钮,现在在对应的包下点鼠标右键New选择项里就有刚才创建的\nTemplate了,点击对应Template,在输入框中输入名字就可以创建对应的文件\n再按照Contract->Model->Presenter->Activity->Module->Component的顺序在对应包下构建这6个模版,名字必须一样,这下\n对应页面的Dagger和Mvp类即自动生成了,就可以专注写逻辑了\n以下模版可以根据需求做相应修改\n\n\n\nName: Activity\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport com.jess.arms.base.BaseActivity;\nimport com.jess.arms.utils.ArmsUtils;\n\n\nimport static com.jess.arms.utils.Preconditions.checkNotNull;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\npublic class ${NAME}Activity extends BaseActivity<${NAME}Presenter> implements ${NAME}Contract.View {\n\n\n    @Override\n    public void setupActivityComponent(AppComponent appComponent) {\n        Dagger${NAME}Component\n                .builder()\n                .appComponent(appComponent)\n                .${NAME}Module(new ${NAME}Module(this)) //请将${NAME}Module()第一个首字母改为小写\n                .build()\n                .inject(this);\n    }\n\n    @Override\n    public int initView(Bundle savedInstanceState) {\n        return 0;\n    }\n\n    @Override\n    public void initData(Bundle savedInstanceState) {\n\n    }\n\n\n    @Override\n    public void showLoading() {\n\n    }\n\n    @Override\n    public void hideLoading() {\n\n    }\n\n    @Override\n    public void showMessage(@NonNull String message) {\n        checkNotNull(message);\n        ArmsUtils.snackbarText(message);\n    }\n\n    @Override\n    public void launchActivity(@NonNull Intent intent) {\n        checkNotNull(intent);\n        ArmsUtils.startActivity(intent);\n    }\n\n    @Override\n    public void killMyself() {\n        finish();\n    }\n\n\n}\n\n--------------------------------------------------------------------------------------\n\n\n\n\nName: Component\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport com.jess.arms.di.scope.ActivityScope;\n\nimport dagger.Component;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\n@ActivityScope\n@Component(modules = ${NAME}Module.class,dependencies = AppComponent.class)\npublic interface ${NAME}Component {\n    void inject(${NAME}Activity activity);\n}\n--------------------------------------------------------------------------------------\n\n\n\n\nName: Contract\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport com.jess.arms.mvp.IView;\nimport com.jess.arms.mvp.IModel;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\npublic interface ${NAME}Contract {\n    //对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息\n    interface View extends IView {\n\n    }\n    //Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存\n    interface Model extends IModel{\n\n    }\n}\n--------------------------------------------------------------------------------------\n\n\nName: Fragment\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport com.jess.arms.base.BaseFragment\n\nimport com.jess.arms.utils.ArmsUtils;\n\nimport butterknife.Bind;\n\nimport static com.jess.arms.utils.Preconditions.checkNotNull;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\npublic class ${NAME}Fragment extends BaseFragment<${NAME}Presenter> implements ${NAME}Contract.View{\n\n\n    public static ${NAME}Fragment newInstance() {\n        ${NAME}Fragment fragment = new ${NAME}Fragment();\n        return fragment;\n    }\n\n    @Override\n    public void setupFragmentComponent(AppComponent appComponent) {\n        Dagger${NAME}Component\n                .builder()\n                .appComponent(appComponent)\n                .${NAME}Module(new ${NAME}Module(this))//请将${NAME}Module()第一个首字母改为小写\n                .build()\n                .inject(this);\n    }\n\n    @Override\n    public View initView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return inflater.inflate(layout_id, container, false);\n    }\n\n    @Override\n    public void initData(Bundle savedInstanceState) {\n\n    }\n\n    /**\n     * 此方法是让外部调用使fragment做一些操作的,比如说外部的activity想让fragment对象执行一些方法,\n     * 建议在有多个需要让外界调用的方法时,统一传Message,通过what字段,来区分不同的方法,在setData\n     * 方法中就可以switch做不同的操作,这样就可以用统一的入口方法做不同的事\n     *\n     * 使用此方法时请注意调用时fragment的生命周期,如果调用此setData方法时onCreate还没执行\n     * setData里却调用了presenter的方法时,是会报空的,因为dagger注入是在onCreated方法中执行的,然后才创建的presenter\n     * 如果要做一些初始化操作,可以不必让外部调setData,在initData中初始化就可以了\n     *\n     * @param data\n     */\n\n    @Override\n    public void setData(Object data) {\n\n    }\n\n\n    @Override\n    public void showLoading() {\n\n    }\n\n    @Override\n    public void hideLoading() {\n\n    }\n\n    @Override\n    public void showMessage(@NonNull String message) {\n        checkNotNull(message);\n        ArmsUtils.snackbarText(message);\n    }\n\n    @Override\n    public void launchActivity(@NonNull Intent intent) {\n        checkNotNull(intent);\n        ArmsUtils.startActivity(intent);\n    }\n\n    @Override\n    public void killMyself() {\n\n    }\n\n}\n--------------------------------------------------------------------------------------\n\n\nName: Model\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport android.app.Application;\nimport com.google.gson.Gson;\nimport com.jess.arms.integration.IRepositoryManager;\nimport com.jess.arms.mvp.BaseModel;\n\nimport static com.jess.arms.utils.Preconditions.checkNotNull;\nimport com.jess.arms.di.scope.ActivityScope;\nimport javax.inject.Inject;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\n@ActivityScope\npublic class ${NAME}Model extends BaseModel implements ${NAME}Contract.Model{\n    private Gson mGson;\n    private Application mApplication;\n\n    @Inject\n    public ${NAME}Model(IRepositoryManager repositoryManager, Gson gson, Application application) {\n        super(repositoryManager);\n        this.mGson = gson;\n        this.mApplication = application;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        this.mGson = null;\n        this.mApplication = null;\n    }\n\n}\n\n--------------------------------------------------------------------------------------\n\n\nName: Module\n--------------------------------------------------------------------------------------\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport com.google.gson.Gson;\nimport android.app.Application;\nimport com.jess.arms.di.scope.ActivityScope;\n\nimport dagger.Module;\nimport dagger.Provides;\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n#parse(\"File Header.java\")\n\n@Module\npublic class ${NAME}Module {\n    private ${NAME}Contract.View view;\n\n    /**\n     * 构建${NAME}Module时,将View的实现类传进来,这样就可以提供View的实现类给presenter\n     * @param view\n     */\n    public ${NAME}Module(${NAME}Contract.View view) {\n        this.view = view;\n    }\n\n    @ActivityScope\n    @Provides\n    ${NAME}Contract.View provide${NAME}View(){\n        return this.view;\n    }\n\n    @ActivityScope\n    @Provides\n    ${NAME}Contract.Model provide${NAME}Model(${NAME}Model model){\n        return model;\n    }\n}\n--------------------------------------------------------------------------------------\n\n\nName: Presenter\n--------------------------------------------------------------------------------------\n\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport android.app.Application;\nimport com.jess.arms.integration.AppManager;\nimport com.jess.arms.di.scope.ActivityScope;\nimport com.jess.arms.mvp.BasePresenter;\nimport com.jess.arms.http.imageloader.ImageLoader;\nimport me.jessyan.rxerrorhandler.core.RxErrorHandler;\nimport javax.inject.Inject;\n\n\n/**\n  * 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同\n  * 由于每个项目包结构都不一定相同,所以每生成一个文件需要自己导入import包名,可以在设置中设置自动导入包名\n  * 请在对应包下按以下顺序生成对应代码,Contract->Model->Presenter->Activity->Module->Component\n  * 因为生成Activity时,Module和Component还没生成,但是Activity中有它们的引用,所以会报错,但是不用理会\n  * 继续将Module和Component生成完后,编译一下项目再回到Activity,按提示修改一个方法名即可\n  * 如果想生成Fragment的相关文件,则将上面构建顺序中的Activity换为Fragment,并将Component中inject方法的参数改为此Fragment\n  */\n\n\n\n#parse(\"File Header.java\")\n\n@ActivityScope\npublic class ${NAME}Presenter extends BasePresenter<${NAME}Contract.Model, ${NAME}Contract.View> {\n    private RxErrorHandler mErrorHandler;\n    private Application mApplication;\n    private ImageLoader mImageLoader;\n    private AppManager mAppManager;\n\n    @Inject\n    public ${NAME}Presenter (${NAME}Contract.Model model, ${NAME}Contract.View rootView\n            , RxErrorHandler handler, Application application\n            , ImageLoader imageLoader, AppManager appManager) {\n        super(model, rootView);\n        this.mErrorHandler = handler;\n        this.mApplication = application;\n        this.mImageLoader = imageLoader;\n        this.mAppManager = appManager;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        this.mErrorHandler = null;\n        this.mAppManager = null;\n        this.mImageLoader = null;\n        this.mApplication = null;\n    }\n\n}\n\n--------------------------------------------------------------------------------------\n\n\nName: AutoView\n--------------------------------------------------------------------------------------\n#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.ViewGroup;\n\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * 此Template用于生成AutoLayout需要的的Auto系列View,如需要使ScrollView适配,使用此Template输入ScrollView,即可生成\n * AutoScrollView,使用此View即可自适应\n * Created by jess on 16/4/14.\n */\npublic class Auto${NAME} extends ${NAME} {\n    private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public Auto${NAME}(Context context) {\n        super(context);\n    }\n\n    public Auto${NAME}(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public Auto${NAME}(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)\n    {\n        if (!isInEditMode())\n            mHelper.adjustChildren();\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b)\n    {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n\n    public static class LayoutParams extends ${NAME}.LayoutParams\n            implements AutoLayoutHelper.AutoLayoutParams\n    {\n        private AutoLayoutInfo mAutoLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs)\n        {\n            super(c, attrs);\n            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo()\n        {\n            return mAutoLayoutInfo;\n        }\n\n\n        public LayoutParams(int width, int height)\n        {\n            super(width, height);\n        }\n\n\n        public LayoutParams(ViewGroup.LayoutParams source)\n        {\n            super(source);\n        }\n\n        public LayoutParams(MarginLayoutParams source)\n        {\n            super(source);\n        }\n\n    }\n}\n\n--------------------------------------------------------------------------------------\n\n"
  },
  {
    "path": "README.md",
    "content": "![Logo](image/arms_banner_v1.0.jpg)\n![Official](image/official.jpeg)\n\n<p align=\"center\">\n   <a href=\"https://bintray.com/jessyancoding/maven/MVPArms/_latestVersion\">\n    <img src=\"https://img.shields.io/badge/Jcenter-v2.5.2-brightgreen.svg?style=flat-square\" alt=\"Latest Stable Version\" />\n  </a>\n  <a href=\"https://travis-ci.org/JessYanCoding/MVPArms\">\n    <img src=\"https://travis-ci.org/JessYanCoding/MVPArms.svg?branch=master\" alt=\"Build Status\" />\n  </a>\n  <a href=\"https://developer.android.com/about/versions/android-4.0.html\">\n    <img src=\"https://img.shields.io/badge/API-14%2B-blue.svg?style=flat-square\" alt=\"Min Sdk Version\" />\n  </a>\n  <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">\n    <img src=\"http://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square\" alt=\"License\" />\n  </a>\n  <a href=\"https://www.jianshu.com/u/1d0c0bc634db\">\n    <img src=\"https://img.shields.io/badge/Author-JessYan-orange.svg?style=flat-square\" alt=\"Author\" />\n  </a>\n  <a href=\"https://shang.qq.com/wpa/qunwpa?idkey=7e59e59145e6c7c68932ace10f52790636451f01d1ecadb6a652b1df234df753\">\n    <img src=\"https://img.shields.io/badge/QQ%E7%BE%A4-455850365%20%7C%20301733278-orange.svg?style=flat-square\" alt=\"QQ Group\" />\n  </a>\n</p>\n\n<p align=\"center\">\n  <a href=\"MVPArms.md\">\n    <b>中文说明</b>\n  </a>\n</p> \n\n## A common Architecture for Android Applications developing based on MVP, integrates many Open Source Projects (like Dagger2、RxJava、Retrofit ...), to make your developing quicker and easier.\n\n## Architectural\n<img src=\"https://github.com/JessYanCoding/MVPArms/raw/master/image/Architecture.png\" width=\"80%\" height=\"80%\">\n\n## Usage\n> New Project (**The following steps are too cumbersome? Now you can use the [new feature (generate an app Module with one click)](https://github.com/JessYanCoding/MVPArms-Module-Template) in new projects, to avoid the cumbersome configuration of the project, to quickly open the world of MVPArms**)\n>> If you are building a new project, directly to the entire project **clone** (or download), as **demo** as the main **Module** (It is recommended to remove the **arms Module** and use **Gradle** to [depend](https://github.com/JessYanCoding/MVPArms/wiki#1.1) on this framework remotely for easy updates), then the package name into their own package name, **demo Module** contains the package structure can be used directly, a mainstream `MVP` +` Dagger2` + `Retrofit` +` RxJava` framework so easy to build successful, and now you refer **Mvp** Package under the **UserActivity** format, [Use Template to automatically generate MVP, Dagger2 related classes](https://github.com/JessYanCoding/MVPArmsTemplate), With access to [Wiki documents](https://github.com/JessYanCoding/MVPArms/wiki) slowly grasp the framework to see more articles as soon as possible in the project to use it, in practice, learning is the fastest\n\n> Old Project\n>> [Old projects would like to introduce this framework, you can refer to the Wiki documentation, written in great detail](https://github.com/JessYanCoding/MVPArms/wiki)\n\n## Wiki\n[Detailed usage reference Wiki (**Must see!!!**)](https://github.com/JessYanCoding/MVPArms/wiki)\n\n\n## Notice\n\n* [MVPArms Learning Project](https://github.com/JessYanCoding/MVPArms/blob/master/CONTRIBUTING_APP.md)\n\n* [Collection Box](https://github.com/JessYanCoding/MVPArms/issues/40)\n\n* [Update Log](https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog)\n\n* [Common Issues](https://github.com/JessYanCoding/MVPArms/wiki/Issues)\n\n* The use of these technologies for the latter part of the project maintenance and iterative, especially large projects is very helpful, but is to develop a pre-write a page to write a lot of `MVP`,` Dagger2` class and interface, which is indeed a headache for the development of pre- Now the framework has been able to [Template](https://github.com/JessYanCoding/MVPArmsTemplate) automatically generate some `MVP`,` Dagger2` template code, and now we can very easily use the framework.\n\n* Use this frame comes with automatic screen adaptation function, please refer to [AndroidAutoSize](https://github.com/JessYanCoding/AndroidAutoSize).\n\n* This framework does not provide any third-party libraries associated with the **UI**.\n\n## Functionality & Libraries\n1. [`Mvp` Google's official` Mvp` architecture project, which contains several different schema branches (this is the Dagger branch).](https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger/)\n2. [`Dagger2`](https://github.com/google/dagger)\n3. [`RxJava`](https://github.com/ReactiveX/RxJava)\n4. [`RxAndroid`](https://github.com/ReactiveX/RxAndroid)\n5. [`Rxlifecycle`](https://github.com/trello/RxLifecycle)\n6. [`RxCache`](https://github.com/VictorAlbertos/RxCache)\n7. [`RxPermissions`](https://github.com/tbruyelle/RxPermissions)\n8. [`RxErroHandler`](https://github.com/JessYanCoding/RxErrorHandler)\n9. [`Retrofit`](https://github.com/square/retrofit)\n10. [`Okhttp`](https://github.com/square/okhttp)\n11. [`AndroidAutoSize`](https://github.com/JessYanCoding/AndroidAutoSize)\n12. [`Gson`](https://github.com/google/gson)\n13. [`Butterknife`](https://github.com/JakeWharton/butterknife)\n14. [`AndroidEventBus`](https://github.com/hehonghui/AndroidEventBus)\n15. [`Timber`](https://github.com/JakeWharton/timber)\n16. [`Glide`](https://github.com/bumptech/glide)\n17. [`LeakCanary`](https://github.com/square/leakcanary)\n\n## Who is using MVPArms?\n\n**天府通** | **小顶家装 工长端** | **小顶家装 工人端** | **小顶家装 材料端** | **小顶网** |\n:-------------------------------------------------------------------:|:----------:|:---------------:|:--------:|:--------------:|\n[<img src=\"image/tianfutong_logo.png\" width=\"80\" height=\"80\">](https://android.myapp.com/myapp/detail.htm?apkName=com.chinarainbow.tft) | [<img src=\"image/xiaoding_foreman_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/xiaoding_worker_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/xiaoding_material_logo.png\" width=\"80\" height=\"80\">](http://www.dggxdjz.com) | [<img src=\"image/top_net_work_logo.png\" width=\"80\" height=\"80\">](http://www.dgg.net/appload.htm) |\n**天天视频** | **天天直播** | **中斗通航** | **中斗祥云** | **麋鹿旅行** |\n[<img src=\"image/tiantian_video_logo.png\" width=\"80\" height=\"80\">](http://sj.qq.com/myapp/detail.htm?apkName=com.dzwh.ttys) | [<img src=\"image/tiantian_live_logo.png\" width=\"80\" height=\"80\">](http://www.25pp.com/android/detail_7611392/) | [<img src=\"image/tong_hang_logo.png\" width=\"80\" height=\"80\">](https://fir.im/3176) | <img src=\"image/xiang_yun_logo.png\" width=\"80\" height=\"80\">  | [<img src=\"image/mi_lu_logo.png\" width=\"80\" height=\"80\">](http://android.myapp.com/myapp/detail.htm?apkName=com.elk.tourist) |\n**汇财富** | **觅窝** | **晒墨宝** | **智播**  | **(Your App ...)** |\n[<img src=\"image/hui_cai_fu_logo.png\" width=\"80\" height=\"80\">](http://android.myapp.com/myapp/detail.htm?apkName=com.tahone.client) | [<img src=\"image/mi_wo_logo.png\" width=\"80\" height=\"80\">](http://miwo.ai/) | [<img src=\"image/shaimobao_logo.png\" width=\"80\" height=\"80\">](http://sj.qq.com/myapp/search.htm?kw=%E6%99%92%E5%A2%A8%E5%AE%9D)  | [<img src=\"image/zhibo_logo.png\" width=\"80\" height=\"80\">](http://www.zhibocloud.cn/) | <img src=\"image/android_logo.png\" width=\"80\" height=\"80\"> |\n\n\n## Acknowledgements \nThanks to all the three libraries used in this framework **Author**, and all for the **Open Source** selfless contributions **Developer** and **Organizations**, so that we can better work and study, I will also spare time return to the open source community\n\n## About Me\n* **Email**: <jess.yan.effort@gmail.com>  \n* **Home**: <http://jessyan.me>\n* **掘金**: <https://juejin.im/user/57a9dbd9165abd0061714613>\n* **简书**: <https://www.jianshu.com/u/1d0c0bc634db>\n\n## License\n``` \n Copyright 2016, jessyan       \n  \n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at \n \n       http://www.apache.org/licenses/LICENSE-2.0 \n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n```\n"
  },
  {
    "path": "arms/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "arms/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.android[\"compileSdkVersion\"]\n    buildToolsVersion rootProject.ext.android[\"buildToolsVersion\"]\n    useLibrary 'org.apache.http.legacy'\n\n    compileOptions {\n        targetCompatibility JavaVersion.VERSION_1_8\n        sourceCompatibility JavaVersion.VERSION_1_8\n    }\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.android[\"minSdkVersion\"]\n        targetSdkVersion rootProject.ext.android[\"targetSdkVersion\"]\n        versionCode rootProject.ext.android[\"versionCode\"]\n        versionName rootProject.ext.android[\"versionName\"]\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    api(rootProject.ext.dependencies[\"legacy-support-v4\"]) {\n        exclude module: 'annotation'\n        exclude module: 'coordinatorlayout'\n    }\n    //androidx\n    api(rootProject.ext.dependencies[\"appcompat\"]) {\n        exclude module: 'annotation'\n    }\n    compileOnly rootProject.ext.dependencies[\"design\"]\n    api(rootProject.ext.dependencies[\"recyclerview\"]) {\n        exclude module: 'annotation'\n    }\n    api rootProject.ext.dependencies[\"annotations\"]\n\n    //view\n    compileOnly rootProject.ext.dependencies[\"autolayout\"]\n    api(rootProject.ext.dependencies[\"butterknife\"]) {\n        exclude module: 'annotation'\n        exclude module: 'core'\n    }\n\n    //rx\n    api rootProject.ext.dependencies[\"rxjava2\"]\n    api(rootProject.ext.dependencies[\"rxandroid2\"]) {\n        exclude module: 'rxjava'\n    }\n    api(rootProject.ext.dependencies[\"rxcache2\"]) {\n        exclude module: 'rxjava'\n        exclude module: 'dagger'\n        exclude module: 'api'\n    }\n    implementation(rootProject.ext.dependencies[\"rxcache-jolyglot-gson\"]) {\n        exclude module: 'gson'\n    }\n    api(rootProject.ext.dependencies[\"rxlifecycle2\"]) {\n        exclude module: 'rxjava'\n        exclude module: 'jsr305'\n    }\n    api(rootProject.ext.dependencies[\"rxlifecycle2-android\"]) {\n        exclude module: 'annotation'\n        exclude module: 'rxjava'\n        exclude module: 'rxandroid'\n        exclude module: 'rxlifecycle'\n    }\n    api(rootProject.ext.dependencies[\"rxpermissions2\"]) {\n        exclude module: 'rxjava'\n        exclude module: 'annotation'\n    }\n    api rootProject.ext.dependencies['rxerrorhandler2']\n\n    //network\n    api(rootProject.ext.dependencies[\"retrofit\"]) {\n        exclude module: 'okhttp'\n        exclude module: 'okio'\n    }\n    implementation(rootProject.ext.dependencies[\"retrofit-converter-gson\"]) {\n        exclude module: 'gson'\n        exclude module: 'okhttp'\n        exclude module: 'okio'\n        exclude module: 'retrofit'\n    }\n    implementation(rootProject.ext.dependencies[\"retrofit-adapter-rxjava2\"]) {\n        exclude module: 'rxjava'\n        exclude module: 'okhttp'\n        exclude module: 'retrofit'\n        exclude module: 'okio'\n    }\n    api rootProject.ext.dependencies[\"okhttp3\"]\n    compileOnly rootProject.ext.dependencies[\"glide\"]\n    annotationProcessor(rootProject.ext.dependencies[\"glide-compiler\"]) {\n        exclude module: 'jsr305'\n    }\n\n    //tools\n    compileOnly rootProject.ext.dependencies[\"javax.annotation\"]\n    api rootProject.ext.dependencies[\"dagger2\"]\n    annotationProcessor rootProject.ext.dependencies[\"dagger2-compiler\"]\n    compileOnly rootProject.ext.dependencies[\"androideventbus\"]\n    compileOnly rootProject.ext.dependencies[\"eventbus\"]\n    api rootProject.ext.dependencies[\"gson\"]\n\n    //test\n    api rootProject.ext.dependencies[\"timber\"]\n}\n\napply from: '../bintray.gradle'"
  },
  {
    "path": "arms/gradle.properties",
    "content": "POM_NAME=MVPArms\n"
  },
  {
    "path": "arms/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/jess/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n-optimizationpasses 5\n\n\n-dontusemixedcaseclassnames\n\n-dontskipnonpubliclibraryclasses\n\n-dontskipnonpubliclibraryclassmembers\n\n-dontpreverify\n\n-verbose\n-printmapping priguardMapping.txt\n\n-optimizations !code/simplification/artithmetic,!field/*,!class/merging/*\n\n\n\n################common###############\n\n-keep public class * implements com.jess.arms.integration.ConfigModule\n\n #实体类不参与混淆\n-keep class com.jess.arms.widget.** { *; } #自定义控件不参与混淆\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keepnames class * implements java.io.Serializable\n-keepattributes Signature\n-keep class **.R$* {*;}\n-ignorewarnings\n-keepclassmembers class **.R$* {\n    public static <fields>;\n}\n\n-keepclasseswithmembernames class * { # 保持native方法不被混淆\n    native <methods>;\n}\n\n-keepclassmembers enum * {  # 使用enum类型时需要注意避免以下两个方法混淆，因为enum类的特殊性，以下两个方法会被反射调用，\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n\n\n################support###############\n-keep class android.support.** { *; }\n-keep interface android.support.** { *; }\n-dontwarn android.support.**\n\n\n################alipay###############\n\n-keep class com.alipay.android.app.IAlixPay{*;}\n-keep class com.alipay.android.app.IAlixPay$Stub{*;}\n-keep class com.alipay.android.app.IRemoteServiceCallback{*;}\n-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}\n-keep class com.alipay.sdk.app.PayTask{ public *;}\n-keep class com.alipay.sdk.app.AuthTask{ public *;}\n\n################retrofit###############\n-dontwarn retrofit2.**\n-keep class retrofit2.** { *; }\n-keepattributes Signature\n-keepattributes Exceptions\n\n################butterknife###############\n-keep class butterknife.** { *; }\n-dontwarn butterknife.internal.**\n-keep class **$$ViewBinder { *; }\n-keepclasseswithmembernames class * {\n   @butterknife.* <fields>;\n}\n-keepclasseswithmembernames class * {\n @butterknife.* <methods>;\n}\n\n\n################gson###############\n-keepattributes Signature\n-keepattributes *Annotation*\n-keep class sun.misc.Unsafe { *; }\n-keep class com.google.gson.stream.** { *; }\n# Application classes that will be serialized/deserialized over Gson\n-keep class com.sunloto.shandong.bean.** { *; }\n\n\n################glide###############\n-keep public class * implements com.bumptech.glide.module.AppGlideModule\n-keep public class * implements com.bumptech.glide.module.LibraryGlideModule\n-keep class com.bumptech.glide.** { *; }\n-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {\n    **[] $VALUES;\n    public *;\n}\n\n################okhttp###############\n-keepattributes Signature\n-keepattributes *Annotation*\n-keep class com.squareup.okhttp.** { *; }\n-keep interface com.squareup.okhttp.** { *; }\n-keep class okhttp3.** { *; }\n-keep interface okhttp3.** { *; }\n-dontwarn com.squareup.okhttp.**\n\n\n################androidEventBus###############\n-keep class org.simple.** { *; }\n-keep interface org.simple.** { *; }\n-keepclassmembers class * {\n    @org.simple.eventbus.Subscriber <methods>;\n}\n-keepattributes *Annotation*\n\n\n################EventBus###############\n-keepclassmembers class * {\n    @org.greenrobot.eventbus.Subscribe <methods>;\n}\n-keep class org.greenrobot.eventbus.EventBus { *; }\n-keep enum org.greenrobot.eventbus.ThreadMode { *; }\n\n-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {\n    <init>(java.lang.Throwable);\n}\n\n################autolayout###############\n-keep class com.zhy.autolayout.** { *; }\n-keep interface com.zhy.autolayout.** { *; }\n\n\n################RxJava and RxAndroid###############\n-dontwarn org.mockito.**\n-dontwarn org.junit.**\n-dontwarn org.robolectric.**\n\n-keep class io.reactivex.** { *; }\n-keep interface io.reactivex.** { *; }\n\n-keepattributes Signature\n-keepattributes *Annotation*\n-keep class com.squareup.okhttp.** { *; }\n-dontwarn okio.**\n-keep interface com.squareup.okhttp.** { *; }\n-dontwarn com.squareup.okhttp.**\n\n-dontwarn io.reactivex.**\n-dontwarn retrofit.**\n-keep class retrofit.** { *; }\n-keepclasseswithmembers class * {\n    @retrofit.http.* <methods>;\n}\n\n-keep class sun.misc.Unsafe { *; }\n\n-dontwarn java.lang.invoke.*\n\n-keep class io.reactivex.schedulers.Schedulers {\n    public static <methods>;\n}\n-keep class io.reactivex.schedulers.ImmediateScheduler {\n    public <methods>;\n}\n-keep class io.reactivex.schedulers.TestScheduler {\n    public <methods>;\n}\n-keep class io.reactivex.schedulers.Schedulers {\n    public static ** test();\n}\n-keepclassmembers class io.reactivex.internal.util.unsafe.*ArrayQueue*Field* {\n    long producerIndex;\n    long consumerIndex;\n}\n-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {\n    long producerNode;\n    long consumerNode;\n}\n\n-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {\n    io.reactivex.internal.util.atomic.LinkedQueueNode producerNode;\n}\n-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {\n    io.reactivex.internal.util.atomic.LinkedQueueNode consumerNode;\n}\n\n-dontwarn io.reactivex.internal.util.unsafe.**\n\n\n\n################espresso###############\n-keep class android.support.test.espresso.** { *; }\n-keep interface android.support.test.espresso.** { *; }\n\n\n\n################annotation###############\n-keep class android.support.annotation.** { *; }\n-keep interface android.support.annotation.** { *; }\n\n\n################RxLifeCycle#################\n-keep class com.trello.rxlifecycle2.** { *; }\n-keep interface com.trello.rxlifecycle2.** { *; }\n\n\n################RxPermissions#################\n-keep class com.tbruyelle.rxpermissions2.** { *; }\n-keep interface com.tbruyelle.rxpermissions2.** { *; }\n\n################RxCache#################\n-dontwarn io.rx_cache2.internal.**\n-keep class io.rx_cache2.internal.Record { *; }\n-keep class io.rx_cache2.Source { *; }\n\n-keep class io.victoralbertos.jolyglot.** { *; }\n-keep interface io.victoralbertos.jolyglot.** { *; }\n\n################RxErrorHandler#################\n -keep class me.jessyan.rxerrorhandler.** { *; }\n -keep interface me.jessyan.rxerrorhandler.** { *; }\n\n################Timber#################\n-dontwarn org.jetbrains.annotations.**\n\n\n################Canary#################\n-dontwarn com.squareup.haha.guava.**\n-dontwarn com.squareup.haha.perflib.**\n-dontwarn com.squareup.haha.trove.**\n-dontwarn com.squareup.leakcanary.**\n-keep class com.squareup.haha.** { *; }\n-keep class com.squareup.leakcanary.** { *; }\n\n# Marshmallow removed Notification.setLatestEventInfo()\n-dontwarn android.app.Notification\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "arms/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.jess.arms\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n</manifest>\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/AdapterViewPager.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport androidx.fragment.app.Fragment;\r\nimport androidx.fragment.app.FragmentManager;\r\nimport androidx.fragment.app.FragmentStatePagerAdapter;\r\n\r\nimport java.util.List;\r\n\r\n/**\r\n * ================================================\r\n * 基类 {@link FragmentStatePagerAdapter}\r\n * <p>\r\n * Created by JessYan on 22/03/2016\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class AdapterViewPager extends FragmentStatePagerAdapter {\r\n    private List<Fragment> mList;\r\n    private CharSequence[] mTitles;\r\n\r\n    public AdapterViewPager(FragmentManager fragmentManager, List<Fragment> list) {\r\n        super(fragmentManager);\r\n        this.mList = list;\r\n    }\r\n\r\n    public AdapterViewPager(FragmentManager fragmentManager, List<Fragment> list, CharSequence[] titles) {\r\n        super(fragmentManager);\r\n        this.mList = list;\r\n        this.mTitles = titles;\r\n    }\r\n\r\n    @Override\r\n    public Fragment getItem(int position) {\r\n        return mList.get(position);\r\n    }\r\n\r\n    @Override\r\n    public CharSequence getPageTitle(int position) {\r\n        if (mTitles != null && position < mTitles.length) {\r\n            return mTitles[position];\r\n        }\r\n        return super.getPageTitle(position);\r\n    }\r\n\r\n    @Override\r\n    public int getCount() {\r\n        return mList.size();\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/App.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base;\n\nimport androidx.annotation.NonNull;\n\nimport com.jess.arms.di.component.AppComponent;\n\n/**\n * ================================================\n * 框架要求框架中的每个 {@link android.app.Application} 都需要实现此类, 以满足规范\n *\n * @see BaseApplication\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki\">请配合官方 Wiki 文档学习本框架</a>\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog\">更新日志, 升级必看!</a>\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/Issues\">常见 Issues, 踩坑必看!</a>\n * @see <a href=\"https://github.com/JessYanCoding/ArmsComponent/wiki\">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>\n * Created by JessYan on 25/04/2017 14:54\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface App {\n    @NonNull\n    AppComponent getAppComponent();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseActivity.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport android.app.Activity;\r\nimport android.content.Context;\r\nimport android.os.Bundle;\r\nimport android.util.AttributeSet;\r\nimport android.view.InflateException;\r\nimport android.view.View;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.annotation.Nullable;\r\nimport androidx.appcompat.app.AppCompatActivity;\r\nimport androidx.fragment.app.Fragment;\r\nimport androidx.fragment.app.FragmentManager;\r\n\r\nimport com.jess.arms.base.delegate.IActivity;\r\nimport com.jess.arms.integration.cache.Cache;\r\nimport com.jess.arms.integration.cache.CacheType;\r\nimport com.jess.arms.integration.lifecycle.ActivityLifecycleable;\r\nimport com.jess.arms.mvp.IPresenter;\r\nimport com.jess.arms.utils.ArmsUtils;\r\nimport com.trello.rxlifecycle2.android.ActivityEvent;\r\n\r\nimport javax.inject.Inject;\r\n\r\nimport butterknife.ButterKnife;\r\nimport butterknife.Unbinder;\r\nimport io.reactivex.subjects.BehaviorSubject;\r\nimport io.reactivex.subjects.Subject;\r\n\r\nimport static com.jess.arms.utils.ThirdViewUtil.convertAutoView;\r\n\r\n/**\r\n * ================================================\r\n * 因为 Java 只能单继承, 所以如果要用到需要继承特定 {@link Activity} 的三方库, 那你就需要自己自定义 {@link Activity}\r\n * 继承于这个特定的 {@link Activity}, 然后再按照 {@link BaseActivity} 的格式, 将代码复制过去, 记住一定要实现{@link IActivity}\r\n *\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki\">请配合官方 Wiki 文档学习本框架</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog\">更新日志, 升级必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/Issues\">常见 Issues, 踩坑必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/ArmsComponent/wiki\">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>\r\n * Created by JessYan on 22/03/2016\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic abstract class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IActivity, ActivityLifecycleable {\r\n    protected final String TAG = this.getClass().getSimpleName();\r\n    private final BehaviorSubject<ActivityEvent> mLifecycleSubject = BehaviorSubject.create();\r\n    @Inject\r\n    @Nullable\r\n    protected P mPresenter;//如果当前页面逻辑简单, Presenter 可以为 null\r\n    private Cache<String, Object> mCache;\r\n    private Unbinder mUnbinder;\r\n\r\n    @NonNull\r\n    @Override\r\n    public synchronized Cache<String, Object> provideCache() {\r\n        if (mCache == null) {\r\n            //noinspection unchecked\r\n            mCache = ArmsUtils.obtainAppComponentFromContext(this).cacheFactory().build(CacheType.ACTIVITY_CACHE);\r\n        }\r\n        return mCache;\r\n    }\r\n\r\n    @NonNull\r\n    @Override\r\n    public final Subject<ActivityEvent> provideLifecycleSubject() {\r\n        return mLifecycleSubject;\r\n    }\r\n\r\n    @Override\r\n    public View onCreateView(String name, Context context, AttributeSet attrs) {\r\n        View view = convertAutoView(name, context, attrs);\r\n        return view == null ? super.onCreateView(name, context, attrs) : view;\r\n    }\r\n\r\n    @Override\r\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        try {\r\n            int layoutResID = initView(savedInstanceState);\r\n            //如果initView返回0,框架则不会调用setContentView(),当然也不会 Bind ButterKnife\r\n            if (layoutResID != 0) {\r\n                setContentView(layoutResID);\r\n                //绑定到butterknife\r\n                mUnbinder = ButterKnife.bind(this);\r\n            }\r\n        } catch (Exception e) {\r\n            if (e instanceof InflateException) {\r\n                throw e;\r\n            }\r\n            e.printStackTrace();\r\n        }\r\n        initData(savedInstanceState);\r\n    }\r\n\r\n    @Override\r\n    protected void onDestroy() {\r\n        super.onDestroy();\r\n        if (mUnbinder != null && mUnbinder != Unbinder.EMPTY) {\r\n            mUnbinder.unbind();\r\n        }\r\n        this.mUnbinder = null;\r\n        if (mPresenter != null) {\r\n            mPresenter.onDestroy();//释放资源\r\n        }\r\n        this.mPresenter = null;\r\n    }\r\n\r\n    /**\r\n     * 是否使用 EventBus\r\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\r\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\r\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\r\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\r\n     *\r\n     * @return 返回 {@code true} (默认为 {@code true}), Arms 会自动注册 EventBus\r\n     */\r\n    @Override\r\n    public boolean useEventBus() {\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * 这个 {@link Activity} 是否会使用 {@link Fragment}, 框架会根据这个属性判断是否注册 {@link FragmentManager.FragmentLifecycleCallbacks}\r\n     * 如果返回 {@code false}, 那意味着这个 {@link Activity} 不需要绑定 {@link Fragment}, 那你再在这个 {@link Activity} 中绑定继承于 {@link BaseFragment} 的 {@link Fragment} 将不起任何作用\r\n     *\r\n     * @return 返回 {@code true} (默认为 {@code true}), 则需要使用 {@link Fragment}\r\n     */\r\n    @Override\r\n    public boolean useFragment() {\r\n        return true;\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseApplication.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport android.app.Application;\r\nimport android.content.Context;\r\n\r\nimport androidx.annotation.NonNull;\r\n\r\nimport com.jess.arms.base.delegate.AppDelegate;\r\nimport com.jess.arms.base.delegate.AppLifecycles;\r\nimport com.jess.arms.di.component.AppComponent;\r\nimport com.jess.arms.utils.ArmsUtils;\r\nimport com.jess.arms.utils.Preconditions;\r\n\r\n/**\r\n * ================================================\r\n * MVPArms 是一个整合了大量主流开源项目的 Android MVP 快速搭建框架, 其中包含 Dagger2、Retrofit、RxJava 以及\r\n * RxLifecycle、RxCache 等 Rx 系三方库, 并且提供 UI 自适应方案, 本框架将它们结合起来, 并全部使用 Dagger2 管理\r\n * 并提供给开发者使用, 使用本框架开发您的项目, 就意味着您已经拥有一个 MVP + Dagger2 + Retrofit + RxJava 项目\r\n *\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki\">请配合官方 Wiki 文档学习本框架</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog\">更新日志, 升级必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/Issues\">常见 Issues, 踩坑必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/ArmsComponent/wiki\">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>\r\n * Created by JessYan on 22/03/2016\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class BaseApplication extends Application implements App {\r\n    private AppLifecycles mAppDelegate;\r\n\r\n    /**\r\n     * 这里会在 {@link BaseApplication#onCreate} 之前被调用,可以做一些较早的初始化\r\n     * 常用于 MultiDex 以及插件化框架的初始化\r\n     *\r\n     * @param base\r\n     */\r\n    @Override\r\n    protected void attachBaseContext(Context base) {\r\n        super.attachBaseContext(base);\r\n        if (mAppDelegate == null) {\r\n            this.mAppDelegate = new AppDelegate(base);\r\n        }\r\n        this.mAppDelegate.attachBaseContext(base);\r\n    }\r\n\r\n    @Override\r\n    public void onCreate() {\r\n        super.onCreate();\r\n        if (mAppDelegate != null) {\r\n            this.mAppDelegate.onCreate(this);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 在模拟环境中程序终止时会被调用\r\n     */\r\n    @Override\r\n    public void onTerminate() {\r\n        super.onTerminate();\r\n        if (mAppDelegate != null) {\r\n            this.mAppDelegate.onTerminate(this);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 将 {@link AppComponent} 返回出去, 供其它地方使用, {@link AppComponent} 接口中声明的方法所返回的实例, 在 {@link #getAppComponent()} 拿到对象后都可以直接使用\r\n     *\r\n     * @return AppComponent\r\n     * @see ArmsUtils#obtainAppComponentFromContext(Context) 可直接获取 {@link AppComponent}\r\n     */\r\n    @NonNull\r\n    @Override\r\n    public AppComponent getAppComponent() {\r\n        Preconditions.checkNotNull(mAppDelegate, \"%s cannot be null\", AppDelegate.class.getName());\r\n        Preconditions.checkState(mAppDelegate instanceof App, \"%s must be implements %s\", mAppDelegate.getClass().getName(), App.class.getName());\r\n        return ((App) mAppDelegate).getAppComponent();\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseFragment.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport android.content.Context;\r\nimport android.os.Bundle;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.annotation.Nullable;\r\nimport androidx.fragment.app.Fragment;\r\n\r\nimport com.jess.arms.base.delegate.IFragment;\r\nimport com.jess.arms.integration.cache.Cache;\r\nimport com.jess.arms.integration.cache.CacheType;\r\nimport com.jess.arms.integration.lifecycle.FragmentLifecycleable;\r\nimport com.jess.arms.mvp.IPresenter;\r\nimport com.jess.arms.utils.ArmsUtils;\r\nimport com.trello.rxlifecycle2.android.FragmentEvent;\r\n\r\nimport javax.inject.Inject;\r\n\r\nimport io.reactivex.subjects.BehaviorSubject;\r\nimport io.reactivex.subjects.Subject;\r\n\r\n/**\r\n * ================================================\r\n * 因为 Java 只能单继承, 所以如果要用到需要继承特定 @{@link Fragment} 的三方库, 那你就需要自己自定义 @{@link Fragment}\r\n * 继承于这个特定的 @{@link Fragment}, 然后再按照 {@link BaseFragment} 的格式, 将代码复制过去, 记住一定要实现{@link IFragment}\r\n *\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki\">请配合官方 Wiki 文档学习本框架</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog\">更新日志, 升级必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/Issues\">常见 Issues, 踩坑必看!</a>\r\n * @see <a href=\"https://github.com/JessYanCoding/ArmsComponent/wiki\">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>\r\n * Created by JessYan on 22/03/2016\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic abstract class BaseFragment<P extends IPresenter> extends Fragment implements IFragment, FragmentLifecycleable {\r\n    protected final String TAG = this.getClass().getSimpleName();\r\n    private final BehaviorSubject<FragmentEvent> mLifecycleSubject = BehaviorSubject.create();\r\n    protected Context mContext;\r\n    @Inject\r\n    @Nullable\r\n    protected P mPresenter;//如果当前页面逻辑简单, Presenter 可以为 null\r\n    private Cache<String, Object> mCache;\r\n\r\n    @NonNull\r\n    @Override\r\n    public synchronized Cache<String, Object> provideCache() {\r\n        if (mCache == null) {\r\n            //noinspection unchecked\r\n            mCache = ArmsUtils.obtainAppComponentFromContext(getActivity()).cacheFactory().build(CacheType.FRAGMENT_CACHE);\r\n        }\r\n        return mCache;\r\n    }\r\n\r\n    @NonNull\r\n    @Override\r\n    public final Subject<FragmentEvent> provideLifecycleSubject() {\r\n        return mLifecycleSubject;\r\n    }\r\n\r\n    @Override\r\n    public void onAttach(Context context) {\r\n        super.onAttach(context);\r\n        mContext = context;\r\n    }\r\n\r\n    @Nullable\r\n    @Override\r\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\r\n        return initView(inflater, container, savedInstanceState);\r\n    }\r\n\r\n    @Override\r\n    public void onDestroy() {\r\n        super.onDestroy();\r\n        if (mPresenter != null) {\r\n            mPresenter.onDestroy();//释放资源\r\n        }\r\n        this.mPresenter = null;\r\n    }\r\n\r\n    @Override\r\n    public void onDetach() {\r\n        super.onDetach();\r\n        mContext = null;\r\n    }\r\n\r\n    /**\r\n     * 是否使用 EventBus\r\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\r\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\r\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\r\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\r\n     *\r\n     * @return 返回 {@code true} (默认为 {@code true}), Arms 会自动注册 EventBus\r\n     */\r\n    @Override\r\n    public boolean useEventBus() {\r\n        return true;\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseHolder.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport android.view.View;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.recyclerview.widget.RecyclerView;\r\n\r\nimport com.jess.arms.utils.ThirdViewUtil;\r\nimport com.zhy.autolayout.utils.AutoUtils;\r\n\r\n/**\r\n * ================================================\r\n * 基类 {@link RecyclerView.ViewHolder}\r\n * <p>\r\n * Created by JessYan on 2015/11/24.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic abstract class BaseHolder<T> extends RecyclerView.ViewHolder implements View.OnClickListener {\r\n    protected final String TAG = this.getClass().getSimpleName();\r\n    protected OnViewClickListener mOnViewClickListener = null;\r\n\r\n    public BaseHolder(View itemView) {\r\n        super(itemView);\r\n        //点击事件\r\n        itemView.setOnClickListener(this);\r\n        //屏幕适配\r\n        if (ThirdViewUtil.isUseAutolayout()) {\r\n            AutoUtils.autoSize(itemView);\r\n        }\r\n        //绑定 ButterKnife\r\n        ThirdViewUtil.bindTarget(this, itemView);\r\n    }\r\n\r\n    /**\r\n     * 设置数据\r\n     *\r\n     * @param data     数据\r\n     * @param position 在 RecyclerView 中的位置\r\n     */\r\n    public abstract void setData(@NonNull T data, int position);\r\n\r\n    /**\r\n     * 在 Activity 的 onDestroy 中使用 {@link DefaultAdapter#releaseAllHolder(RecyclerView)} 方法 (super.onDestroy() 之前)\r\n     * {@link BaseHolder#onRelease()} 才会被调用, 可以在此方法中释放一些资源\r\n     */\r\n    protected void onRelease() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public void onClick(View view) {\r\n        if (mOnViewClickListener != null) {\r\n            mOnViewClickListener.onViewClick(view, this.getPosition());\r\n        }\r\n    }\r\n\r\n    public void setOnItemClickListener(OnViewClickListener listener) {\r\n        this.mOnViewClickListener = listener;\r\n    }\r\n\r\n    /**\r\n     * item 点击事件\r\n     */\r\n    public interface OnViewClickListener {\r\n\r\n        /**\r\n         * item 被点击\r\n         *\r\n         * @param view     被点击的 {@link View}\r\n         * @param position 在 RecyclerView 中的位置\r\n         */\r\n        void onViewClick(View view, int position);\r\n    }\r\n}"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseLazyLoadFragment.java",
    "content": "package com.jess.arms.base;\n\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.mvp.IPresenter;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\n/**\n * 子类覆写{@link BaseLazyLoadFragment}lazyLoadData可快速实现Fragment懒加载\n */\npublic abstract class BaseLazyLoadFragment<P extends IPresenter> extends BaseFragment<P> {\n\n    @Inject\n    Unused mUnused;\n\n    private boolean isViewCreated; // 界面是否已创建完成\n    private boolean isVisibleToUser; // 是否对用户可见\n    private boolean isDataLoaded; // 数据是否已请求\n\n    /**\n     * 第一次可见时触发调用,此处实现具体的数据请求逻辑\n     */\n    protected abstract void lazyLoadData();\n\n    @Override\n    public void setUserVisibleHint(boolean isVisibleToUser) {\n        super.setUserVisibleHint(isVisibleToUser);\n        this.isVisibleToUser = isVisibleToUser;\n        tryLoadData();\n    }\n\n    /**\n     * 保证在initData后触发\n     */\n    @Override\n    public void onResume() {\n        super.onResume();\n        isViewCreated = true;\n        tryLoadData();\n    }\n\n    /**\n     * ViewPager场景下，判断父fragment是否可见\n     */\n    private boolean isParentVisible() {\n        Fragment fragment = getParentFragment();\n        return fragment == null || (fragment instanceof BaseLazyLoadFragment && ((BaseLazyLoadFragment) fragment).isVisibleToUser);\n    }\n\n    /**\n     * ViewPager场景下，当前fragment可见时，如果其子fragment也可见，则让子fragment请求数据\n     */\n    private void dispatchParentVisibleState() {\n        FragmentManager fragmentManager = getChildFragmentManager();\n        List<Fragment> fragments = fragmentManager.getFragments();\n        if (fragments.isEmpty()) {\n            return;\n        }\n        for (Fragment child : fragments) {\n            if (child instanceof BaseLazyLoadFragment && ((BaseLazyLoadFragment) child).isVisibleToUser) {\n                ((BaseLazyLoadFragment) child).tryLoadData();\n            }\n        }\n    }\n\n    public void tryLoadData() {\n        if (isViewCreated && isVisibleToUser && isParentVisible() && !isDataLoaded) {\n            lazyLoadData();\n            isDataLoaded = true;\n            //通知子Fragment请求数据\n            dispatchParentVisibleState();\n        }\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/BaseService.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.integration.EventBusManager;\n\nimport io.reactivex.disposables.CompositeDisposable;\nimport io.reactivex.disposables.Disposable;\n\n/**\n * ================================================\n * 基类 {@link Service}\n * <p>\n * Created by jess on 2016/5/6.\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic abstract class BaseService extends Service {\n    protected final String TAG = this.getClass().getSimpleName();\n    protected CompositeDisposable mCompositeDisposable;\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        if (useEventBus()) {\n            EventBusManager.getInstance().register(this);\n        }\n        init();\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (useEventBus()) {\n            EventBusManager.getInstance().unregister(this);\n        }\n        unDispose();//解除订阅\n        this.mCompositeDisposable = null;\n    }\n\n    /**\n     * 是否使用 EventBus\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\n     *\n     * @return 返回 {@code true} (默认为 {@code true}), Arms 会自动注册 EventBus\n     */\n    public boolean useEventBus() {\n        return true;\n    }\n\n    protected void addDispose(Disposable disposable) {\n        if (mCompositeDisposable == null) {\n            mCompositeDisposable = new CompositeDisposable();\n        }\n        mCompositeDisposable.add(disposable);//将所有 Disposable 放入容器集中处理\n    }\n\n    protected void unDispose() {\n        if (mCompositeDisposable != null) {\n            mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅\n        }\n    }\n\n    /**\n     * 初始化\n     */\n    abstract public void init();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/DefaultAdapter.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.base;\r\n\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.recyclerview.widget.RecyclerView;\r\n\r\nimport org.jetbrains.annotations.NotNull;\r\n\r\nimport java.util.List;\r\n\r\n/**\r\n * ================================================\r\n * 基类 {@link RecyclerView.Adapter}, 如果需要实现非常复杂的 {@link RecyclerView}, 请尽量使用其他优秀的三方库\r\n * <p>\r\n * Created by jess on 2015/11/27.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic abstract class DefaultAdapter<T> extends RecyclerView.Adapter<BaseHolder<T>> {\r\n    protected List<T> mInfos;\r\n    protected OnRecyclerViewItemClickListener mOnItemClickListener = null;\r\n\r\n    public DefaultAdapter(List<T> infos) {\r\n        super();\r\n        this.mInfos = infos;\r\n    }\r\n\r\n    /**\r\n     * 遍历所有 {@link BaseHolder}, 释放他们需要释放的资源\r\n     *\r\n     * @param recyclerView {@link RecyclerView}\r\n     */\r\n    public static void releaseAllHolder(RecyclerView recyclerView) {\r\n        if (recyclerView == null) {\r\n            return;\r\n        }\r\n        for (int i = recyclerView.getChildCount() - 1; i >= 0; i--) {\r\n            final View view = recyclerView.getChildAt(i);\r\n            RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);\r\n            if (viewHolder instanceof BaseHolder) {\r\n                ((BaseHolder) viewHolder).onRelease();\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 创建 {@link BaseHolder}\r\n     *\r\n     * @param parent   父容器\r\n     * @param viewType 布局类型\r\n     * @return {@link BaseHolder}\r\n     */\r\n    @NotNull\r\n    @Override\r\n    public BaseHolder<T> onCreateViewHolder(ViewGroup parent, final int viewType) {\r\n        View view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(viewType), parent, false);\r\n        BaseHolder<T> mHolder = getHolder(view, viewType);\r\n        //设置Item点击事件\r\n        mHolder.setOnItemClickListener((view1, position) -> {\r\n            if (mOnItemClickListener != null && mInfos.size() > 0) {\r\n                //noinspection unchecked\r\n                mOnItemClickListener.onItemClick(view1, viewType, mInfos.get(position), position);\r\n            }\r\n        });\r\n        return mHolder;\r\n    }\r\n\r\n    /**\r\n     * 绑定数据\r\n     *\r\n     * @param holder   {@link BaseHolder}\r\n     * @param position 在 RecyclerView 中的位置\r\n     */\r\n    @Override\r\n    public void onBindViewHolder(BaseHolder<T> holder, int position) {\r\n        holder.setData(mInfos.get(position), position);\r\n    }\r\n\r\n    /**\r\n     * 返回数据总个数\r\n     *\r\n     * @return 数据总个数\r\n     */\r\n    @Override\r\n    public int getItemCount() {\r\n        return mInfos.size();\r\n    }\r\n\r\n    /**\r\n     * 返回数据集合\r\n     *\r\n     * @return 数据集合\r\n     */\r\n    public List<T> getInfos() {\r\n        return mInfos;\r\n    }\r\n\r\n    /**\r\n     * 获得 RecyclerView 中某个 position 上的 item 数据\r\n     *\r\n     * @param position 在 RecyclerView 中的位置\r\n     * @return 数据\r\n     */\r\n    public T getItem(int position) {\r\n        return mInfos == null ? null : mInfos.get(position);\r\n    }\r\n\r\n    /**\r\n     * 让子类实现用以提供 {@link BaseHolder}\r\n     *\r\n     * @param v        用于展示的 {@link View}\r\n     * @param viewType 布局类型\r\n     * @return {@link BaseHolder}\r\n     */\r\n    @NonNull\r\n    public abstract BaseHolder<T> getHolder(@NonNull View v, int viewType);\r\n\r\n    /**\r\n     * 提供用于 item 布局的 {@code layoutId}\r\n     *\r\n     * @param viewType 布局类型\r\n     * @return 布局 id\r\n     */\r\n    public abstract int getLayoutId(int viewType);\r\n\r\n    /**\r\n     * 设置 item 点击事件\r\n     *\r\n     * @param listener\r\n     */\r\n    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {\r\n        this.mOnItemClickListener = listener;\r\n    }\r\n\r\n    /**\r\n     * item 点击事件\r\n     *\r\n     * @param <T>\r\n     */\r\n    public interface OnRecyclerViewItemClickListener<T> {\r\n\r\n        /**\r\n         * item 被点击\r\n         *\r\n         * @param view     被点击的 {@link View}\r\n         * @param viewType 布局类型\r\n         * @param data     数据\r\n         * @param position 在 RecyclerView 中的位置\r\n         */\r\n        void onItemClick(@NonNull View view, int viewType, @NonNull T data, int position);\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/Platform.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base;\n\n/**\n * ================================================\n * Created by JessYan on 2018/7/27 15:32\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class Platform {\n    public static final boolean DEPENDENCY_AUTO_LAYOUT;\n    public static final boolean DEPENDENCY_SUPPORT_DESIGN;\n    public static final boolean DEPENDENCY_GLIDE;\n    public static final boolean DEPENDENCY_ANDROID_EVENTBUS;\n    public static final boolean DEPENDENCY_EVENTBUS;\n\n    static {\n        DEPENDENCY_AUTO_LAYOUT = findClassByClassName(\"com.zhy.autolayout.AutoLayoutInfo\");\n        DEPENDENCY_SUPPORT_DESIGN = findClassByClassName(\"com.google.android.material.snackbar.Snackbar\");\n        DEPENDENCY_GLIDE = findClassByClassName(\"com.bumptech.glide.Glide\");\n        DEPENDENCY_ANDROID_EVENTBUS = findClassByClassName(\"org.simple.eventbus.EventBus\");\n        DEPENDENCY_EVENTBUS = findClassByClassName(\"org.greenrobot.eventbus.EventBus\");\n    }\n\n    private static boolean findClassByClassName(String className) {\n        boolean hasDependency;\n        try {\n            Class.forName(className);\n            hasDependency = true;\n        } catch (ClassNotFoundException e) {\n            hasDependency = false;\n        }\n        return hasDependency;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/Unused.java",
    "content": "package com.jess.arms.base;\n\nimport javax.inject.Inject;\n\n/**\n * Created by yexiaokang on 2019/11/12.\n */\npublic class Unused {\n\n    @Inject\n    public Unused() {\n\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/ActivityDelegate.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/**\n * ================================================\n * {@link Activity} 代理类,用于框架内部在每个 {@link Activity} 的对应生命周期中插入需要的逻辑\n *\n * @see ActivityDelegateImpl\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.13\">ActivityDelegate wiki 官方文档</a>\n * Created by JessYan on 26/04/2017 20:23\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface ActivityDelegate {\n    String LAYOUT_LINEARLAYOUT = \"LinearLayout\";\n    String LAYOUT_FRAMELAYOUT = \"FrameLayout\";\n    String LAYOUT_RELATIVELAYOUT = \"RelativeLayout\";\n    String ACTIVITY_DELEGATE = \"ACTIVITY_DELEGATE\";\n\n    void onCreate(@Nullable Bundle savedInstanceState);\n\n    void onStart();\n\n    void onResume();\n\n    void onPause();\n\n    void onStop();\n\n    void onSaveInstanceState(@NonNull Bundle outState);\n\n    void onDestroy();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/ActivityDelegateImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.integration.EventBusManager;\nimport com.jess.arms.utils.ArmsUtils;\n\n/**\n * ================================================\n * {@link ActivityDelegate} 默认实现类\n * <p>\n * Created by JessYan on 26/04/2017 20:23\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ActivityDelegateImpl implements ActivityDelegate {\n    private Activity mActivity;\n    private IActivity iActivity;\n\n    public ActivityDelegateImpl(@NonNull Activity activity) {\n        this.mActivity = activity;\n        this.iActivity = (IActivity) activity;\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        //如果要使用 EventBus 请将此方法返回 true\n        if (iActivity.useEventBus()) {\n            //注册到事件主线\n            EventBusManager.getInstance().register(mActivity);\n        }\n\n        //这里提供 AppComponent 对象给 BaseActivity 的子类, 用于 Dagger2 的依赖注入\n        iActivity.setupActivityComponent(ArmsUtils.obtainAppComponentFromContext(mActivity));\n    }\n\n    @Override\n    public void onStart() {\n\n    }\n\n    @Override\n    public void onResume() {\n\n    }\n\n    @Override\n    public void onPause() {\n\n    }\n\n    @Override\n    public void onStop() {\n\n    }\n\n    @Override\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n\n    }\n\n    @Override\n    public void onDestroy() {\n        //如果要使用 EventBus 请将此方法返回 true\n        if (iActivity != null && iActivity.useEventBus()) {\n            EventBusManager.getInstance().unregister(mActivity);\n        }\n        this.iActivity = null;\n        this.mActivity = null;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/AppDelegate.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.Service;\nimport android.content.ComponentCallbacks2;\nimport android.content.ContentProvider;\nimport android.content.Context;\nimport android.content.res.Configuration;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\n\nimport com.jess.arms.base.App;\nimport com.jess.arms.base.BaseApplication;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.di.component.DaggerAppComponent;\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.integration.ConfigModule;\nimport com.jess.arms.integration.ManifestParser;\nimport com.jess.arms.integration.cache.IntelligentCache;\nimport com.jess.arms.utils.ArmsUtils;\nimport com.jess.arms.utils.Preconditions;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.inject.Inject;\nimport javax.inject.Named;\n\n/**\n * ================================================\n * AppDelegate 可以代理 Application 的生命周期,在对应的生命周期,执行对应的逻辑,因为 Java 只能单继承\n * 所以当遇到某些三方库需要继承于它的 Application 的时候,就只有自定义 Application 并继承于三方库的 Application\n * 这时就不用再继承 BaseApplication,只用在自定义Application中对应的生命周期调用AppDelegate对应的方法\n * (Application一定要实现APP接口),框架就能照常运行\n *\n * @see BaseApplication\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.12\">AppDelegate wiki 官方文档</a>\n * Created by JessYan on 24/04/2017 09:44\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AppDelegate implements App, AppLifecycles {\n    @Inject\n    @Named(\"ActivityLifecycle\")\n    protected Application.ActivityLifecycleCallbacks mActivityLifecycle;\n    @Inject\n    @Named(\"ActivityLifecycleForRxLifecycle\")\n    protected Application.ActivityLifecycleCallbacks mActivityLifecycleForRxLifecycle;\n    private Application mApplication;\n    private AppComponent mAppComponent;\n    private List<ConfigModule> mModules;\n    private List<AppLifecycles> mAppLifecycles = new ArrayList<>();\n    private List<Application.ActivityLifecycleCallbacks> mActivityLifecycles = new ArrayList<>();\n    private ComponentCallbacks2 mComponentCallback;\n\n    public AppDelegate(@NonNull Context context) {\n\n        //用反射, 将 AndroidManifest.xml 中带有 ConfigModule 标签的 class 转成对象集合（List<ConfigModule>）\n        this.mModules = new ManifestParser(context).parse();\n\n        //遍历之前获得的集合, 执行每一个 ConfigModule 实现类的某些方法\n        for (ConfigModule module : mModules) {\n\n            //将框架外部, 开发者实现的 Application 的生命周期回调 (AppLifecycles) 存入 mAppLifecycles 集合 (此时还未注册回调)\n            module.injectAppLifecycle(context, mAppLifecycles);\n\n            //将框架外部, 开发者实现的 Activity 的生命周期回调 (ActivityLifecycleCallbacks) 存入 mActivityLifecycles 集合 (此时还未注册回调)\n            module.injectActivityLifecycle(context, mActivityLifecycles);\n        }\n    }\n\n    @Override\n    public void attachBaseContext(@NonNull Context base) {\n\n        //遍历 mAppLifecycles, 执行所有已注册的 AppLifecycles 的 attachBaseContext() 方法 (框架外部, 开发者扩展的逻辑)\n        for (AppLifecycles lifecycle : mAppLifecycles) {\n            lifecycle.attachBaseContext(base);\n        }\n    }\n\n    @Override\n    public void onCreate(@NonNull Application application) {\n        this.mApplication = application;\n        mAppComponent = DaggerAppComponent\n                .builder()\n                .application(mApplication)//提供application\n                .globalConfigModule(getGlobalConfigModule(mApplication, mModules))//全局配置\n                .build();\n        mAppComponent.inject(this);\n\n        //将 ConfigModule 的实现类的集合存放到缓存 Cache, 可以随时获取\n        //使用 IntelligentCache.KEY_KEEP 作为 key 的前缀, 可以使储存的数据永久存储在内存中\n        //否则存储在 LRU 算法的存储空间中 (大于或等于缓存所能允许的最大 size, 则会根据 LRU 算法清除之前的条目)\n        //前提是 extras 使用的是 IntelligentCache (框架默认使用)\n        mAppComponent.extras().put(IntelligentCache.getKeyOfKeep(ConfigModule.class.getName()), mModules);\n\n        this.mModules = null;\n\n        //注册框架内部已实现的 Activity 生命周期逻辑\n        mApplication.registerActivityLifecycleCallbacks(mActivityLifecycle);\n\n        //注册框架内部已实现的 RxLifecycle 逻辑\n        mApplication.registerActivityLifecycleCallbacks(mActivityLifecycleForRxLifecycle);\n\n        //注册框架外部, 开发者扩展的 Activity 生命周期逻辑\n        //每个 ConfigModule 的实现类可以声明多个 Activity 的生命周期回调\n        //也可以有 N 个 ConfigModule 的实现类 (完美支持组件化项目 各个 Module 的各种独特需求)\n        for (Application.ActivityLifecycleCallbacks lifecycle : mActivityLifecycles) {\n            mApplication.registerActivityLifecycleCallbacks(lifecycle);\n        }\n\n        mComponentCallback = new AppComponentCallbacks(mApplication, mAppComponent);\n\n        //注册回掉: 内存紧张时释放部分内存\n        mApplication.registerComponentCallbacks(mComponentCallback);\n\n        //执行框架外部, 开发者扩展的 App onCreate 逻辑\n        for (AppLifecycles lifecycle : mAppLifecycles) {\n            lifecycle.onCreate(mApplication);\n        }\n    }\n\n    @Override\n    public void onTerminate(@NonNull Application application) {\n        if (mActivityLifecycle != null) {\n            mApplication.unregisterActivityLifecycleCallbacks(mActivityLifecycle);\n        }\n        if (mActivityLifecycleForRxLifecycle != null) {\n            mApplication.unregisterActivityLifecycleCallbacks(mActivityLifecycleForRxLifecycle);\n        }\n        if (mComponentCallback != null) {\n            mApplication.unregisterComponentCallbacks(mComponentCallback);\n        }\n        if (mActivityLifecycles != null && mActivityLifecycles.size() > 0) {\n            for (Application.ActivityLifecycleCallbacks lifecycle : mActivityLifecycles) {\n                mApplication.unregisterActivityLifecycleCallbacks(lifecycle);\n            }\n        }\n        if (mAppLifecycles != null && mAppLifecycles.size() > 0) {\n            for (AppLifecycles lifecycle : mAppLifecycles) {\n                lifecycle.onTerminate(mApplication);\n            }\n        }\n        this.mAppComponent = null;\n        this.mActivityLifecycle = null;\n        this.mActivityLifecycleForRxLifecycle = null;\n        this.mActivityLifecycles = null;\n        this.mComponentCallback = null;\n        this.mAppLifecycles = null;\n        this.mApplication = null;\n    }\n\n    /**\n     * 将app的全局配置信息封装进module(使用Dagger注入到需要配置信息的地方)\n     * 需要在AndroidManifest中声明{@link ConfigModule}的实现类,和Glide的配置方式相似\n     *\n     * @return GlobalConfigModule\n     */\n    private GlobalConfigModule getGlobalConfigModule(Context context, List<ConfigModule> modules) {\n        GlobalConfigModule.Builder builder = GlobalConfigModule\n                .builder();\n\n        //遍历 ConfigModule 集合, 给全局配置 GlobalConfigModule 添加参数\n        for (ConfigModule module : modules) {\n            module.applyOptions(context, builder);\n        }\n\n        return builder.build();\n    }\n\n    /**\n     * 将 {@link AppComponent} 返回出去, 供其它地方使用, {@link AppComponent} 接口中声明的方法返回的实例, 在 {@link #getAppComponent()} 拿到对象后都可以直接使用\n     *\n     * @return AppComponent\n     * @see ArmsUtils#obtainAppComponentFromContext(Context) 可直接获取 {@link AppComponent}\n     */\n    @NonNull\n    @Override\n    public AppComponent getAppComponent() {\n        Preconditions.checkNotNull(mAppComponent,\n                \"%s == null, first call %s#onCreate(Application) in %s#onCreate()\",\n                AppComponent.class.getName(), getClass().getName(), mApplication == null\n                        ? Application.class.getName() : mApplication.getClass().getName());\n        return mAppComponent;\n    }\n\n    /**\n     * {@link ComponentCallbacks2} 是一个细粒度的内存回收管理回调\n     * {@link Application}、{@link Activity}、{@link Service}、{@link ContentProvider}、{@link Fragment} 实现了 {@link ComponentCallbacks2} 接口\n     * 开发者应该实现 {@link ComponentCallbacks2#onTrimMemory(int)} 方法, 细粒度 release 内存, 参数的值不同可以体现出不同程度的内存可用情况\n     * 响应 {@link ComponentCallbacks2#onTrimMemory(int)} 回调, 开发者的 App 会存活的更持久, 有利于用户体验\n     * 不响应 {@link ComponentCallbacks2#onTrimMemory(int)} 回调, 系统 kill 掉进程的几率更大\n     */\n    private static class AppComponentCallbacks implements ComponentCallbacks2 {\n\n        AppComponentCallbacks(Application application, AppComponent appComponent) {\n        }\n\n        /**\n         * 在你的 App 生命周期的任何阶段, {@link ComponentCallbacks2#onTrimMemory(int)} 发生的回调都预示着你设备的内存资源已经开始紧张\n         * 你应该根据 {@link ComponentCallbacks2#onTrimMemory(int)} 发生回调时的内存级别来进一步决定释放哪些资源\n         * {@link ComponentCallbacks2#onTrimMemory(int)} 的回调可以发生在 {@link Application}、{@link Activity}、{@link Service}、{@link ContentProvider}、{@link Fragment}\n         *\n         * @param level 内存级别\n         * @see <a href=\"https://developer.android.com/reference/android/content/ComponentCallbacks2.html#TRIM_MEMORY_RUNNING_MODERATE\">level 官方文档</a>\n         */\n        @Override\n        public void onTrimMemory(int level) {\n            //状态1. 当开发者的 App 正在运行\n            //设备开始运行缓慢, 不会被 kill, 也不会被列为可杀死的, 但是设备此时正运行于低内存状态下, 系统开始触发杀死 LRU 列表中的进程的机制\n//                case TRIM_MEMORY_RUNNING_MODERATE:\n\n\n            //设备运行更缓慢了, 不会被 kill, 但请你回收 unused 资源, 以便提升系统的性能, 你应该释放不用的资源用来提升系统性能 (但是这也会直接影响到你的 App 的性能)\n//                case TRIM_MEMORY_RUNNING_LOW:\n\n\n            //设备运行特别慢, 当前 App 还不会被杀死, 但是系统已经把 LRU 列表中的大多数进程都已经杀死, 因此你应该立即释放所有非必须的资源\n            //如果系统不能回收到足够的 RAM 数量, 系统将会清除所有的 LRU 列表中的进程, 并且开始杀死那些之前被认为不应该杀死的进程, 例如那个包含了一个运行态 Service 的进程\n//                case TRIM_MEMORY_RUNNING_CRITICAL:\n\n\n            //状态2. 当前 App UI 不再可见, 这是一个回收大个资源的好时机\n//                case TRIM_MEMORY_UI_HIDDEN:\n\n\n            //状态3. 当前的 App 进程被置于 Background LRU 列表中\n            //进程位于 LRU 列表的上端, 尽管你的 App 进程并不是处于被杀掉的高危险状态, 但系统可能已经开始杀掉 LRU 列表中的其他进程了\n            //你应该释放那些容易恢复的资源, 以便于你的进程可以保留下来, 这样当用户回退到你的 App 的时候才能够迅速恢复\n//                case TRIM_MEMORY_BACKGROUND:\n\n\n            //系统正运行于低内存状态并且你的进程已经已经接近 LRU 列表的中部位置, 如果系统的内存开始变得更加紧张, 你的进程是有可能被杀死的\n//                case TRIM_MEMORY_MODERATE:\n\n\n            //系统正运行于低内存的状态并且你的进程正处于 LRU 列表中最容易被杀掉的位置, 你应该释放任何不影响你的 App 恢复状态的资源\n            //低于 API 14 的 App 可以使用 onLowMemory 回调\n//                case TRIM_MEMORY_COMPLETE:\n        }\n\n        @Override\n        public void onConfigurationChanged(Configuration newConfig) {\n\n        }\n\n        /**\n         * 当系统开始清除 LRU 列表中的进程时, 尽管它会首先按照 LRU 的顺序来清除, 但是它同样会考虑进程的内存使用量, 因此消耗越少的进程则越容易被留下来\n         * {@link ComponentCallbacks2#onTrimMemory(int)} 的回调是在 API 14 才被加进来的, 对于老的版本, 你可以使用 {@link ComponentCallbacks2#onLowMemory} 方法来进行兼容\n         * {@link ComponentCallbacks2#onLowMemory} 相当于 {@code onTrimMemory(TRIM_MEMORY_COMPLETE)}\n         *\n         * @see #TRIM_MEMORY_COMPLETE\n         */\n        @Override\n        public void onLowMemory() {\n            //系统正运行于低内存的状态并且你的进程正处于 LRU 列表中最容易被杀掉的位置, 你应该释放任何不影响你的 App 恢复状态的资源\n        }\n    }\n}\n\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/AppLifecycles.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\n/**\n * ================================================\n * 用于代理 {@link Application} 的生命周期\n *\n * @see AppDelegate\n * Created by JessYan on 18/07/2017 17:43\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface AppLifecycles {\n    void attachBaseContext(@NonNull Context base);\n\n    void onCreate(@NonNull Application application);\n\n    void onTerminate(@NonNull Application application);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/FragmentDelegate.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\n/**\n * ================================================\n * {@link Fragment} 代理类,用于框架内部在每个 {@link Fragment} 的对应生命周期中插入需要的逻辑\n *\n * @see FragmentDelegateImpl\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.13\">FragmentDelegate wiki 官方文档</a>\n * Created by JessYan on 29/04/2017 14:30\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface FragmentDelegate {\n    String FRAGMENT_DELEGATE = \"FRAGMENT_DELEGATE\";\n\n    void onAttach(@NonNull Context context);\n\n    void onCreate(@Nullable Bundle savedInstanceState);\n\n    void onCreateView(@Nullable View view, @Nullable Bundle savedInstanceState);\n\n    void onActivityCreate(@Nullable Bundle savedInstanceState);\n\n    void onStart();\n\n    void onResume();\n\n    void onPause();\n\n    void onStop();\n\n    void onSaveInstanceState(@NonNull Bundle outState);\n\n    void onDestroyView();\n\n    void onDestroy();\n\n    void onDetach();\n\n    /**\n     * Return true if the fragment is currently added to its activity.\n     */\n    boolean isAdded();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/FragmentDelegateImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.integration.EventBusManager;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport butterknife.ButterKnife;\nimport butterknife.Unbinder;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * {@link FragmentDelegate} 默认实现类\n * <p>\n * Created by JessYan on 29/04/2017 16:12\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class FragmentDelegateImpl implements FragmentDelegate {\n    private FragmentManager mFragmentManager;\n    private Fragment mFragment;\n    private IFragment iFragment;\n    private Unbinder mUnbinder;\n\n    public FragmentDelegateImpl(@NonNull FragmentManager fragmentManager, @NonNull Fragment fragment) {\n        this.mFragmentManager = fragmentManager;\n        this.mFragment = fragment;\n        this.iFragment = (IFragment) fragment;\n    }\n\n    @Override\n    public void onAttach(@NonNull Context context) {\n\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        if (iFragment.useEventBus())//如果要使用eventbus请将此方法返回true\n        {\n            EventBusManager.getInstance().register(mFragment);//注册到事件主线\n        }\n        iFragment.setupFragmentComponent(ArmsUtils.obtainAppComponentFromContext(mFragment.getActivity()));\n    }\n\n    @Override\n    public void onCreateView(@Nullable View view, @Nullable Bundle savedInstanceState) {\n        //绑定到butterknife\n        if (view != null) {\n            mUnbinder = ButterKnife.bind(mFragment, view);\n        }\n    }\n\n    @Override\n    public void onActivityCreate(@Nullable Bundle savedInstanceState) {\n        iFragment.initData(savedInstanceState);\n    }\n\n    @Override\n    public void onStart() {\n\n    }\n\n    @Override\n    public void onResume() {\n\n    }\n\n    @Override\n    public void onPause() {\n\n    }\n\n    @Override\n    public void onStop() {\n\n    }\n\n    @Override\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n\n    }\n\n    @Override\n    public void onDestroyView() {\n        if (mUnbinder != null && mUnbinder != Unbinder.EMPTY) {\n            try {\n                mUnbinder.unbind();\n            } catch (IllegalStateException e) {\n                e.printStackTrace();\n                //fix Bindings already cleared\n                Timber.w(\"onDestroyView: %s\", e.getMessage());\n            }\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        if (iFragment != null && iFragment.useEventBus())//如果要使用eventbus请将此方法返回true\n        {\n            EventBusManager.getInstance().unregister(mFragment);//注册到事件主线\n        }\n        this.mUnbinder = null;\n        this.mFragmentManager = null;\n        this.mFragment = null;\n        this.iFragment = null;\n    }\n\n    @Override\n    public void onDetach() {\n\n    }\n\n    /**\n     * Return true if the fragment is currently added to its activity.\n     */\n    @Override\n    public boolean isAdded() {\n        return mFragment != null && mFragment.isAdded();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/IActivity.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.base.BaseActivity;\nimport com.jess.arms.base.BaseFragment;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.integration.ActivityLifecycle;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.LruCache;\n\n/**\n * ================================================\n * 框架要求框架中的每个 {@link Activity} 都需要实现此类,以满足规范\n *\n * @see BaseActivity\n * Created by JessYan on 26/04/2017 21:42\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IActivity {\n\n    /**\n     * 提供在 {@link Activity} 生命周期内的缓存容器, 可向此 {@link Activity} 存取一些必要的数据\n     * 此缓存容器和 {@link Activity} 的生命周期绑定, 如果 {@link Activity} 在屏幕旋转或者配置更改的情况下\n     * 重新创建, 那此缓存容器中的数据也会被清空, 如果你想避免此种情况请使用 <a href=\"https://github.com/JessYanCoding/LifecycleModel\">LifecycleModel</a>\n     *\n     * @return like {@link LruCache}\n     */\n    @NonNull\n    Cache<String, Object> provideCache();\n\n    /**\n     * 提供 AppComponent (提供所有的单例对象) 给实现类, 进行 Component 依赖\n     *\n     * @param appComponent\n     */\n    void setupActivityComponent(@NonNull AppComponent appComponent);\n\n    /**\n     * 是否使用 EventBus\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\n     *\n     * @return 返回 {@code true}, Arms 会自动注册 EventBus\n     */\n    boolean useEventBus();\n\n    /**\n     * 初始化 View, 如果 {@link #initView(Bundle)} 返回 0, 框架则不会调用 {@link Activity#setContentView(int)}\n     *\n     * @param savedInstanceState\n     * @return\n     */\n    int initView(@Nullable Bundle savedInstanceState);\n\n    /**\n     * 初始化数据\n     *\n     * @param savedInstanceState\n     */\n    void initData(@Nullable Bundle savedInstanceState);\n\n    /**\n     * 这个 Activity 是否会使用 Fragment,框架会根据这个属性判断是否注册 {@link FragmentManager.FragmentLifecycleCallbacks}\n     * 如果返回{@code false},那意味着这个 Activity 不需要绑定 Fragment,那你再在这个 Activity 中绑定继承于 {@link BaseFragment} 的 Fragment 将不起任何作用\n     *\n     * @return\n     * @see ActivityLifecycle#registerFragmentCallbacks (Fragment 的注册过程)\n     */\n    boolean useFragment();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/base/delegate/IFragment.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.base.delegate;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.Message;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport com.jess.arms.base.BaseFragment;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.LruCache;\n\n/**\n * ================================================\n * 框架要求框架中的每个 {@link Fragment} 都需要实现此类,以满足规范\n *\n * @see BaseFragment\n * Created by JessYan on 29/04/2017 14:31\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IFragment {\n\n    /**\n     * 提供在 {@link Fragment} 生命周期内的缓存容器, 可向此 {@link Fragment} 存取一些必要的数据\n     * 此缓存容器和 {@link Fragment} 的生命周期绑定, 如果 {@link Fragment} 在屏幕旋转或者配置更改的情况下\n     * 重新创建, 那此缓存容器中的数据也会被清空, 如果你想避免此种情况请使用 <a href=\"https://github.com/JessYanCoding/LifecycleModel\">LifecycleModel</a>\n     *\n     * @return like {@link LruCache}\n     */\n    @NonNull\n    Cache<String, Object> provideCache();\n\n    /**\n     * 提供 AppComponent (提供所有的单例对象) 给实现类, 进行 Component 依赖\n     *\n     * @param appComponent\n     */\n    void setupFragmentComponent(@NonNull AppComponent appComponent);\n\n    /**\n     * 是否使用 EventBus\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\n     *\n     * @return 返回 {@code true}, Arms 会自动注册 EventBus\n     */\n    boolean useEventBus();\n\n    /**\n     * 初始化 View\n     *\n     * @param inflater\n     * @param container\n     * @param savedInstanceState\n     * @return\n     */\n    View initView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);\n\n    /**\n     * 初始化数据\n     *\n     * @param savedInstanceState\n     */\n    void initData(@Nullable Bundle savedInstanceState);\n\n    /**\n     * 通过此方法可以使 Fragment 能够与外界做一些交互和通信, 比如说外部的 Activity 想让自己持有的某个 Fragment 对象执行一些方法,\n     * 建议在有多个需要与外界交互的方法时, 统一传 {@link Message}, 通过 what 字段来区分不同的方法, 在 {@link #setData(Object)}\n     * 方法中就可以 {@code switch} 做不同的操作, 这样就可以用统一的入口方法做多个不同的操作, 可以起到分发的作用\n     * <p>\n     * 调用此方法时请注意调用时 Fragment 的生命周期, 如果调用 {@link #setData(Object)} 方法时 {@link Fragment#onCreate(Bundle)} 还没执行\n     * 但在 {@link #setData(Object)} 里却调用了 Presenter 的方法, 是会报空的, 因为 Dagger 注入是在 {@link Fragment#onCreate(Bundle)} 方法中执行的\n     * 然后才创建的 Presenter, 如果要做一些初始化操作,可以不必让外部调用 {@link #setData(Object)}, 在 {@link #initData(Bundle)} 中初始化就可以了\n     * <p>\n     * Example usage:\n     * <pre>\n     * public void setData(@Nullable Object data) {\n     *     if (data != null && data instanceof Message) {\n     *         switch (((Message) data).what) {\n     *             case 0:\n     *                 loadData(((Message) data).arg1);\n     *                 break;\n     *             case 1:\n     *                 refreshUI();\n     *                 break;\n     *             default:\n     *                 //do something\n     *                 break;\n     *         }\n     *     }\n     * }\n     *\n     * // call setData(Object):\n     * Message data = new Message();\n     * data.what = 0;\n     * data.arg1 = 1;\n     * fragment.setData(data);\n     * </pre>\n     * <p>\n     * {@link #setData(Object)} 框架是不会调用的, 是拿给开发者自己去调用的, 让 {@link Activity} 或者其他类可以和 {@link Fragment} 通信,\n     * 并且因为 {@link #setData(Object)} 是 {@link IFragment} 的方法, 所以你可以通过多态, 持有父类,\n     * 不持有具体子类的方式就可以和子类 {@link Fragment} 通信, 这样如果需要替换子类, 就不会影响到其他地方,\n     * 并且 {@link #setData(Object)} 可以通过传入 {@link Message} 作为参数, 使外部统一调用 {@link #setData(Object)},\n     * 方法内部再通过 {@code switch(message.what)} 的方式, 从而在外部调用方式不变的情况下, 却可以扩展更多的方法,\n     * 让方法扩展更多的参数, 这样不管 {@link Fragment} 子类怎么变, 它内部的方法以及方法的参数怎么变, 却不会影响到外部调用的任何一行代码\n     *\n     * @param data 当不需要参数时 {@code data} 可以为 {@code null}\n     */\n    void setData(@Nullable Object data);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/component/AppComponent.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.di.component;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.Context;\n\nimport com.google.gson.Gson;\nimport com.jess.arms.base.delegate.AppDelegate;\nimport com.jess.arms.di.module.AppModule;\nimport com.jess.arms.di.module.ClientModule;\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\nimport com.jess.arms.http.imageloader.ImageLoader;\nimport com.jess.arms.integration.AppManager;\nimport com.jess.arms.integration.ConfigModule;\nimport com.jess.arms.integration.IRepositoryManager;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport java.io.File;\nimport java.util.concurrent.ExecutorService;\n\nimport javax.inject.Singleton;\n\nimport dagger.BindsInstance;\nimport dagger.Component;\nimport me.jessyan.rxerrorhandler.core.RxErrorHandler;\nimport okhttp3.OkHttpClient;\n\n/**\n * ================================================\n * 可通过 {@link ArmsUtils#obtainAppComponentFromContext(Context)} 拿到此接口的实现类\n * 拥有此接口的实现类即可调用对应的方法拿到 Dagger 提供的对应实例\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.2\">AppComponent wiki 官方文档</a>\n * Created by JessYan on 8/4/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\n@Component(modules = {AppModule.class, ClientModule.class, GlobalConfigModule.class})\npublic interface AppComponent {\n    Application application();\n\n    /**\n     * 用于管理所有 {@link Activity}\n     * 之前 {@link AppManager} 使用 Dagger 保证单例, 只能使用 {@link AppComponent#appManager()} 访问\n     * 现在直接将 AppManager 独立为单例类, 可以直接通过静态方法 {@link AppManager#getAppManager()} 访问, 更加方便\n     * 但为了不影响之前使用 {@link AppComponent#appManager()} 获取 {@link AppManager} 的项目, 所以暂时保留这种访问方式\n     *\n     * @return {@link AppManager}\n     * @deprecated Use {@link AppManager#getAppManager()} instead\n     */\n    @Deprecated\n    AppManager appManager();\n\n    /**\n     * 用于管理网络请求层, 以及数据缓存层\n     *\n     * @return {@link IRepositoryManager}\n     */\n    IRepositoryManager repositoryManager();\n\n    /**\n     * RxJava 错误处理管理类\n     *\n     * @return {@link RxErrorHandler}\n     */\n    RxErrorHandler rxErrorHandler();\n\n    /**\n     * 图片加载管理器, 用于加载图片的管理类, 使用策略者模式, 可在运行时动态替换任何图片加载框架\n     * arms-imageloader-glide 提供 Glide 的策略实现类, 也可以自行实现\n     * 需要在 {@link ConfigModule#applyOptions(Context, GlobalConfigModule.Builder)} 中\n     * 手动注册 {@link BaseImageLoaderStrategy}, {@link ImageLoader} 才能正常使用\n     *\n     * @return\n     */\n    ImageLoader imageLoader();\n\n    /**\n     * 网络请求框架\n     *\n     * @return {@link OkHttpClient}\n     */\n    OkHttpClient okHttpClient();\n\n    /**\n     * Json 序列化库\n     *\n     * @return {@link Gson}\n     */\n    Gson gson();\n\n    /**\n     * 缓存文件根目录 (RxCache 和 Glide 的缓存都已经作为子文件夹放在这个根目录下), 应该将所有缓存都统一放到这个根目录下\n     * 便于管理和清理, 可在 {@link ConfigModule#applyOptions(Context, GlobalConfigModule.Builder)} 种配置\n     *\n     * @return {@link File}\n     */\n    File cacheFile();\n\n    /**\n     * 用来存取一些整个 App 公用的数据, 切勿大量存放大容量数据, 这里的存放的数据和 {@link Application} 的生命周期一致\n     *\n     * @return {@link Cache}\n     */\n    Cache<String, Object> extras();\n\n    /**\n     * 用于创建框架所需缓存对象的工厂\n     *\n     * @return {@link Cache.Factory}\n     */\n    Cache.Factory cacheFactory();\n\n    /**\n     * 返回一个全局公用的线程池,适用于大多数异步需求。\n     * 避免多个线程池创建带来的资源消耗。\n     *\n     * @return {@link ExecutorService}\n     */\n    ExecutorService executorService();\n\n    void inject(AppDelegate delegate);\n\n    @Component.Builder\n    interface Builder {\n        @BindsInstance\n        Builder application(Application application);\n\n        Builder globalConfigModule(GlobalConfigModule globalConfigModule);\n\n        AppComponent build();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/module/AppModule.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.di.module;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.integration.ActivityLifecycle;\nimport com.jess.arms.integration.AppManager;\nimport com.jess.arms.integration.FragmentLifecycle;\nimport com.jess.arms.integration.IRepositoryManager;\nimport com.jess.arms.integration.RepositoryManager;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.CacheType;\nimport com.jess.arms.integration.lifecycle.ActivityLifecycleForRxLifecycle;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.inject.Named;\nimport javax.inject.Singleton;\n\nimport dagger.Binds;\nimport dagger.Module;\nimport dagger.Provides;\n\n/**\n * ================================================\n * 提供一些框架必须的实例的 {@link Module}\n * <p>\n * Created by JessYan on 8/4/2016.\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Module\npublic abstract class AppModule {\n\n    @Singleton\n    @Provides\n    static Gson provideGson(Application application, @Nullable GsonConfiguration configuration) {\n        GsonBuilder builder = new GsonBuilder();\n        if (configuration != null) {\n            configuration.configGson(application, builder);\n        }\n        return builder.create();\n    }\n\n    /**\n     * 之前 {@link AppManager} 使用 Dagger 保证单例, 只能使用 {@link AppComponent#appManager()} 访问\n     * 现在直接将 AppManager 独立为单例类, 可以直接通过静态方法 {@link AppManager#getAppManager()} 访问, 更加方便\n     * 但为了不影响之前使用 {@link AppComponent#appManager()} 获取 {@link AppManager} 的项目, 所以暂时保留这种访问方式\n     *\n     * @param application\n     * @return\n     */\n    @Singleton\n    @Provides\n    static AppManager provideAppManager(Application application) {\n        return AppManager.getAppManager().init(application);\n    }\n\n    @Singleton\n    @Provides\n    static Cache<String, Object> provideExtras(Cache.Factory cacheFactory) {\n        //noinspection unchecked\n        return cacheFactory.build(CacheType.EXTRAS);\n    }\n\n    @Singleton\n    @Provides\n    static List<FragmentManager.FragmentLifecycleCallbacks> provideFragmentLifecycles() {\n        return new ArrayList<>();\n    }\n\n    @Binds\n    abstract IRepositoryManager bindRepositoryManager(RepositoryManager repositoryManager);\n\n    @Binds\n    @Named(\"ActivityLifecycle\")\n    abstract Application.ActivityLifecycleCallbacks bindActivityLifecycle(ActivityLifecycle activityLifecycle);\n\n    @Binds\n    @Named(\"ActivityLifecycleForRxLifecycle\")\n    abstract Application.ActivityLifecycleCallbacks bindActivityLifecycleForRxLifecycle(ActivityLifecycleForRxLifecycle activityLifecycleForRxLifecycle);\n\n    @Binds\n    abstract FragmentManager.FragmentLifecycleCallbacks bindFragmentLifecycle(FragmentLifecycle fragmentLifecycle);\n\n    public interface GsonConfiguration {\n        void configGson(@NonNull Context context, @NonNull GsonBuilder builder);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/module/ClientModule.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.di.module;\r\n\r\nimport android.app.Application;\r\nimport android.content.Context;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.annotation.Nullable;\r\n\r\nimport com.google.gson.Gson;\r\nimport com.jess.arms.http.GlobalHttpHandler;\r\nimport com.jess.arms.http.log.RequestInterceptor;\r\nimport com.jess.arms.utils.DataHelper;\r\n\r\nimport java.io.File;\r\nimport java.util.List;\r\nimport java.util.concurrent.ExecutorService;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport javax.inject.Named;\r\nimport javax.inject.Singleton;\r\n\r\nimport dagger.Binds;\r\nimport dagger.Module;\r\nimport dagger.Provides;\r\nimport io.rx_cache2.internal.RxCache;\r\nimport io.victoralbertos.jolyglot.GsonSpeaker;\r\nimport me.jessyan.rxerrorhandler.core.RxErrorHandler;\r\nimport me.jessyan.rxerrorhandler.handler.listener.ResponseErrorListener;\r\nimport okhttp3.Dispatcher;\r\nimport okhttp3.HttpUrl;\r\nimport okhttp3.Interceptor;\r\nimport okhttp3.OkHttpClient;\r\nimport retrofit2.Retrofit;\r\nimport retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;\r\nimport retrofit2.converter.gson.GsonConverterFactory;\r\n\r\n/**\r\n * ================================================\r\n * 提供一些三方库客户端实例的 {@link Module}\r\n * <p>\r\n * Created by JessYan on 2016/3/14.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\n@Module\r\npublic abstract class ClientModule {\r\n    private static final int TIME_OUT = 10;\r\n\r\n    /**\r\n     * 提供 {@link Retrofit}\r\n     *\r\n     * @param application   {@link Application}\r\n     * @param configuration {@link RetrofitConfiguration}\r\n     * @param builder       {@link Retrofit.Builder}\r\n     * @param client        {@link OkHttpClient}\r\n     * @param httpUrl       {@link HttpUrl}\r\n     * @param gson          {@link Gson}\r\n     * @return {@link Retrofit}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    static Retrofit provideRetrofit(Application application, @Nullable RetrofitConfiguration configuration, Retrofit.Builder builder, OkHttpClient client\r\n            , HttpUrl httpUrl, Gson gson) {\r\n        builder\r\n                .baseUrl(httpUrl)//域名\r\n                .client(client);//设置 OkHttp\r\n\r\n        if (configuration != null) {\r\n            configuration.configRetrofit(application, builder);\r\n        }\r\n\r\n        builder\r\n                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//使用 RxJava\r\n                .addConverterFactory(GsonConverterFactory.create(gson));//使用 Gson\r\n        return builder.build();\r\n    }\r\n\r\n    /**\r\n     * 提供 {@link OkHttpClient}\r\n     *\r\n     * @param application     {@link Application}\r\n     * @param configuration   {@link OkhttpConfiguration}\r\n     * @param builder         {@link OkHttpClient.Builder}\r\n     * @param intercept       {@link Interceptor}\r\n     * @param interceptors    {@link List<Interceptor>}\r\n     * @param handler         {@link GlobalHttpHandler}\r\n     * @param executorService {@link ExecutorService}\r\n     * @return {@link OkHttpClient}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    static OkHttpClient provideClient(Application application, @Nullable OkhttpConfiguration configuration, OkHttpClient.Builder builder, Interceptor intercept\r\n            , @Nullable List<Interceptor> interceptors, @Nullable GlobalHttpHandler handler, ExecutorService executorService) {\r\n        builder\r\n                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)\r\n                .readTimeout(TIME_OUT, TimeUnit.SECONDS)\r\n                .addNetworkInterceptor(intercept);\r\n\r\n        if (handler != null) {\r\n            builder.addInterceptor(chain -> chain.proceed(handler.onHttpRequestBefore(chain, chain.request())));\r\n        }\r\n\r\n        //如果外部提供了 Interceptor 的集合则遍历添加\r\n        if (interceptors != null) {\r\n            for (Interceptor interceptor : interceptors) {\r\n                builder.addInterceptor(interceptor);\r\n            }\r\n        }\r\n\r\n        //为 OkHttp 设置默认的线程池\r\n        builder.dispatcher(new Dispatcher(executorService));\r\n\r\n        if (configuration != null) {\r\n            configuration.configOkhttp(application, builder);\r\n        }\r\n        return builder.build();\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    static Retrofit.Builder provideRetrofitBuilder() {\r\n        return new Retrofit.Builder();\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    static OkHttpClient.Builder provideClientBuilder() {\r\n        return new OkHttpClient.Builder();\r\n    }\r\n\r\n    /**\r\n     * 提供 {@link RxCache}\r\n     *\r\n     * @param application    {@link Application}\r\n     * @param configuration  {@link RxCacheConfiguration}\r\n     * @param cacheDirectory RxCache 缓存路径\r\n     * @param gson           {@link Gson}\r\n     * @return {@link RxCache}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    static RxCache provideRxCache(Application application, @Nullable RxCacheConfiguration configuration\r\n            , @Named(\"RxCacheDirectory\") File cacheDirectory, Gson gson) {\r\n        RxCache.Builder builder = new RxCache.Builder();\r\n        RxCache rxCache = null;\r\n        if (configuration != null) {\r\n            rxCache = configuration.configRxCache(application, builder);\r\n        }\r\n        if (rxCache != null) {\r\n            return rxCache;\r\n        }\r\n        return builder\r\n                .persistence(cacheDirectory, new GsonSpeaker(gson));\r\n    }\r\n\r\n    /**\r\n     * 需要单独给 {@link RxCache} 提供子缓存文件\r\n     *\r\n     * @param cacheDir 框架缓存文件\r\n     * @return {@link File}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    @Named(\"RxCacheDirectory\")\r\n    static File provideRxCacheDirectory(File cacheDir) {\r\n        File cacheDirectory = new File(cacheDir, \"RxCache\");\r\n        return DataHelper.makeDirs(cacheDirectory);\r\n    }\r\n\r\n    /**\r\n     * 提供处理 RxJava 错误的管理器\r\n     *\r\n     * @param application {@link Application}\r\n     * @param listener    {@link ResponseErrorListener}\r\n     * @return {@link RxErrorHandler}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    static RxErrorHandler proRxErrorHandler(Application application, ResponseErrorListener listener) {\r\n        return RxErrorHandler\r\n                .builder()\r\n                .with(application)\r\n                .responseErrorListener(listener)\r\n                .build();\r\n    }\r\n\r\n    @Binds\r\n    abstract Interceptor bindInterceptor(RequestInterceptor interceptor);\r\n\r\n    /**\r\n     * {@link Retrofit} 自定义配置接口\r\n     */\r\n    public interface RetrofitConfiguration {\r\n        void configRetrofit(@NonNull Context context, @NonNull Retrofit.Builder builder);\r\n    }\r\n\r\n    /**\r\n     * {@link OkHttpClient} 自定义配置接口\r\n     */\r\n    public interface OkhttpConfiguration {\r\n        void configOkhttp(@NonNull Context context, @NonNull OkHttpClient.Builder builder);\r\n    }\r\n\r\n    /**\r\n     * {@link RxCache} 自定义配置接口\r\n     */\r\n    public interface RxCacheConfiguration {\r\n        /**\r\n         * 若想自定义 RxCache 的缓存文件夹或者解析方式, 如改成 FastJson\r\n         * 请 {@code return rxCacheBuilder.persistence(cacheDirectory, new FastJsonSpeaker());}, 否则请 {@code return null;}\r\n         *\r\n         * @param context {@link Context}\r\n         * @param builder {@link RxCache.Builder}\r\n         * @return {@link RxCache}\r\n         */\r\n        RxCache configRxCache(@NonNull Context context, @NonNull RxCache.Builder builder);\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/module/GlobalConfigModule.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.di.module;\r\n\r\nimport android.app.Application;\r\nimport android.text.TextUtils;\r\n\r\nimport androidx.annotation.Nullable;\r\n\r\nimport com.bumptech.glide.Glide;\r\nimport com.jess.arms.http.BaseUrl;\r\nimport com.jess.arms.http.GlobalHttpHandler;\r\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\r\nimport com.jess.arms.http.log.DefaultFormatPrinter;\r\nimport com.jess.arms.http.log.FormatPrinter;\r\nimport com.jess.arms.http.log.RequestInterceptor;\r\nimport com.jess.arms.integration.IRepositoryManager;\r\nimport com.jess.arms.integration.cache.Cache;\r\nimport com.jess.arms.integration.cache.CacheType;\r\nimport com.jess.arms.integration.cache.IntelligentCache;\r\nimport com.jess.arms.integration.cache.LruCache;\r\nimport com.jess.arms.utils.DataHelper;\r\nimport com.jess.arms.utils.Preconditions;\r\n\r\nimport java.io.File;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.concurrent.Executor;\r\nimport java.util.concurrent.ExecutorService;\r\nimport java.util.concurrent.SynchronousQueue;\r\nimport java.util.concurrent.ThreadPoolExecutor;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\nimport javax.inject.Singleton;\r\n\r\nimport dagger.Module;\r\nimport dagger.Provides;\r\nimport me.jessyan.rxerrorhandler.handler.listener.ResponseErrorListener;\r\nimport okhttp3.HttpUrl;\r\nimport okhttp3.Interceptor;\r\nimport okhttp3.internal.Util;\r\n\r\n/**\r\n * ================================================\r\n * 框架独创的建造者模式 {@link Module},可向框架中注入外部配置的自定义参数\r\n *\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.1\">GlobalConfigModule Wiki 官方文档</a>\r\n * Created by JessYan on 2016/3/14.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\n@Module\r\npublic class GlobalConfigModule {\r\n    private HttpUrl mApiUrl;\r\n    private BaseUrl mBaseUrl;\r\n    private BaseImageLoaderStrategy mLoaderStrategy;\r\n    private GlobalHttpHandler mHandler;\r\n    private List<Interceptor> mInterceptors;\r\n    private ResponseErrorListener mErrorListener;\r\n    private File mCacheFile;\r\n    private ClientModule.RetrofitConfiguration mRetrofitConfiguration;\r\n    private ClientModule.OkhttpConfiguration mOkhttpConfiguration;\r\n    private ClientModule.RxCacheConfiguration mRxCacheConfiguration;\r\n    private AppModule.GsonConfiguration mGsonConfiguration;\r\n    private RequestInterceptor.Level mPrintHttpLogLevel;\r\n    private FormatPrinter mFormatPrinter;\r\n    private Cache.Factory mCacheFactory;\r\n    private ExecutorService mExecutorService;\r\n    private IRepositoryManager.ObtainServiceDelegate mObtainServiceDelegate;\r\n\r\n    private GlobalConfigModule(Builder builder) {\r\n        this.mApiUrl = builder.apiUrl;\r\n        this.mBaseUrl = builder.baseUrl;\r\n        this.mLoaderStrategy = builder.loaderStrategy;\r\n        this.mHandler = builder.handler;\r\n        this.mInterceptors = builder.interceptors;\r\n        this.mErrorListener = builder.responseErrorListener;\r\n        this.mCacheFile = builder.cacheFile;\r\n        this.mRetrofitConfiguration = builder.retrofitConfiguration;\r\n        this.mOkhttpConfiguration = builder.okhttpConfiguration;\r\n        this.mRxCacheConfiguration = builder.rxCacheConfiguration;\r\n        this.mGsonConfiguration = builder.gsonConfiguration;\r\n        this.mPrintHttpLogLevel = builder.printHttpLogLevel;\r\n        this.mFormatPrinter = builder.formatPrinter;\r\n        this.mCacheFactory = builder.cacheFactory;\r\n        this.mExecutorService = builder.executorService;\r\n        this.mObtainServiceDelegate = builder.obtainServiceDelegate;\r\n    }\r\n\r\n    public static Builder builder() {\r\n        return new Builder();\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    List<Interceptor> provideInterceptors() {\r\n        return mInterceptors;\r\n    }\r\n\r\n    /**\r\n     * 提供 BaseUrl,默认使用 <\"https://api.github.com/\">\r\n     *\r\n     * @return\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    HttpUrl provideBaseUrl() {\r\n        if (mBaseUrl != null) {\r\n            HttpUrl httpUrl = mBaseUrl.url();\r\n            if (httpUrl != null) {\r\n                return httpUrl;\r\n            }\r\n        }\r\n        return mApiUrl == null ? HttpUrl.parse(\"https://api.github.com/\") : mApiUrl;\r\n    }\r\n\r\n    /**\r\n     * 提供图片加载框架,默认使用 {@link Glide}\r\n     *\r\n     * @return\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    BaseImageLoaderStrategy provideImageLoaderStrategy() {\r\n        return mLoaderStrategy;\r\n    }\r\n\r\n    /**\r\n     * 提供处理 Http 请求和响应结果的处理类\r\n     *\r\n     * @return\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    GlobalHttpHandler provideGlobalHttpHandler() {\r\n        return mHandler;\r\n    }\r\n\r\n    /**\r\n     * 提供缓存文件\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    File provideCacheFile(Application application) {\r\n        return mCacheFile == null ? DataHelper.getCacheFile(application) : mCacheFile;\r\n    }\r\n\r\n    /**\r\n     * 提供处理 RxJava 错误的管理器的回调\r\n     *\r\n     * @return\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    ResponseErrorListener provideResponseErrorListener() {\r\n        return mErrorListener == null ? ResponseErrorListener.EMPTY : mErrorListener;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    ClientModule.RetrofitConfiguration provideRetrofitConfiguration() {\r\n        return mRetrofitConfiguration;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    ClientModule.OkhttpConfiguration provideOkhttpConfiguration() {\r\n        return mOkhttpConfiguration;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    ClientModule.RxCacheConfiguration provideRxCacheConfiguration() {\r\n        return mRxCacheConfiguration;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    AppModule.GsonConfiguration provideGsonConfiguration() {\r\n        return mGsonConfiguration;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    RequestInterceptor.Level providePrintHttpLogLevel() {\r\n        return mPrintHttpLogLevel == null ? RequestInterceptor.Level.ALL : mPrintHttpLogLevel;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    FormatPrinter provideFormatPrinter() {\r\n        return mFormatPrinter == null ? new DefaultFormatPrinter() : mFormatPrinter;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    Cache.Factory provideCacheFactory(Application application) {\r\n        return mCacheFactory == null ? type -> {\r\n            //若想自定义 LruCache 的 size, 或者不想使用 LruCache, 想使用自己自定义的策略\r\n            //使用 GlobalConfigModule.Builder#cacheFactory() 即可扩展\r\n            switch (type.getCacheTypeId()) {\r\n                //Activity、Fragment 以及 Extras 使用 IntelligentCache (具有 LruCache 和 可永久存储数据的 Map)\r\n                case CacheType.EXTRAS_TYPE_ID:\r\n                case CacheType.ACTIVITY_CACHE_TYPE_ID:\r\n                case CacheType.FRAGMENT_CACHE_TYPE_ID:\r\n                    return new IntelligentCache(type.calculateCacheSize(application));\r\n                //其余使用 LruCache (当达到最大容量时可根据 LRU 算法抛弃不合规数据)\r\n                default:\r\n                    return new LruCache(type.calculateCacheSize(application));\r\n            }\r\n        } : mCacheFactory;\r\n    }\r\n\r\n    /**\r\n     * 返回一个全局公用的线程池,适用于大多数异步需求。\r\n     * 避免多个线程池创建带来的资源消耗。\r\n     *\r\n     * @return {@link Executor}\r\n     */\r\n    @Singleton\r\n    @Provides\r\n    ExecutorService provideExecutorService() {\r\n        return mExecutorService == null ? new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,\r\n                new SynchronousQueue<>(), Util.threadFactory(\"Arms Executor\", false)) : mExecutorService;\r\n    }\r\n\r\n    @Singleton\r\n    @Provides\r\n    @Nullable\r\n    IRepositoryManager.ObtainServiceDelegate provideObtainServiceDelegate() {\r\n        return mObtainServiceDelegate;\r\n    }\r\n\r\n    public static final class Builder {\r\n        private HttpUrl apiUrl;\r\n        private BaseUrl baseUrl;\r\n        private BaseImageLoaderStrategy loaderStrategy;\r\n        private GlobalHttpHandler handler;\r\n        private List<Interceptor> interceptors;\r\n        private ResponseErrorListener responseErrorListener;\r\n        private File cacheFile;\r\n        private ClientModule.RetrofitConfiguration retrofitConfiguration;\r\n        private ClientModule.OkhttpConfiguration okhttpConfiguration;\r\n        private ClientModule.RxCacheConfiguration rxCacheConfiguration;\r\n        private AppModule.GsonConfiguration gsonConfiguration;\r\n        private RequestInterceptor.Level printHttpLogLevel;\r\n        private FormatPrinter formatPrinter;\r\n        private Cache.Factory cacheFactory;\r\n        private ExecutorService executorService;\r\n        private IRepositoryManager.ObtainServiceDelegate obtainServiceDelegate;\r\n\r\n        private Builder() {\r\n        }\r\n\r\n        public Builder baseurl(String baseUrl) {//基础url\r\n            if (TextUtils.isEmpty(baseUrl)) {\r\n                throw new NullPointerException(\"BaseUrl can not be empty\");\r\n            }\r\n            this.apiUrl = HttpUrl.parse(baseUrl);\r\n            return this;\r\n        }\r\n\r\n        public Builder baseurl(BaseUrl baseUrl) {\r\n            this.baseUrl = Preconditions.checkNotNull(baseUrl, BaseUrl.class.getCanonicalName() + \"can not be null.\");\r\n            return this;\r\n        }\r\n\r\n        public Builder imageLoaderStrategy(BaseImageLoaderStrategy loaderStrategy) {//用来请求网络图片\r\n            this.loaderStrategy = loaderStrategy;\r\n            return this;\r\n        }\r\n\r\n        public Builder globalHttpHandler(GlobalHttpHandler handler) {//用来处理http响应结果\r\n            this.handler = handler;\r\n            return this;\r\n        }\r\n\r\n        public Builder addInterceptor(Interceptor interceptor) {//动态添加任意个interceptor\r\n            if (interceptors == null) {\r\n                interceptors = new ArrayList<>();\r\n            }\r\n            this.interceptors.add(interceptor);\r\n            return this;\r\n        }\r\n\r\n        public Builder responseErrorListener(ResponseErrorListener listener) {//处理所有RxJava的onError逻辑\r\n            this.responseErrorListener = listener;\r\n            return this;\r\n        }\r\n\r\n        public Builder cacheFile(File cacheFile) {\r\n            this.cacheFile = cacheFile;\r\n            return this;\r\n        }\r\n\r\n        public Builder retrofitConfiguration(ClientModule.RetrofitConfiguration retrofitConfiguration) {\r\n            this.retrofitConfiguration = retrofitConfiguration;\r\n            return this;\r\n        }\r\n\r\n        public Builder okhttpConfiguration(ClientModule.OkhttpConfiguration okhttpConfiguration) {\r\n            this.okhttpConfiguration = okhttpConfiguration;\r\n            return this;\r\n        }\r\n\r\n        public Builder rxCacheConfiguration(ClientModule.RxCacheConfiguration rxCacheConfiguration) {\r\n            this.rxCacheConfiguration = rxCacheConfiguration;\r\n            return this;\r\n        }\r\n\r\n        public Builder gsonConfiguration(AppModule.GsonConfiguration gsonConfiguration) {\r\n            this.gsonConfiguration = gsonConfiguration;\r\n            return this;\r\n        }\r\n\r\n        public Builder printHttpLogLevel(RequestInterceptor.Level printHttpLogLevel) {//是否让框架打印 Http 的请求和响应信息\r\n            this.printHttpLogLevel = Preconditions.checkNotNull(printHttpLogLevel, \"The printHttpLogLevel can not be null, use RequestInterceptor.Level.NONE instead.\");\r\n            return this;\r\n        }\r\n\r\n        public Builder formatPrinter(FormatPrinter formatPrinter) {\r\n            this.formatPrinter = Preconditions.checkNotNull(formatPrinter, FormatPrinter.class.getCanonicalName() + \"can not be null.\");\r\n            return this;\r\n        }\r\n\r\n        public Builder cacheFactory(Cache.Factory cacheFactory) {\r\n            this.cacheFactory = cacheFactory;\r\n            return this;\r\n        }\r\n\r\n        public Builder executorService(ExecutorService executorService) {\r\n            this.executorService = executorService;\r\n            return this;\r\n        }\r\n\r\n        public Builder obtainServiceDelegate(IRepositoryManager.ObtainServiceDelegate obtainServiceDelegate) {\r\n            this.obtainServiceDelegate = obtainServiceDelegate;\r\n            return this;\r\n        }\r\n\r\n        public GlobalConfigModule build() {\r\n            return new GlobalConfigModule(this);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/scope/ActivityScope.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.di.scope;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\n\nimport javax.inject.Scope;\n\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\n/**\n * A scoping annotation to permit objects whose lifetime should\n * conform to the life of the activity to be memorized in the\n * correct component.\n */\n@Scope\n@Documented\n@Retention(RUNTIME)\npublic @interface ActivityScope {\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/di/scope/FragmentScope.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.di.scope;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\n\nimport javax.inject.Scope;\n\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\n/**\n * A scoping annotation to permit objects whose lifetime should\n * conform to the life of the fragment to be memorized in the\n * correct component.\n */\n@Scope\n@Documented\n@Retention(RUNTIME)\npublic @interface FragmentScope {\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/BaseUrl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http;\n\nimport androidx.annotation.NonNull;\n\nimport okhttp3.HttpUrl;\n\n/**\n * ================================================\n * 针对于 BaseUrl 在 App 启动时不能确定,需要请求服务器接口动态获取的应用场景\n * <p>\n * Created by JessYan on 11/07/2017 14:58\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface BaseUrl {\n    /**\n     * 在调用 Retrofit API 接口之前,使用 Okhttp 或其他方式,请求到正确的 BaseUrl 并通过此方法返回\n     *\n     * @return\n     */\n    @NonNull\n    HttpUrl url();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/GlobalHttpHandler.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\n\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\n\n/**\n * ================================================\n * 处理 Http 请求和响应结果的处理类\n * 使用 {@link GlobalConfigModule.Builder#globalHttpHandler(GlobalHttpHandler)} 方法配置\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.2\">GlobalHttpHandler Wiki 官方文档</a>\n * Created by JessYan on 8/30/16 17:47\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface GlobalHttpHandler {\n\n    /**\n     * 空实现\n     */\n    GlobalHttpHandler EMPTY = new GlobalHttpHandler() {\n\n        @NonNull\n        @Override\n        public Response onHttpResultResponse(@Nullable String httpResult, @NonNull Interceptor.Chain chain, @NonNull Response response) {\n            //不管是否处理, 都必须将 response 返回出去\n            return response;\n        }\n\n        @NonNull\n        @Override\n        public Request onHttpRequestBefore(@NonNull Interceptor.Chain chain, @NonNull Request request) {\n            //不管是否处理, 都必须将 request 返回出去\n            return request;\n        }\n    };\n\n    /**\n     * 这里可以先客户端一步拿到每一次 Http 请求的结果, 可以先解析成 Json, 再做一些操作, 如检测到 token 过期后\n     * 重新请求 token, 并重新执行请求\n     *\n     * @param httpResult 服务器返回的结果 (已被框架自动转换为字符串)\n     * @param chain      {@link okhttp3.Interceptor.Chain}\n     * @param response   {@link Response}\n     * @return {@link Response}\n     */\n    @NonNull\n    Response onHttpResultResponse(@Nullable String httpResult, @NonNull Interceptor.Chain chain, @NonNull Response response);\n\n    /**\n     * 这里可以在请求服务器之前拿到 {@link Request}, 做一些操作比如给 {@link Request} 统一添加 token 或者 header 以及参数加密等操作\n     *\n     * @param chain   {@link okhttp3.Interceptor.Chain}\n     * @param request {@link Request}\n     * @return {@link Request}\n     */\n    @NonNull\n    Request onHttpRequestBefore(@NonNull Interceptor.Chain chain, @NonNull Request request);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/OkHttpStreamFetcher.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http;\n\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport com.bumptech.glide.Priority;\nimport com.bumptech.glide.load.DataSource;\nimport com.bumptech.glide.load.HttpException;\nimport com.bumptech.glide.load.data.DataFetcher;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.bumptech.glide.util.ContentLengthInputStream;\nimport com.bumptech.glide.util.Preconditions;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport okhttp3.Call;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\n/**\n * Fetches an {@link InputStream} using the okhttp library.\n */\npublic class OkHttpStreamFetcher implements DataFetcher<InputStream>, okhttp3.Callback {\n    private static final String TAG = \"OkHttpFetcher\";\n    private final Call.Factory client;\n    private final GlideUrl url;\n    private InputStream stream;\n    private ResponseBody responseBody;\n    private DataCallback<? super InputStream> callback;\n    // call may be accessed on the main thread while the object is in use on other threads. All other\n    // accesses to variables may occur on different threads, but only one at a time.\n    private volatile Call call;\n\n    // Public API.\n    @SuppressWarnings(\"WeakerAccess\")\n    public OkHttpStreamFetcher(Call.Factory client, GlideUrl url) {\n        this.client = client;\n        this.url = url;\n    }\n\n    @Override\n    public void loadData(@NonNull Priority priority,\n                         @NonNull final DataCallback<? super InputStream> callback) {\n        Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl());\n        for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {\n            String key = headerEntry.getKey();\n            requestBuilder.addHeader(key, headerEntry.getValue());\n        }\n        Request request = requestBuilder.build();\n        this.callback = callback;\n\n        call = client.newCall(request);\n        call.enqueue(this);\n    }\n\n    @Override\n    public void onFailure(@NonNull Call call, @NonNull IOException e) {\n        if (Log.isLoggable(TAG, Log.DEBUG)) {\n            Log.d(TAG, \"OkHttp failed to obtain result\", e);\n        }\n\n        callback.onLoadFailed(e);\n    }\n\n    @Override\n    public void onResponse(@NonNull Call call, @NonNull Response response) {\n        responseBody = response.body();\n        if (response.isSuccessful()) {\n            long contentLength = Preconditions.checkNotNull(responseBody).contentLength();\n            stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);\n            callback.onDataReady(stream);\n        } else {\n            callback.onLoadFailed(new HttpException(response.message(), response.code()));\n        }\n    }\n\n    @Override\n    public void cleanup() {\n        try {\n            if (stream != null) {\n                stream.close();\n            }\n        } catch (IOException e) {\n            // Ignored\n        }\n        if (responseBody != null) {\n            responseBody.close();\n        }\n        callback = null;\n    }\n\n    @Override\n    public void cancel() {\n        Call local = call;\n        if (local != null) {\n            local.cancel();\n        }\n    }\n\n    @NonNull\n    @Override\n    public Class<InputStream> getDataClass() {\n        return InputStream.class;\n    }\n\n    @NonNull\n    @Override\n    public DataSource getDataSource() {\n        return DataSource.REMOTE;\n    }\n}"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/OkHttpUrlLoader.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http;\n\nimport androidx.annotation.NonNull;\n\nimport com.bumptech.glide.load.Options;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.bumptech.glide.load.model.ModelLoader;\nimport com.bumptech.glide.load.model.ModelLoaderFactory;\nimport com.bumptech.glide.load.model.MultiModelLoaderFactory;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.InputStream;\n\nimport okhttp3.Call;\nimport okhttp3.OkHttpClient;\n\n/**\n * A simple model loader for fetching media over http/https using OkHttp.\n */\npublic class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {\n\n    private final Call.Factory client;\n\n    // Public API.\n    @SuppressWarnings(\"WeakerAccess\")\n    public OkHttpUrlLoader(@NonNull Call.Factory client) {\n        this.client = client;\n    }\n\n    @Override\n    public boolean handles(@NonNull GlideUrl url) {\n        return true;\n    }\n\n    @Override\n    public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,\n                                               @NonNull Options options) {\n        return new LoadData<>(model, new OkHttpStreamFetcher(client, model));\n    }\n\n    /**\n     * The default factory for {@link OkHttpUrlLoader}s.\n     */\n    // Public API.\n    @SuppressWarnings(\"WeakerAccess\")\n    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {\n        private static volatile Call.Factory internalClient;\n        private final Call.Factory client;\n\n        /**\n         * Constructor for a new Factory that runs requests using a static singleton client.\n         */\n        public Factory() {\n            this(getInternalClient());\n        }\n\n        /**\n         * Constructor for a new Factory that runs requests using given client.\n         *\n         * @param client this is typically an instance of {@code OkHttpClient}.\n         */\n        public Factory(@NonNull Call.Factory client) {\n            this.client = client;\n        }\n\n        private static Call.Factory getInternalClient() {\n            if (internalClient == null) {\n                synchronized (Factory.class) {\n                    if (internalClient == null) {\n                        internalClient = new OkHttpClient();\n                    }\n                }\n            }\n            return internalClient;\n        }\n\n        @NonNull\n        @Override\n        public ModelLoader<GlideUrl, InputStream> build(@NotNull MultiModelLoaderFactory multiFactory) {\n            return new OkHttpUrlLoader(client);\n        }\n\n        @Override\n        public void teardown() {\n            // Do nothing, this instance doesn't own the client.\n        }\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/imageloader/BaseImageLoaderStrategy.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader;\n\nimport android.content.Context;\n\nimport androidx.annotation.Nullable;\n\n/**\n * ================================================\n * 图片加载策略,实现 {@link BaseImageLoaderStrategy}\n * 并通过 {@link ImageLoader#setLoadImgStrategy(BaseImageLoaderStrategy)} 配置后,才可进行图片请求\n * <p>\n * Created by JessYan on 8/5/2016 15:50\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface BaseImageLoaderStrategy<T extends ImageConfig> {\n\n    /**\n     * 加载图片\n     *\n     * @param ctx    {@link Context}\n     * @param config 图片加载配置信息\n     */\n    void loadImage(@Nullable Context ctx, @Nullable T config);\n\n    /**\n     * 停止加载\n     *\n     * @param ctx    {@link Context}\n     * @param config 图片加载配置信息\n     */\n    void clear(@Nullable Context ctx, @Nullable T config);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/imageloader/ImageConfig.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader;\n\nimport android.widget.ImageView;\n\n/**\n * ================================================\n * 这里是图片加载配置信息的基类,定义一些所有图片加载框架都可以用的通用参数\n * 每个 {@link BaseImageLoaderStrategy} 应该对应一个 {@link ImageConfig} 实现类\n * <p>\n * Created by JessYan on 8/5/16 15:19\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ImageConfig {\n    protected String url;\n    protected ImageView imageView;\n    protected int placeholder;//占位符\n    protected int errorPic;//错误占位符\n\n    public String getUrl() {\n        return url;\n    }\n\n    public ImageView getImageView() {\n        return imageView;\n    }\n\n    public int getPlaceholder() {\n        return placeholder;\n    }\n\n    public int getErrorPic() {\n        return errorPic;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/imageloader/ImageLoader.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader;\n\nimport android.content.Context;\n\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.utils.Preconditions;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\n/**\n * ================================================\n * {@link ImageLoader} 使用策略模式和建造者模式,可以动态切换图片请求框架(比如说切换成 Picasso )\n * 当需要切换图片请求框架或图片请求框架升级后变更了 Api 时\n * 这里可以将影响范围降到最低,所以封装 {@link ImageLoader} 是为了屏蔽这个风险\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.4\">ImageLoader wiki 文档</a>\n * Created by JessYan on 8/5/16 15:57\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic final class ImageLoader {\n    @Inject\n    @Nullable\n    BaseImageLoaderStrategy mStrategy;\n\n    @Inject\n    public ImageLoader() {\n    }\n\n    /**\n     * 加载图片\n     *\n     * @param context\n     * @param config\n     * @param <T>\n     */\n    public <T extends ImageConfig> void loadImage(Context context, T config) {\n        Preconditions.checkNotNull(mStrategy, \"Please implement BaseImageLoaderStrategy and call GlobalConfigModule.Builder#imageLoaderStrategy(BaseImageLoaderStrategy) in the applyOptions method of ConfigModule\");\n        //noinspection unchecked\n        this.mStrategy.loadImage(context, config);\n    }\n\n    /**\n     * 停止加载或清理缓存\n     *\n     * @param context\n     * @param config\n     * @param <T>\n     */\n    public <T extends ImageConfig> void clear(Context context, T config) {\n        Preconditions.checkNotNull(mStrategy, \"Please implement BaseImageLoaderStrategy and call GlobalConfigModule.Builder#imageLoaderStrategy(BaseImageLoaderStrategy) in the applyOptions method of ConfigModule\");\n        //noinspection unchecked\n        this.mStrategy.clear(context, config);\n    }\n\n    @Nullable\n    public BaseImageLoaderStrategy getLoadImgStrategy() {\n        return mStrategy;\n    }\n\n    /**\n     * 可在运行时随意切换 {@link BaseImageLoaderStrategy}\n     *\n     * @param strategy\n     */\n    public void setLoadImgStrategy(BaseImageLoaderStrategy strategy) {\n        Preconditions.checkNotNull(strategy, \"strategy == null\");\n        this.mStrategy = strategy;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/imageloader/glide/GlideAppliesOptions.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader.glide;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.GlideBuilder;\nimport com.bumptech.glide.Registry;\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\n\n/**\n * ================================================\n * 如果你想具有配置 @{@link Glide} 的权利,则需要让 {@link BaseImageLoaderStrategy}\n * 的实现类也必须实现 {@link GlideAppliesOptions}\n * <p>\n * Created by JessYan on 13/08/2017 22:02\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface GlideAppliesOptions {\n\n    /**\n     * 配置 @{@link Glide} 的自定义参数,此方法在 @{@link Glide} 初始化时执行(@{@link Glide} 在第一次被调用时初始化),只会执行一次\n     *\n     * @param context\n     * @param builder {@link GlideBuilder} 此类被用来创建 Glide\n     */\n    void applyGlideOptions(@NonNull Context context, @NonNull GlideBuilder builder);\n\n    /**\n     * 注册{@link Glide}的组件，参考{@link com.bumptech.glide.module.LibraryGlideModule}\n     *\n     * @param context  Android context\n     * @param glide    {@link Glide}\n     * @param registry {@link Registry}\n     */\n    void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/imageloader/glide/GlideConfiguration.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader.glide;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.GlideBuilder;\nimport com.bumptech.glide.Registry;\nimport com.bumptech.glide.annotation.GlideModule;\nimport com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;\nimport com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper;\nimport com.bumptech.glide.load.engine.cache.LruResourceCache;\nimport com.bumptech.glide.load.engine.cache.MemorySizeCalculator;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.bumptech.glide.module.AppGlideModule;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.http.OkHttpUrlLoader;\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\nimport com.jess.arms.utils.ArmsUtils;\nimport com.jess.arms.utils.DataHelper;\n\nimport java.io.File;\nimport java.io.InputStream;\n\n/**\n * ================================================\n * {@link AppGlideModule} 的默认实现类\n * 用于配置缓存文件夹,切换图片请求框架等操作\n * <p>\n * Created by JessYan on 16/4/15.\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@GlideModule(glideName = \"GlideArms\")\npublic class GlideConfiguration extends AppGlideModule {\n    public static final int IMAGE_DISK_CACHE_MAX_SIZE = 100 * 1024 * 1024;//图片缓存文件最大值为100Mb\n\n    @Override\n    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {\n        final AppComponent appComponent = ArmsUtils.obtainAppComponentFromContext(context);\n        builder.setDiskCache(() -> {\n            // Careful: the external cache directory doesn't enforce permissions\n            return DiskLruCacheWrapper.create(DataHelper.makeDirs(new File(appComponent.cacheFile(), \"Glide\")), IMAGE_DISK_CACHE_MAX_SIZE);\n        });\n\n        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();\n        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();\n        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();\n\n        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);\n        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);\n\n        builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));\n        builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));\n\n        //将配置 Glide 的机会转交给 GlideImageLoaderStrategy,如你觉得框架提供的 GlideImageLoaderStrategy\n        //并不能满足自己的需求,想自定义 BaseImageLoaderStrategy,那请你最好实现 GlideAppliesOptions\n        //因为只有成为 GlideAppliesOptions 的实现类,这里才能调用 applyGlideOptions(),让你具有配置 Glide 的权利\n        BaseImageLoaderStrategy loadImgStrategy = appComponent.imageLoader().getLoadImgStrategy();\n        if (loadImgStrategy instanceof GlideAppliesOptions) {\n            ((GlideAppliesOptions) loadImgStrategy).applyGlideOptions(context, builder);\n        }\n    }\n\n    @Override\n    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {\n        //Glide 默认使用 HttpURLConnection 做网络请求,在这切换成 Okhttp 请求\n        AppComponent appComponent = ArmsUtils.obtainAppComponentFromContext(context);\n        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(appComponent.okHttpClient()));\n\n        BaseImageLoaderStrategy loadImgStrategy = appComponent.imageLoader().getLoadImgStrategy();\n        if (loadImgStrategy instanceof GlideAppliesOptions) {\n            ((GlideAppliesOptions) loadImgStrategy).registerComponents(context, glide, registry);\n        }\n    }\n\n    @Override\n    public boolean isManifestParsingEnabled() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/log/DefaultFormatPrinter.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.log;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.utils.CharacterHandler;\nimport com.jess.arms.utils.LogUtils;\n\nimport java.util.List;\n\nimport okhttp3.MediaType;\nimport okhttp3.Request;\n\n/**\n * ================================================\n * 对 OkHttp 的请求和响应信息进行更规范和清晰的打印, 此类为框架默认实现, 以默认格式打印信息, 若觉得默认打印格式\n * 并不能满足自己的需求, 可自行扩展自己理想的打印格式\n *\n * @see GlobalConfigModule.Builder#formatPrinter(FormatPrinter)\n * Created by JessYan on 25/01/2018 14:51\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class DefaultFormatPrinter implements FormatPrinter {\n    private static final String TAG = \"ArmsHttpLog\";\n    private static final String LINE_SEPARATOR = System.getProperty(\"line.separator\");\n    private static final String DOUBLE_SEPARATOR = LINE_SEPARATOR + LINE_SEPARATOR;\n\n    private static final String[] OMITTED_RESPONSE = {LINE_SEPARATOR, \"Omitted response body\"};\n    private static final String[] OMITTED_REQUEST = {LINE_SEPARATOR, \"Omitted request body\"};\n\n    private static final String N = \"\\n\";\n    private static final String T = \"\\t\";\n    private static final String REQUEST_UP_LINE = \"   ┌────── Request ────────────────────────────────────────────────────────────────────────\";\n    private static final String END_LINE = \"   └───────────────────────────────────────────────────────────────────────────────────────\";\n    private static final String RESPONSE_UP_LINE = \"   ┌────── Response ───────────────────────────────────────────────────────────────────────\";\n    private static final String BODY_TAG = \"Body:\";\n    private static final String URL_TAG = \"URL: \";\n    private static final String METHOD_TAG = \"Method: @\";\n    private static final String HEADERS_TAG = \"Headers:\";\n    private static final String STATUS_CODE_TAG = \"Status Code: \";\n    private static final String RECEIVED_TAG = \"Received in: \";\n    private static final String CORNER_UP = \"┌ \";\n    private static final String CORNER_BOTTOM = \"└ \";\n    private static final String CENTER_LINE = \"├ \";\n    private static final String DEFAULT_LINE = \"│ \";\n    private static final String[] ARMS = new String[]{\"-A-\", \"-R-\", \"-M-\", \"-S-\"};\n    private static ThreadLocal<Integer> last = new ThreadLocal<Integer>() {\n        @Override\n        protected Integer initialValue() {\n            return 0;\n        }\n    };\n\n    private static boolean isEmpty(String line) {\n        return TextUtils.isEmpty(line) || N.equals(line) || T.equals(line) || TextUtils.isEmpty(line.trim());\n    }\n\n    /**\n     * 对 {@code lines} 中的信息进行逐行打印\n     *\n     * @param tag\n     * @param lines\n     * @param withLineSize 为 {@code true} 时, 每行的信息长度不会超过110, 超过则自动换行\n     */\n    private static void logLines(String tag, String[] lines, boolean withLineSize) {\n        for (String line : lines) {\n            int lineLength = line.length();\n            int maxLongSize = withLineSize ? 110 : lineLength;\n            for (int i = 0; i <= lineLength / maxLongSize; i++) {\n                int start = i * maxLongSize;\n                int end = (i + 1) * maxLongSize;\n                end = end > line.length() ? line.length() : end;\n                LogUtils.debugInfo(resolveTag(tag), DEFAULT_LINE + line.substring(start, end));\n            }\n        }\n    }\n\n    private static String computeKey() {\n        if (last.get() >= 4) {\n            last.set(0);\n        }\n        String s = ARMS[last.get()];\n        last.set(last.get() + 1);\n        return s;\n    }\n\n    /**\n     * 此方法是为了解决在 AndroidStudio v3.1 以上 Logcat 输出的日志无法对齐的问题\n     * <p>\n     * 此问题引起的原因, 据 JessYan 猜测, 可能是因为 AndroidStudio v3.1 以上将极短时间内以相同 tag 输出多次的 log 自动合并为一次输出\n     * 导致本来对称的输出日志, 出现不对称的问题\n     * AndroidStudio v3.1 此次对输出日志的优化, 不小心使市面上所有具有日志格式化输出功能的日志框架无法正常工作\n     * 现在暂时能想到的解决方案有两个: 1. 改变每行的 tag (每行 tag 都加一个可变化的 token) 2. 延迟每行日志打印的间隔时间\n     * <p>\n     * {@link #resolveTag(String)} 使用第一种解决方案\n     *\n     * @param tag\n     */\n    private static String resolveTag(String tag) {\n        return computeKey() + tag;\n    }\n\n    private static String[] getRequest(Request request) {\n        String log;\n        String header = request.headers().toString();\n        log = METHOD_TAG + request.method() + DOUBLE_SEPARATOR +\n                (isEmpty(header) ? \"\" : HEADERS_TAG + LINE_SEPARATOR + dotHeaders(header));\n        return log.split(LINE_SEPARATOR);\n    }\n\n    private static String[] getResponse(String header, long tookMs, int code, boolean isSuccessful,\n                                        List<String> segments, String message) {\n        String log;\n        String segmentString = slashSegments(segments);\n        log = ((!TextUtils.isEmpty(segmentString) ? segmentString + \" - \" : \"\") + \"is success : \"\n                + isSuccessful + \" - \" + RECEIVED_TAG + tookMs + \"ms\" + DOUBLE_SEPARATOR + STATUS_CODE_TAG +\n                code + \" / \" + message + DOUBLE_SEPARATOR + (isEmpty(header) ? \"\" : HEADERS_TAG + LINE_SEPARATOR +\n                dotHeaders(header)));\n        return log.split(LINE_SEPARATOR);\n    }\n\n    private static String slashSegments(List<String> segments) {\n        StringBuilder segmentString = new StringBuilder();\n        for (String segment : segments) {\n            segmentString.append(\"/\").append(segment);\n        }\n        return segmentString.toString();\n    }\n\n    /**\n     * 对 {@code header} 按规定的格式进行处理\n     *\n     * @param header\n     * @return\n     */\n    private static String dotHeaders(String header) {\n        String[] headers = header.split(LINE_SEPARATOR);\n        StringBuilder builder = new StringBuilder();\n        String tag = \"─ \";\n        if (headers.length > 1) {\n            for (int i = 0; i < headers.length; i++) {\n                if (i == 0) {\n                    tag = CORNER_UP;\n                } else if (i == headers.length - 1) {\n                    tag = CORNER_BOTTOM;\n                } else {\n                    tag = CENTER_LINE;\n                }\n                builder.append(tag).append(headers[i]).append(\"\\n\");\n            }\n        } else {\n            for (String item : headers) {\n                builder.append(tag).append(item).append(\"\\n\");\n            }\n        }\n        return builder.toString();\n    }\n\n    private static String getTag(boolean isRequest) {\n        if (isRequest) {\n            return TAG + \"-Request\";\n        } else {\n            return TAG + \"-Response\";\n        }\n    }\n\n    /**\n     * 打印网络请求信息, 当网络请求时 {{@link okhttp3.RequestBody}} 可以解析的情况\n     *\n     * @param request\n     * @param bodyString\n     */\n    @Override\n    public void printJsonRequest(@NonNull Request request, @NonNull String bodyString) {\n        final String requestBody = LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + bodyString;\n        final String tag = getTag(true);\n\n        LogUtils.debugInfo(tag, REQUEST_UP_LINE);\n        logLines(tag, new String[]{URL_TAG + request.url()}, false);\n        logLines(tag, getRequest(request), true);\n        logLines(tag, requestBody.split(LINE_SEPARATOR), true);\n        LogUtils.debugInfo(tag, END_LINE);\n    }\n\n    /**\n     * 打印网络请求信息, 当网络请求时 {{@link okhttp3.RequestBody}} 为 {@code null} 或不可解析的情况\n     *\n     * @param request\n     */\n    @Override\n    public void printFileRequest(@NonNull Request request) {\n        final String tag = getTag(true);\n\n        LogUtils.debugInfo(tag, REQUEST_UP_LINE);\n        logLines(tag, new String[]{URL_TAG + request.url()}, false);\n        logLines(tag, getRequest(request), true);\n        logLines(tag, OMITTED_REQUEST, true);\n        LogUtils.debugInfo(tag, END_LINE);\n    }\n\n    /**\n     * 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 可以解析的情况\n     *\n     * @param chainMs      服务器响应耗时(单位毫秒)\n     * @param isSuccessful 请求是否成功\n     * @param code         响应码\n     * @param headers      请求头\n     * @param contentType  服务器返回数据的数据类型\n     * @param bodyString   服务器返回的数据(已解析)\n     * @param segments     域名后面的资源地址\n     * @param message      响应信息\n     * @param responseUrl  请求地址\n     */\n    @Override\n    public void printJsonResponse(long chainMs, boolean isSuccessful, int code, @NonNull String headers, @Nullable MediaType contentType,\n                                  @Nullable String bodyString, @NonNull List<String> segments, @NonNull String message, @NonNull final String responseUrl) {\n        bodyString = RequestInterceptor.isJson(contentType) ? CharacterHandler.jsonFormat(bodyString)\n                : RequestInterceptor.isXml(contentType) ? CharacterHandler.xmlFormat(bodyString) : bodyString;\n\n        final String responseBody = LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + bodyString;\n        final String tag = getTag(false);\n        final String[] urlLine = {URL_TAG + responseUrl, N};\n\n        LogUtils.debugInfo(tag, RESPONSE_UP_LINE);\n        logLines(tag, urlLine, true);\n        logLines(tag, getResponse(headers, chainMs, code, isSuccessful, segments, message), true);\n        logLines(tag, responseBody.split(LINE_SEPARATOR), true);\n        LogUtils.debugInfo(tag, END_LINE);\n    }\n\n    /**\n     * 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 为 {@code null} 或不可解析的情况\n     *\n     * @param chainMs      服务器响应耗时(单位毫秒)\n     * @param isSuccessful 请求是否成功\n     * @param code         响应码\n     * @param headers      请求头\n     * @param segments     域名后面的资源地址\n     * @param message      响应信息\n     * @param responseUrl  请求地址\n     */\n    @Override\n    public void printFileResponse(long chainMs, boolean isSuccessful, int code, @NonNull String headers,\n                                  @NonNull List<String> segments, @NonNull String message, @NonNull final String responseUrl) {\n        final String tag = getTag(false);\n        final String[] urlLine = {URL_TAG + responseUrl, N};\n\n        LogUtils.debugInfo(tag, RESPONSE_UP_LINE);\n        logLines(tag, urlLine, true);\n        logLines(tag, getResponse(headers, chainMs, code, isSuccessful, segments, message), true);\n        logLines(tag, OMITTED_RESPONSE, true);\n        LogUtils.debugInfo(tag, END_LINE);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/log/FormatPrinter.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\n\nimport java.util.List;\n\nimport okhttp3.MediaType;\nimport okhttp3.Request;\n\n/**\n * ================================================\n * 对 OkHttp 的请求和响应信息进行更规范和清晰的打印, 开发者可更根据自己的需求自行扩展打印格式\n *\n * @see DefaultFormatPrinter\n * @see GlobalConfigModule.Builder#formatPrinter(FormatPrinter)\n * Created by JessYan on 31/01/2018 17:36\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n\npublic interface FormatPrinter {\n\n    /**\n     * 打印网络请求信息, 当网络请求时 {{@link okhttp3.RequestBody}} 可以解析的情况\n     *\n     * @param request\n     * @param bodyString 发送给服务器的请求体中的数据(已解析)\n     */\n    void printJsonRequest(@NonNull Request request, @NonNull String bodyString);\n\n    /**\n     * 打印网络请求信息, 当网络请求时 {{@link okhttp3.RequestBody}} 为 {@code null} 或不可解析的情况\n     *\n     * @param request\n     */\n    void printFileRequest(@NonNull Request request);\n\n    /**\n     * 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 可以解析的情况\n     *\n     * @param chainMs      服务器响应耗时(单位毫秒)\n     * @param isSuccessful 请求是否成功\n     * @param code         响应码\n     * @param headers      请求头\n     * @param contentType  服务器返回数据的数据类型\n     * @param bodyString   服务器返回的数据(已解析)\n     * @param segments     域名后面的资源地址\n     * @param message      响应信息\n     * @param responseUrl  请求地址\n     */\n    void printJsonResponse(long chainMs, boolean isSuccessful, int code, @NonNull String headers, @Nullable MediaType contentType,\n                           @Nullable String bodyString, @NonNull List<String> segments, @NonNull String message, @NonNull String responseUrl);\n\n    /**\n     * 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 为 {@code null} 或不可解析的情况\n     *\n     * @param chainMs      服务器响应耗时(单位毫秒)\n     * @param isSuccessful 请求是否成功\n     * @param code         响应码\n     * @param headers      请求头\n     * @param segments     域名后面的资源地址\n     * @param message      响应信息\n     * @param responseUrl  请求地址\n     */\n    void printFileResponse(long chainMs, boolean isSuccessful, int code, @NonNull String headers,\n                           @NonNull List<String> segments, @NonNull String message, @NonNull String responseUrl);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/http/log/RequestInterceptor.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.log;\n\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.http.GlobalHttpHandler;\nimport com.jess.arms.utils.CharacterHandler;\nimport com.jess.arms.utils.UrlEncoderUtils;\nimport com.jess.arms.utils.ZipHelper;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.nio.charset.Charset;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\nimport okhttp3.Interceptor;\nimport okhttp3.MediaType;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\nimport okio.Buffer;\nimport okio.BufferedSource;\nimport timber.log.Timber;\n\n\n/**\n * ================================================\n * 解析框架中的网络请求和响应结果,并以日志形式输出,调试神器\n * 可使用 {@link GlobalConfigModule.Builder#printHttpLogLevel(Level)} 控制或关闭日志\n * <p>\n * Created by JessYan on 7/1/2016.\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic class RequestInterceptor implements Interceptor {\n    @Inject\n    @Nullable\n    GlobalHttpHandler mHandler;\n    @Inject\n    FormatPrinter mPrinter;\n    @Inject\n    Level printLevel;\n\n    @Inject\n    public RequestInterceptor() {\n    }\n\n    /**\n     * 解析请求服务器的请求参数\n     *\n     * @param request {@link Request}\n     * @return 解析后的请求信息\n     * @throws UnsupportedEncodingException\n     */\n    public static String parseParams(Request request) throws UnsupportedEncodingException {\n        try {\n            RequestBody body = request.newBuilder().build().body();\n            if (body == null) {\n                return \"\";\n            }\n            Buffer requestbuffer = new Buffer();\n            body.writeTo(requestbuffer);\n            Charset charset = Charset.forName(\"UTF-8\");\n            MediaType contentType = body.contentType();\n            if (contentType != null) {\n                charset = contentType.charset(charset);\n            }\n            String json = requestbuffer.readString(charset);\n            if (UrlEncoderUtils.hasUrlEncoded(json)) {\n                json = URLDecoder.decode(json, convertCharset(charset));\n            }\n            return CharacterHandler.jsonFormat(json);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return \"{\\\"error\\\": \\\"\" + e.getMessage() + \"\\\"}\";\n        }\n    }\n\n    /**\n     * 是否可以解析\n     *\n     * @param mediaType {@link MediaType}\n     * @return {@code true} 为可以解析\n     */\n    public static boolean isParseable(MediaType mediaType) {\n        if (mediaType == null || mediaType.type() == null) {\n            return false;\n        }\n        return isText(mediaType) || isPlain(mediaType)\n                || isJson(mediaType) || isForm(mediaType)\n                || isHtml(mediaType) || isXml(mediaType);\n    }\n\n    public static boolean isText(MediaType mediaType) {\n        if (mediaType == null || mediaType.type() == null) {\n            return false;\n        }\n        return \"text\".equals(mediaType.type());\n    }\n\n    public static boolean isPlain(MediaType mediaType) {\n        if (mediaType == null || mediaType.subtype() == null) {\n            return false;\n        }\n        return mediaType.subtype().toLowerCase().contains(\"plain\");\n    }\n\n    public static boolean isJson(MediaType mediaType) {\n        if (mediaType == null || mediaType.subtype() == null) {\n            return false;\n        }\n        return mediaType.subtype().toLowerCase().contains(\"json\");\n    }\n\n    public static boolean isXml(MediaType mediaType) {\n        if (mediaType == null || mediaType.subtype() == null) {\n            return false;\n        }\n        return mediaType.subtype().toLowerCase().contains(\"xml\");\n    }\n\n    public static boolean isHtml(MediaType mediaType) {\n        if (mediaType == null || mediaType.subtype() == null) {\n            return false;\n        }\n        return mediaType.subtype().toLowerCase().contains(\"html\");\n    }\n\n    public static boolean isForm(MediaType mediaType) {\n        if (mediaType == null || mediaType.subtype() == null) {\n            return false;\n        }\n        return mediaType.subtype().toLowerCase().contains(\"x-www-form-urlencoded\");\n    }\n\n    public static String convertCharset(Charset charset) {\n        String s = charset.toString();\n        int i = s.indexOf(\"[\");\n        if (i == -1) {\n            return s;\n        }\n        return s.substring(i + 1, s.length() - 1);\n    }\n\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        Request request = chain.request();\n\n        boolean logRequest = printLevel == Level.ALL || (printLevel != Level.NONE && printLevel == Level.REQUEST);\n\n        if (logRequest) {\n            //打印请求信息\n            if (request.body() != null && isParseable(request.body().contentType())) {\n                mPrinter.printJsonRequest(request, parseParams(request));\n            } else {\n                mPrinter.printFileRequest(request);\n            }\n        }\n\n        boolean logResponse = printLevel == Level.ALL || (printLevel != Level.NONE && printLevel == Level.RESPONSE);\n\n        long t1 = logResponse ? System.nanoTime() : 0;\n        Response originalResponse;\n        try {\n            originalResponse = chain.proceed(request);\n        } catch (Exception e) {\n            Timber.w(\"Http Error: %s\", e);\n            throw e;\n        }\n        long t2 = logResponse ? System.nanoTime() : 0;\n\n        ResponseBody responseBody = originalResponse.body();\n\n        //打印响应结果\n        String bodyString = null;\n        if (responseBody != null && isParseable(responseBody.contentType())) {\n            bodyString = printResult(request, originalResponse, logResponse);\n        }\n\n        if (logResponse) {\n            final List<String> segmentList = request.url().encodedPathSegments();\n            final String header = originalResponse.headers().toString();\n            final int code = originalResponse.code();\n            final boolean isSuccessful = originalResponse.isSuccessful();\n            final String message = originalResponse.message();\n            final String url = originalResponse.request().url().toString();\n\n            if (responseBody != null && isParseable(responseBody.contentType())) {\n                mPrinter.printJsonResponse(TimeUnit.NANOSECONDS.toMillis(t2 - t1), isSuccessful,\n                        code, header, responseBody.contentType(), bodyString, segmentList, message, url);\n            } else {\n                mPrinter.printFileResponse(TimeUnit.NANOSECONDS.toMillis(t2 - t1),\n                        isSuccessful, code, header, segmentList, message, url);\n            }\n\n        }\n\n        if (mHandler != null)//这里可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取\n        {\n            return mHandler.onHttpResultResponse(bodyString, chain, originalResponse);\n        }\n\n        return originalResponse;\n    }\n\n    /**\n     * 打印响应结果\n     *\n     * @param request     {@link Request}\n     * @param response    {@link Response}\n     * @param logResponse 是否打印响应结果\n     * @return 解析后的响应结果\n     * @throws IOException\n     */\n    @Nullable\n    private String printResult(Request request, Response response, boolean logResponse) throws IOException {\n        try {\n            //读取服务器返回的结果\n            ResponseBody responseBody = response.newBuilder().build().body();\n            BufferedSource source = responseBody.source();\n            source.request(Long.MAX_VALUE); // Buffer the entire body.\n            Buffer buffer = source.buffer();\n\n            //获取content的压缩类型\n            String encoding = response\n                    .headers()\n                    .get(\"Content-Encoding\");\n\n            Buffer clone = buffer.clone();\n\n            //解析response content\n            return parseContent(responseBody, encoding, clone);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return \"{\\\"error\\\": \\\"\" + e.getMessage() + \"\\\"}\";\n        }\n    }\n\n    /**\n     * 解析服务器响应的内容\n     *\n     * @param responseBody {@link ResponseBody}\n     * @param encoding     编码类型\n     * @param clone        克隆后的服务器响应内容\n     * @return 解析后的响应结果\n     */\n    private String parseContent(ResponseBody responseBody, String encoding, Buffer clone) {\n        Charset charset = Charset.forName(\"UTF-8\");\n        MediaType contentType = responseBody.contentType();\n        if (contentType != null) {\n            charset = contentType.charset(charset);\n        }\n        //content 使用 gzip 压缩\n        if (\"gzip\".equalsIgnoreCase(encoding)) {\n            //解压\n            return ZipHelper.decompressForGzip(clone.readByteArray(), convertCharset(charset));\n        } else if (\"zlib\".equalsIgnoreCase(encoding)) {\n            //content 使用 zlib 压缩\n            return ZipHelper.decompressToStringForZlib(clone.readByteArray(), convertCharset(charset));\n        } else {\n            //content 没有被压缩, 或者使用其他未知压缩方式\n            return clone.readString(charset);\n        }\n    }\n\n    public enum Level {\n        /**\n         * 不打印log\n         */\n        NONE,\n        /**\n         * 只打印请求信息\n         */\n        REQUEST,\n        /**\n         * 只打印响应信息\n         */\n        RESPONSE,\n        /**\n         * 所有数据全部打印\n         */\n        ALL\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/ActivityLifecycle.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.base.BaseFragment;\nimport com.jess.arms.base.delegate.ActivityDelegate;\nimport com.jess.arms.base.delegate.ActivityDelegateImpl;\nimport com.jess.arms.base.delegate.FragmentDelegate;\nimport com.jess.arms.base.delegate.IActivity;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.IntelligentCache;\nimport com.jess.arms.utils.Preconditions;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\nimport dagger.Lazy;\n\n\n/**\n * ================================================\n * {@link Application.ActivityLifecycleCallbacks} 默认实现类\n * 通过 {@link ActivityDelegate} 管理 {@link Activity}\n *\n * @see <a href=\"http://www.jianshu.com/p/75a5c24174b2\">ActivityLifecycleCallbacks 分析文章</a>\n * Created by JessYan on 21/02/2017 14:23\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic class ActivityLifecycle implements Application.ActivityLifecycleCallbacks {\n\n    @Inject\n    AppManager mAppManager;\n    @Inject\n    Application mApplication;\n    @Inject\n    Cache<String, Object> mExtras;\n    @Inject\n    Lazy<FragmentManager.FragmentLifecycleCallbacks> mFragmentLifecycle;\n    @Inject\n    Lazy<List<FragmentManager.FragmentLifecycleCallbacks>> mFragmentLifecycles;\n\n    @Inject\n    public ActivityLifecycle() {\n    }\n\n    @Override\n    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {\n        //如果 intent 包含了此字段,并且为 true 说明不加入到 list 进行统一管理\n        boolean isNotAdd = false;\n        if (activity.getIntent() != null) {\n            isNotAdd = activity.getIntent().getBooleanExtra(AppManager.IS_NOT_ADD_ACTIVITY_LIST, false);\n        }\n\n        if (!isNotAdd) {\n            mAppManager.addActivity(activity);\n        }\n\n        //配置ActivityDelegate\n        if (activity instanceof IActivity) {\n            ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n            if (activityDelegate == null) {\n                Cache<String, Object> cache = getCacheFromActivity((IActivity) activity);\n                activityDelegate = new ActivityDelegateImpl(activity);\n                //使用 IntelligentCache.KEY_KEEP 作为 key 的前缀, 可以使储存的数据永久存储在内存中\n                //否则存储在 LRU 算法的存储空间中, 前提是 Activity 使用的是 IntelligentCache (框架默认使用)\n                cache.put(IntelligentCache.getKeyOfKeep(ActivityDelegate.ACTIVITY_DELEGATE), activityDelegate);\n            }\n            activityDelegate.onCreate(savedInstanceState);\n        }\n\n        registerFragmentCallbacks(activity);\n    }\n\n    @Override\n    public void onActivityStarted(Activity activity) {\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onStart();\n        }\n    }\n\n    @Override\n    public void onActivityResumed(Activity activity) {\n        mAppManager.setCurrentActivity(activity);\n\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onResume();\n        }\n    }\n\n    @Override\n    public void onActivityPaused(Activity activity) {\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onPause();\n        }\n    }\n\n    @Override\n    public void onActivityStopped(Activity activity) {\n        if (mAppManager.getCurrentActivity() == activity) {\n            mAppManager.setCurrentActivity(null);\n        }\n\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onStop();\n        }\n    }\n\n    @Override\n    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onSaveInstanceState(outState);\n        }\n    }\n\n    @Override\n    public void onActivityDestroyed(Activity activity) {\n        mAppManager.removeActivity(activity);\n\n        ActivityDelegate activityDelegate = fetchActivityDelegate(activity);\n        if (activityDelegate != null) {\n            activityDelegate.onDestroy();\n            getCacheFromActivity((IActivity) activity).clear();\n        }\n    }\n\n    /**\n     * 给每个 Activity 的所有 Fragment 设置监听其生命周期, Activity 可以通过 {@link IActivity#useFragment()}\n     * 设置是否使用监听,如果这个 Activity 返回 false 的话,这个 Activity 下面的所有 Fragment 将不能使用 {@link FragmentDelegate}\n     * 意味着 {@link BaseFragment} 也不能使用\n     *\n     * @param activity\n     */\n    private void registerFragmentCallbacks(Activity activity) {\n\n        boolean useFragment = !(activity instanceof IActivity) || ((IActivity) activity).useFragment();\n        if (activity instanceof FragmentActivity && useFragment) {\n\n            //mFragmentLifecycle 为 Fragment 生命周期实现类, 用于框架内部对每个 Fragment 的必要操作, 如给每个 Fragment 配置 FragmentDelegate\n            //注册框架内部已实现的 Fragment 生命周期逻辑\n            ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifecycle.get(), true);\n\n            if (mExtras.containsKey(IntelligentCache.getKeyOfKeep(ConfigModule.class.getName()))) {\n                @SuppressWarnings(\"unchecked\")\n                List<ConfigModule> modules = (List<ConfigModule>) mExtras.get(IntelligentCache.getKeyOfKeep(ConfigModule.class.getName()));\n                if (modules != null) {\n                    for (ConfigModule module : modules) {\n                        module.injectFragmentLifecycle(mApplication, mFragmentLifecycles.get());\n                    }\n                }\n                mExtras.remove(IntelligentCache.getKeyOfKeep(ConfigModule.class.getName()));\n            }\n\n            //注册框架外部, 开发者扩展的 Fragment 生命周期逻辑\n            for (FragmentManager.FragmentLifecycleCallbacks fragmentLifecycle : mFragmentLifecycles.get()) {\n                ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(fragmentLifecycle, true);\n            }\n        }\n    }\n\n    private ActivityDelegate fetchActivityDelegate(Activity activity) {\n        ActivityDelegate activityDelegate = null;\n        if (activity instanceof IActivity) {\n            Cache<String, Object> cache = getCacheFromActivity((IActivity) activity);\n            activityDelegate = (ActivityDelegate) cache.get(IntelligentCache.getKeyOfKeep(ActivityDelegate.ACTIVITY_DELEGATE));\n        }\n        return activityDelegate;\n    }\n\n    @NonNull\n    private Cache<String, Object> getCacheFromActivity(IActivity activity) {\n        Cache<String, Object> cache = activity.provideCache();\n        Preconditions.checkNotNull(cache, \"%s cannot be null on Activity\", Cache.class.getName());\n        return cache;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/AppManager.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Message;\nimport android.view.View;\n\nimport com.google.android.material.snackbar.Snackbar;\nimport com.jess.arms.base.delegate.AppLifecycles;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport androidx.annotation.Nullable;\nimport io.reactivex.Completable;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport timber.log.Timber;\n\nimport static com.jess.arms.base.Platform.DEPENDENCY_SUPPORT_DESIGN;\n\n/**\n * ================================================\n * 用于管理所有 {@link Activity}, 和在前台的 {@link Activity}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.11\">AppManager wiki 官方文档</a>\n * Created by JessYan on 14/12/2016 13:50\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic final class AppManager {\n    /**\n     * true 为不需要加入到 Activity 容器进行统一管理,默认为 false\n     */\n    public static final String IS_NOT_ADD_ACTIVITY_LIST = \"is_not_add_activity_list\";\n    private static volatile AppManager sAppManager;\n    protected final String TAG = this.getClass().getSimpleName();\n    private Application mApplication;\n    /**\n     * 管理所有存活的 Activity, 容器中的顺序仅仅是 Activity 的创建顺序, 并不能保证和 Activity 任务栈顺序一致\n     */\n    private List<Activity> mActivityList;\n    /**\n     * 当前在前台的 Activity\n     */\n    private Activity mCurrentActivity;\n    /**\n     * 此方法作废, 现在可通过 {@link AppManager#getAppManager()} 直接访问 {@link AppManager}\n     * <p>\n     * 提供给外部扩展 {@link AppManager} 的 {@link #onReceive(Message)} 方法\n     */\n    private HandleListener mHandleListener;\n\n    private AppManager() {\n    }\n\n    public static AppManager getAppManager() {\n        if (sAppManager == null) {\n            synchronized (AppManager.class) {\n                if (sAppManager == null) {\n                    sAppManager = new AppManager();\n                }\n            }\n        }\n        return sAppManager;\n    }\n\n    /**\n     * 此方法作废, 现在可通过 {@link AppManager#getAppManager()} 直接访问 {@link AppManager}\n     * <p>\n     * 通过此方法远程遥控 {@link AppManager}, 使 {@link #onReceive(Message)} 执行对应方法\n     *\n     * @param msg {@link Message}\n     */\n    @Deprecated\n    public static void post(Message msg) {\n        getAppManager().onReceive(msg);\n    }\n\n    public AppManager init(Application application) {\n        this.mApplication = application;\n        return sAppManager;\n    }\n\n    /**\n     * 此方法作废, 现在可通过 {@link AppManager#getAppManager()} 直接访问 {@link AppManager}\n     * <p>\n     * 可通过 {@link #setHandleListener(HandleListener)}, 让外部可扩展新的事件\n     *\n     * @param message\n     */\n    @Deprecated\n    public void onReceive(Message message) {\n        if (mHandleListener != null) {\n            mHandleListener.handleMessage(this, message);\n        }\n    }\n\n    @Deprecated\n    public HandleListener getHandleListener() {\n        return mHandleListener;\n    }\n\n    /**\n     * 此方法作废, 现在可通过 {@link AppManager#getAppManager()} 直接访问 {@link AppManager}\n     * <p>\n     * 提供给外部扩展 {@link AppManager} 的 {@link #onReceive} 方法(远程遥控 {@link AppManager} 的功能)\n     * 建议在 {@link ConfigModule#injectAppLifecycle(Context, List)} 中\n     * 通过 {@link AppLifecycles#onCreate(Application)} 在 App 初始化时,使用此方法传入自定义的 {@link HandleListener}\n     *\n     * @param handleListener\n     */\n    @Deprecated\n    public void setHandleListener(HandleListener handleListener) {\n        this.mHandleListener = handleListener;\n    }\n\n    /**\n     * 让在前台的 {@link Activity}, 使用 {@link Snackbar} 显示文本内容\n     *\n     * @param message\n     * @param isLong\n     */\n    public void showSnackbar(String message, boolean isLong) {\n        if (getCurrentActivity() == null && getTopActivity() == null) {\n            Timber.tag(TAG).w(\"mCurrentActivity == null when showSnackbar(String,boolean)\");\n            return;\n        }\n        Completable.fromAction(() -> {\n            //Arms 已将 com.google.android.material:material 从依赖中移除 (目的是减小 Arms 体积, design 库中含有太多 View)\n            //因为 Snackbar 在 com.google.android.material:material 库中, 所以如果框架使用者没有自行依赖 com.google.android.material:material\n            //Arms 则会使用 Toast 替代 Snackbar 显示信息, 如果框架使用者依赖了 arms-autolayout 库就不用依赖 com.google.android.material:material 了\n            //因为在 arms-autolayout 库中已经依赖有 com.google.android.material:material\n            if (DEPENDENCY_SUPPORT_DESIGN) {\n                Activity activity = getCurrentActivity() == null ? getTopActivity() : getCurrentActivity();\n                View view = activity.getWindow().getDecorView().findViewById(android.R.id.content);\n                Snackbar.make(view, message, isLong ? Snackbar.LENGTH_LONG : Snackbar.LENGTH_SHORT).show();\n            } else {\n                ArmsUtils.makeText(mApplication, message);\n            }\n        }).subscribeOn(AndroidSchedulers.mainThread()).subscribe();\n\n    }\n\n    /**\n     * 让在栈顶的 {@link Activity} ,打开指定的 {@link Activity}\n     *\n     * @param intent\n     */\n    public void startActivity(Intent intent) {\n        if (getTopActivity() == null) {\n            Timber.tag(TAG).w(\"mCurrentActivity == null when startActivity(Intent)\");\n            //如果没有前台的activity就使用new_task模式启动activity\n            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            mApplication.startActivity(intent);\n            return;\n        }\n        getTopActivity().startActivity(intent);\n    }\n\n    /**\n     * 让在栈顶的 {@link Activity} ,打开指定的 {@link Activity}\n     *\n     * @param activityClass\n     */\n    public void startActivity(Class activityClass) {\n        startActivity(new Intent(mApplication, activityClass));\n    }\n\n    /**\n     * 释放资源\n     */\n    public void release() {\n        mActivityList.clear();\n        mHandleListener = null;\n        mActivityList = null;\n        mCurrentActivity = null;\n        mApplication = null;\n    }\n\n    /**\n     * 获取在前台的 {@link Activity} (保证获取到的 {@link Activity} 正处于可见状态, 即未调用 {@link Activity#onStop()}), 获取的 {@link Activity} 存续时间\n     * 是在 {@link Activity#onStop()} 之前, 所以如果当此 {@link Activity} 调用 {@link Activity#onStop()} 方法之后, 没有其他的 {@link Activity} 回到前台(用户返回桌面或者打开了其他 App 会出现此状况)\n     * 这时调用 {@link #getCurrentActivity()} 有可能返回 {@code null}, 所以请注意使用场景和 {@link #getTopActivity()} 不一样\n     * <p>\n     * Example usage:\n     * 使用场景比较适合, 只需要在可见状态的 {@link Activity} 上执行的操作\n     * 如当后台 {@link Service} 执行某个任务时, 需要让前台 {@link Activity} ,做出某种响应操作或其他操作,如弹出 {@link Dialog}, 这时在 {@link Service} 中就可以使用 {@link #getCurrentActivity()}\n     * 如果返回为 {@code null}, 说明没有前台 {@link Activity} (用户返回桌面或者打开了其他 App 会出现此状况), 则不做任何操作, 不为 {@code null}, 则弹出 {@link Dialog}\n     *\n     * @return\n     */\n    @Nullable\n    public Activity getCurrentActivity() {\n        return mCurrentActivity;\n    }\n\n    /**\n     * 将在前台的 {@link Activity} 赋值给 {@code currentActivity}, 注意此方法是在 {@link Activity#onResume} 方法执行时将栈顶的 {@link Activity} 赋值给 {@code currentActivity}\n     * 所以在栈顶的 {@link Activity} 执行 {@link Activity#onCreate} 方法时使用 {@link #getCurrentActivity()} 获取的就不是当前栈顶的 {@link Activity}, 可能是上一个 {@link Activity}\n     * 如果在 App 启动第一个 {@link Activity} 执行 {@link Activity#onCreate} 方法时使用 {@link #getCurrentActivity()} 则会出现返回为 {@code null} 的情况\n     * 想避免这种情况请使用 {@link #getTopActivity()}\n     *\n     * @param currentActivity\n     */\n    public void setCurrentActivity(Activity currentActivity) {\n        this.mCurrentActivity = currentActivity;\n    }\n\n    /**\n     * 获取最近启动的一个 {@link Activity}, 此方法不保证获取到的 {@link Activity} 正处于前台可见状态\n     * 即使 App 进入后台或在这个 {@link Activity} 中打开一个之前已经存在的 {@link Activity}, 这时调用此方法\n     * 还是会返回这个最近启动的 {@link Activity}, 因此基本不会出现 {@code null} 的情况\n     * 比较适合大部分的使用场景, 如 startActivity\n     * <p>\n     * Tips: mActivityList 容器中的顺序仅仅是 Activity 的创建顺序, 并不能保证和 Activity 任务栈顺序一致\n     *\n     * @return\n     */\n    @Nullable\n    public Activity getTopActivity() {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when getTopActivity()\");\n            return null;\n        }\n        return mActivityList.size() > 0 ? mActivityList.get(mActivityList.size() - 1) : null;\n    }\n\n    /**\n     * 返回一个存储所有未销毁的 {@link Activity} 的集合\n     *\n     * @return\n     */\n    public List<Activity> getActivityList() {\n        if (mActivityList == null) {\n            mActivityList = new LinkedList<>();\n        }\n        return mActivityList;\n    }\n\n    /**\n     * 添加 {@link Activity} 到集合\n     */\n    public void addActivity(Activity activity) {\n        synchronized (AppManager.class) {\n            List<Activity> activities = getActivityList();\n            if (!activities.contains(activity)) {\n                activities.add(activity);\n            }\n        }\n    }\n\n    /**\n     * 删除集合里的指定的 {@link Activity} 实例\n     *\n     * @param {@link Activity}\n     */\n    public void removeActivity(Activity activity) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when removeActivity(Activity)\");\n            return;\n        }\n        synchronized (AppManager.class) {\n            mActivityList.remove(activity);\n        }\n    }\n\n    /**\n     * 删除集合里的指定位置的 {@link Activity}\n     *\n     * @param location\n     */\n    public Activity removeActivity(int location) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when removeActivity(int)\");\n            return null;\n        }\n        synchronized (AppManager.class) {\n            if (location > 0 && location < mActivityList.size()) {\n                return mActivityList.remove(location);\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 关闭指定的 {@link Activity} class 的所有的实例\n     *\n     * @param activityClass\n     */\n    public void killActivity(Class<?> activityClass) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when killActivity(Class)\");\n            return;\n        }\n        synchronized (AppManager.class) {\n            Iterator<Activity> iterator = getActivityList().iterator();\n            while (iterator.hasNext()) {\n                Activity next = iterator.next();\n\n                if (next.getClass().equals(activityClass)) {\n                    iterator.remove();\n                    next.finish();\n                }\n            }\n        }\n    }\n\n    /**\n     * 指定的 {@link Activity} 实例是否存活\n     *\n     * @param {@link Activity}\n     * @return\n     */\n    public boolean activityInstanceIsLive(Activity activity) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when activityInstanceIsLive(Activity)\");\n            return false;\n        }\n        return mActivityList.contains(activity);\n    }\n\n    /**\n     * 指定的 {@link Activity} class 是否存活(同一个 {@link Activity} class 可能有多个实例)\n     *\n     * @param activityClass\n     * @return\n     */\n    public boolean activityClassIsLive(Class<?> activityClass) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when activityClassIsLive(Class)\");\n            return false;\n        }\n        for (Activity activity : mActivityList) {\n            if (activity.getClass().equals(activityClass)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 获取指定 {@link Activity} class 的实例,没有则返回 null(同一个 {@link Activity} class 有多个实例,则返回最早创建的实例)\n     *\n     * @param activityClass\n     * @return\n     */\n    public Activity findActivity(Class<?> activityClass) {\n        if (mActivityList == null) {\n            Timber.tag(TAG).w(\"mActivityList == null when findActivity(Class)\");\n            return null;\n        }\n        for (Activity activity : mActivityList) {\n            if (activity.getClass().equals(activityClass)) {\n                return activity;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 关闭所有 {@link Activity}\n     */\n    public void killAll() {\n//        while (getActivityList().size() != 0) { //此方法只能兼容LinkedList\n//            getActivityList().remove(0).finish();\n//        }\n        synchronized (AppManager.class) {\n            Iterator<Activity> iterator = getActivityList().iterator();\n            while (iterator.hasNext()) {\n                Activity next = iterator.next();\n                iterator.remove();\n                next.finish();\n            }\n        }\n    }\n\n    /**\n     * 关闭所有 {@link Activity},排除指定的 {@link Activity}\n     *\n     * @param excludeActivityClasses activity class\n     */\n    public void killAll(Class<?>... excludeActivityClasses) {\n        List<Class<?>> excludeList = Arrays.asList(excludeActivityClasses);\n        synchronized (AppManager.class) {\n            Iterator<Activity> iterator = getActivityList().iterator();\n            while (iterator.hasNext()) {\n                Activity next = iterator.next();\n\n                if (excludeList.contains(next.getClass())) {\n                    continue;\n                }\n\n                iterator.remove();\n                next.finish();\n            }\n        }\n    }\n\n    /**\n     * 关闭所有 {@link Activity},排除指定的 {@link Activity}\n     *\n     * @param excludeActivityName {@link Activity} 的完整全路径\n     */\n    public void killAll(String... excludeActivityName) {\n        List<String> excludeList = Arrays.asList(excludeActivityName);\n        synchronized (AppManager.class) {\n            Iterator<Activity> iterator = getActivityList().iterator();\n            while (iterator.hasNext()) {\n                Activity next = iterator.next();\n\n                if (excludeList.contains(next.getClass().getName())) {\n                    continue;\n                }\n\n                iterator.remove();\n                next.finish();\n            }\n        }\n    }\n\n    /**\n     * 退出应用程序\n     * <p>\n     * 此方法经测试在某些机型上并不能完全杀死 App 进程, 几乎试过市面上大部分杀死进程的方式, 但都发现没卵用, 所以此\n     * 方法如果不能百分之百保证能杀死进程, 就不能贸然调用 {@link #release()} 释放资源, 否则会造成其他问题, 如果您\n     * 有测试通过的并能适用于绝大多数机型的杀死进程的方式, 望告知\n     */\n    public void appExit() {\n        try {\n            killAll();\n            android.os.Process.killProcess(android.os.Process.myPid());\n            System.exit(0);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Deprecated\n    public interface HandleListener {\n        void handleMessage(AppManager appManager, Message message);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/ConfigModule.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.base.delegate.AppLifecycles;\nimport com.jess.arms.di.module.GlobalConfigModule;\n\nimport java.util.List;\n\n/**\n * ================================================\n * {@link ConfigModule} 可以给框架配置一些参数,需要实现 {@link ConfigModule} 后,在 AndroidManifest 中声明该实现类\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.1\">ConfigModule wiki 官方文档</a>\n * Created by JessYan on 12/04/2017 11:37\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface ConfigModule {\n    /**\n     * 使用 {@link GlobalConfigModule.Builder} 给框架配置一些配置参数\n     *\n     * @param context {@link Context}\n     * @param builder {@link GlobalConfigModule.Builder}\n     */\n    void applyOptions(@NonNull Context context, @NonNull GlobalConfigModule.Builder builder);\n\n    /**\n     * 使用 {@link AppLifecycles} 在 {@link Application} 的生命周期中注入一些操作\n     *\n     * @param context    {@link Context}\n     * @param lifecycles {@link Application} 的生命周期容器, 可向框架中添加多个 {@link Application} 的生命周期类\n     */\n    void injectAppLifecycle(@NonNull Context context, @NonNull List<AppLifecycles> lifecycles);\n\n    /**\n     * 使用 {@link Application.ActivityLifecycleCallbacks} 在 {@link Activity} 的生命周期中注入一些操作\n     *\n     * @param context    {@link Context}\n     * @param lifecycles {@link Activity} 的生命周期容器, 可向框架中添加多个 {@link Activity} 的生命周期类\n     */\n    void injectActivityLifecycle(@NonNull Context context, @NonNull List<Application.ActivityLifecycleCallbacks> lifecycles);\n\n    /**\n     * 使用 {@link FragmentManager.FragmentLifecycleCallbacks} 在 {@link Fragment} 的生命周期中注入一些操作\n     *\n     * @param context    {@link Context}\n     * @param lifecycles {@link Fragment} 的生命周期容器, 可向框架中添加多个 {@link Fragment} 的生命周期类\n     */\n    void injectFragmentLifecycle(@NonNull Context context, @NonNull List<FragmentManager.FragmentLifecycleCallbacks> lifecycles);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/EventBusManager.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport org.greenrobot.eventbus.Subscribe;\n\nimport java.lang.reflect.Method;\n\nimport static com.jess.arms.base.Platform.DEPENDENCY_ANDROID_EVENTBUS;\nimport static com.jess.arms.base.Platform.DEPENDENCY_EVENTBUS;\n\n/**\n * ================================================\n * EventBus 的管理类, Arms 核心库并不会依赖某个 EventBus, 如果您想使用 EventBus, 则请在项目中自行依赖对应的 EventBus, 如果不想使用则不依赖\n * 支持 greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n * 这个类并不能完全做到 EventBus 对外界的零耦合, 只能降低耦合, 因为两个 EventBus 的部分功能使用方法差别太大, 做到完全解耦代价太大\n * 允许同时使用两个 EventBus 但不建议这样做, 建议使用 AndroidEventBus, 特别是组件化项目, 原因请看 https://github.com/hehonghui/AndroidEventBus/issues/49\n * <p>\n * Created by JessYan on 2018/8/1 15:28\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic final class EventBusManager {\n    private static volatile EventBusManager sInstance;\n\n    private EventBusManager() {\n    }\n\n    public static EventBusManager getInstance() {\n        if (sInstance == null) {\n            synchronized (EventBusManager.class) {\n                if (sInstance == null) {\n                    sInstance = new EventBusManager();\n                }\n            }\n        }\n        return sInstance;\n    }\n\n    /**\n     * 注册订阅者, 允许在项目中同时依赖两个 EventBus, 只要您喜欢\n     *\n     * @param subscriber 订阅者\n     */\n    public void register(Object subscriber) {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().register(subscriber);\n        }\n        if (DEPENDENCY_EVENTBUS) {\n            if (haveAnnotation(subscriber)) {\n                org.greenrobot.eventbus.EventBus.getDefault().register(subscriber);\n            }\n        }\n    }\n\n    /**\n     * 注销订阅者, 允许在项目中同时依赖两个 EventBus, 只要您喜欢\n     *\n     * @param subscriber 订阅者\n     */\n    public void unregister(Object subscriber) {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().unregister(subscriber);\n        }\n        if (DEPENDENCY_EVENTBUS) {\n            if (haveAnnotation(subscriber)) {\n                org.greenrobot.eventbus.EventBus.getDefault().unregister(subscriber);\n            }\n        }\n    }\n\n    /**\n     * 发送事件, 如果您在项目中同时依赖了两个 EventBus, 请自己使用想使用的 EventBus 的 Api 发送事件\n     *\n     * @param event 事件\n     */\n    public void post(Object event) {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().post(event);\n        } else if (DEPENDENCY_EVENTBUS) {\n            org.greenrobot.eventbus.EventBus.getDefault().post(event);\n        }\n    }\n\n    /**\n     * 发送黏性事件, 如果您在项目中同时依赖了两个 EventBus, 请自己使用想使用的 EventBus 的 Api 发送黏性事件\n     *\n     * @param event 事件\n     */\n    public void postSticky(Object event) {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().postSticky(event);\n        } else if (DEPENDENCY_EVENTBUS) {\n            org.greenrobot.eventbus.EventBus.getDefault().postSticky(event);\n        }\n    }\n\n    /**\n     * 注销黏性事件, 如果您在项目中同时依赖了两个 EventBus, 请自己使用想使用的 EventBus 的 Api 注销黏性事件\n     *\n     * @param eventType\n     * @param <T>\n     * @return\n     */\n    public <T> T removeStickyEvent(Class<T> eventType) {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().removeStickyEvent(eventType);\n            return null;\n        } else if (DEPENDENCY_EVENTBUS) {\n            return org.greenrobot.eventbus.EventBus.getDefault().removeStickyEvent(eventType);\n        }\n        return null;\n    }\n\n    /**\n     * 清除订阅者和事件的缓存, 如果您在项目中同时依赖了两个 EventBus, 请自己使用想使用的 EventBus 的 Api 清除订阅者和事件的缓存\n     */\n    public void clear() {\n        if (DEPENDENCY_ANDROID_EVENTBUS) {\n            org.simple.eventbus.EventBus.getDefault().clear();\n        } else if (DEPENDENCY_EVENTBUS) {\n            org.greenrobot.eventbus.EventBus.clearCaches();\n        }\n    }\n\n    /**\n     * {@link org.greenrobot.eventbus.EventBus} 要求注册之前, 订阅者必须含有一个或以上声明 {@link org.greenrobot.eventbus.Subscribe}\n     * 注解的方法, 否则会报错, 所以如果要想完成在基类中自动注册, 避免报错就要先检查是否符合注册资格\n     *\n     * @param subscriber 订阅者\n     * @return 返回 {@code true} 则表示含有 {@link org.greenrobot.eventbus.Subscribe} 注解, {@code false} 为不含有\n     */\n    private boolean haveAnnotation(Object subscriber) {\n        boolean skipSuperClasses = false;\n        Class<?> clazz = subscriber.getClass();\n        //查找类中符合注册要求的方法, 直到Object类\n        while (clazz != null && !isSystemCalss(clazz.getName()) && !skipSuperClasses) {\n            Method[] allMethods;\n            try {\n                allMethods = clazz.getDeclaredMethods();\n            } catch (Throwable th) {\n                try {\n                    allMethods = clazz.getMethods();\n                } catch (Throwable th2) {\n                    continue;\n                } finally {\n                    skipSuperClasses = true;\n                }\n            }\n            for (Method method : allMethods) {\n                Class<?>[] parameterTypes = method.getParameterTypes();\n                //查看该方法是否含有 Subscribe 注解\n                if (method.isAnnotationPresent(Subscribe.class) && parameterTypes.length == 1) {\n                    return true;\n                }\n            } //end for\n            //获取父类, 以继续查找父类中符合要求的方法\n            clazz = clazz.getSuperclass();\n        }\n        return false;\n    }\n\n    private boolean isSystemCalss(String name) {\n        return name.startsWith(\"java.\") || name.startsWith(\"javax.\") || name.startsWith(\"android.\");\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/FragmentLifecycle.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.base.delegate.FragmentDelegate;\nimport com.jess.arms.base.delegate.FragmentDelegateImpl;\nimport com.jess.arms.base.delegate.IFragment;\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.IntelligentCache;\nimport com.jess.arms.utils.Preconditions;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\n/**\n * ================================================\n * {@link FragmentManager.FragmentLifecycleCallbacks} 默认实现类\n * 通过 {@link FragmentDelegate} 管理 {@link Fragment}\n * <p>\n * Created by JessYan on 04/09/2017 16:04\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic class FragmentLifecycle extends FragmentManager.FragmentLifecycleCallbacks {\n\n    @Inject\n    public FragmentLifecycle() {\n    }\n\n    @Override\n    public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {\n        if (f instanceof IFragment) {\n            FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n            if (fragmentDelegate == null || !fragmentDelegate.isAdded()) {\n                Cache<String, Object> cache = getCacheFromFragment((IFragment) f);\n                fragmentDelegate = new FragmentDelegateImpl(fm, f);\n                //使用 IntelligentCache.KEY_KEEP 作为 key 的前缀, 可以使储存的数据永久存储在内存中\n                //否则存储在 LRU 算法的存储空间中, 前提是 Fragment 使用的是 IntelligentCache (框架默认使用)\n                cache.put(IntelligentCache.getKeyOfKeep(FragmentDelegate.FRAGMENT_DELEGATE), fragmentDelegate);\n            }\n            fragmentDelegate.onAttach(context);\n        }\n    }\n\n    @Override\n    public void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f, Bundle savedInstanceState) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onCreate(savedInstanceState);\n        }\n    }\n\n    @Override\n    public void onFragmentViewCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull View v, Bundle savedInstanceState) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onCreateView(v, savedInstanceState);\n        }\n    }\n\n    @Override\n    public void onFragmentActivityCreated(@NonNull FragmentManager fm, @NonNull Fragment f, Bundle savedInstanceState) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onActivityCreate(savedInstanceState);\n        }\n    }\n\n    @Override\n    public void onFragmentStarted(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onStart();\n        }\n    }\n\n    @Override\n    public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onResume();\n        }\n    }\n\n    @Override\n    public void onFragmentPaused(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onPause();\n        }\n    }\n\n    @Override\n    public void onFragmentStopped(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onStop();\n        }\n    }\n\n    @Override\n    public void onFragmentSaveInstanceState(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Bundle outState) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onSaveInstanceState(outState);\n        }\n    }\n\n    @Override\n    public void onFragmentViewDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onDestroyView();\n        }\n    }\n\n    @Override\n    public void onFragmentDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onDestroy();\n        }\n    }\n\n    @Override\n    public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {\n        FragmentDelegate fragmentDelegate = fetchFragmentDelegate(f);\n        if (fragmentDelegate != null) {\n            fragmentDelegate.onDetach();\n        }\n    }\n\n    private FragmentDelegate fetchFragmentDelegate(Fragment fragment) {\n        if (fragment instanceof IFragment) {\n            Cache<String, Object> cache = getCacheFromFragment((IFragment) fragment);\n            return (FragmentDelegate) cache.get(IntelligentCache.getKeyOfKeep(FragmentDelegate.FRAGMENT_DELEGATE));\n        }\n        return null;\n    }\n\n    @NonNull\n    private Cache<String, Object> getCacheFromFragment(IFragment fragment) {\n        Cache<String, Object> cache = fragment.provideCache();\n        Preconditions.checkNotNull(cache, \"%s cannot be null on Fragment\", Cache.class.getName());\n        return cache;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/IRepositoryManager.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.mvp.IModel;\n\nimport retrofit2.Retrofit;\n\n/**\n * ================================================\n * 用来管理网络请求层,以及数据缓存层,以后可能添加数据库请求层\n * 提供给 {@link IModel} 必要的 Api 做数据处理\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.3\">RepositoryManager wiki 官方文档</a>\n * Created by JessYan on 17/03/2017 11:15\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IRepositoryManager {\n\n    /**\n     * 根据传入的 Class 获取对应的 Retrofit service\n     *\n     * @param service Retrofit service class\n     * @param <T>     Retrofit service 类型\n     * @return Retrofit service\n     */\n    @NonNull\n    <T> T obtainRetrofitService(@NonNull Class<T> service);\n\n\n    /**\n     * 根据传入的 Class 获取对应的 RxCache service\n     *\n     * @param cache RxCache service class\n     * @param <T>   RxCache service 类型\n     * @return RxCache service\n     */\n    @NonNull\n    <T> T obtainCacheService(@NonNull Class<T> cache);\n\n    /**\n     * 清理所有缓存\n     */\n    void clearAllCache();\n\n    /**\n     * 获取 {@link Context}\n     *\n     * @return {@link Context}\n     */\n    @NonNull\n    Context getContext();\n\n    interface ObtainServiceDelegate {\n\n        @Nullable\n        <T> T createRetrofitService(Retrofit retrofit, Class<T> serviceClass);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/ManifestParser.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ================================================\n * 用于解析 AndroidManifest 中的 Meta 属性\n * 配合 {@link ConfigModule} 使用\n * <p>\n * Created by JessYan on 12/04/2017 14:41\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic final class ManifestParser {\n    private static final String MODULE_VALUE = \"ConfigModule\";\n    private final Context context;\n\n    public ManifestParser(Context context) {\n        this.context = context;\n    }\n\n    private static ConfigModule parseModule(String className) {\n        Class<?> clazz;\n        try {\n            clazz = Class.forName(className);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalArgumentException(\"Unable to find ConfigModule implementation\", e);\n        }\n\n        Object module;\n        try {\n            module = clazz.newInstance();\n        } catch (InstantiationException e) {\n            throw new RuntimeException(\"Unable to instantiate ConfigModule implementation for \" + clazz, e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(\"Unable to instantiate ConfigModule implementation for \" + clazz, e);\n        }\n\n        if (!(module instanceof ConfigModule)) {\n            throw new RuntimeException(\"Expected instanceof ConfigModule, but found: \" + module);\n        }\n        return (ConfigModule) module;\n    }\n\n    public List<ConfigModule> parse() {\n        List<ConfigModule> modules = new ArrayList<>();\n        try {\n            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(\n                    context.getPackageName(), PackageManager.GET_META_DATA);\n            if (appInfo.metaData != null) {\n                for (String key : appInfo.metaData.keySet()) {\n                    if (MODULE_VALUE.equals(appInfo.metaData.get(key))) {\n                        modules.add(parseModule(key));\n                    }\n                }\n            }\n        } catch (PackageManager.NameNotFoundException e) {\n            throw new RuntimeException(\"Unable to find metadata to parse ConfigModule\", e);\n        }\n\n        return modules;\n    }\n}"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/RepositoryManager.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.integration.cache.Cache;\nimport com.jess.arms.integration.cache.CacheType;\nimport com.jess.arms.mvp.IModel;\nimport com.jess.arms.utils.Preconditions;\n\nimport java.lang.reflect.Proxy;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\nimport dagger.Lazy;\nimport io.rx_cache2.internal.RxCache;\nimport retrofit2.Retrofit;\n\n/**\n * ================================================\n * 用来管理网络请求层,以及数据缓存层,以后可能添加数据库请求层\n * 提供给 {@link IModel} 层必要的 Api 做数据处理\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.3\">RepositoryManager wiki 官方文档</a>\n * Created by JessYan on 13/04/2017 09:52\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@SuppressWarnings(\"unchecked\")\n@Singleton\npublic class RepositoryManager implements IRepositoryManager {\n\n    @Inject\n    Lazy<Retrofit> mRetrofit;\n    @Inject\n    Lazy<RxCache> mRxCache;\n    @Inject\n    Application mApplication;\n    @Inject\n    Cache.Factory mCacheFactory;\n    @Inject\n    @Nullable\n    ObtainServiceDelegate mObtainServiceDelegate;\n    private Cache<String, Object> mRetrofitServiceCache;\n    private Cache<String, Object> mCacheServiceCache;\n\n    @Inject\n    public RepositoryManager() {\n    }\n\n    /**\n     * 根据传入的 Class 获取对应的 Retrofit service\n     *\n     * @param serviceClass ApiService class\n     * @param <T>          ApiService class\n     * @return ApiService\n     */\n    @NonNull\n    @Override\n    public synchronized <T> T obtainRetrofitService(@NonNull Class<T> serviceClass) {\n        if (mRetrofitServiceCache == null) {\n            mRetrofitServiceCache = mCacheFactory.build(CacheType.RETROFIT_SERVICE_CACHE);\n        }\n        Preconditions.checkNotNull(mRetrofitServiceCache,\n                \"Cannot return null from a Cache.Factory#build(int) method\");\n        T retrofitService = (T) mRetrofitServiceCache.get(serviceClass.getCanonicalName());\n        if (retrofitService == null) {\n            if (mObtainServiceDelegate != null) {\n                retrofitService = mObtainServiceDelegate.createRetrofitService(\n                        mRetrofit.get(), serviceClass);\n            }\n            if (retrofitService == null) {\n                retrofitService = (T) Proxy.newProxyInstance(\n                        serviceClass.getClassLoader(),\n                        new Class[]{serviceClass},\n                        new RetrofitServiceProxyHandler(mRetrofit.get(), serviceClass));\n            }\n            mRetrofitServiceCache.put(serviceClass.getCanonicalName(), retrofitService);\n        }\n        return retrofitService;\n    }\n\n    /**\n     * 根据传入的 Class 获取对应的 RxCache service\n     *\n     * @param cacheClass Cache class\n     * @param <T>        Cache class\n     * @return Cache\n     */\n    @NonNull\n    @Override\n    public synchronized <T> T obtainCacheService(@NonNull Class<T> cacheClass) {\n        Preconditions.checkNotNull(cacheClass, \"cacheClass == null\");\n        if (mCacheServiceCache == null) {\n            mCacheServiceCache = mCacheFactory.build(CacheType.CACHE_SERVICE_CACHE);\n        }\n        Preconditions.checkNotNull(mCacheServiceCache,\n                \"Cannot return null from a Cache.Factory#build(int) method\");\n        T cacheService = (T) mCacheServiceCache.get(cacheClass.getCanonicalName());\n        if (cacheService == null) {\n            cacheService = mRxCache.get().using(cacheClass);\n            mCacheServiceCache.put(cacheClass.getCanonicalName(), cacheService);\n        }\n        return cacheService;\n    }\n\n    /**\n     * 清理所有缓存\n     */\n    @Override\n    public void clearAllCache() {\n        mRxCache.get().evictAll().subscribe();\n    }\n\n    @NonNull\n    @Override\n    public Context getContext() {\n        return mApplication;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/RetrofitServiceProxyHandler.java",
    "content": "package com.jess.arms.integration;\n\nimport androidx.annotation.Nullable;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\n\nimport io.reactivex.Observable;\nimport io.reactivex.Single;\nimport retrofit2.Retrofit;\n\n\npublic class RetrofitServiceProxyHandler implements InvocationHandler {\n\n    private Retrofit mRetrofit;\n    private Class<?> mServiceClass;\n    private Object mRetrofitService;\n\n    public RetrofitServiceProxyHandler(Retrofit retrofit, Class<?> serviceClass) {\n        mRetrofit = retrofit;\n        mServiceClass = serviceClass;\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {\n\n        // 根据 https://zhuanlan.zhihu.com/p/40097338 对 Retrofit 进行的优化\n\n        if (method.getReturnType() == Observable.class) {\n            // 如果方法返回值是 Observable 的话，则包一层再返回，\n            // 只包一层 defer 由外部去控制耗时方法以及网络请求所处线程，\n            // 如此对原项目的影响为 0，且更可控。\n            return Observable.defer(() -> {\n                // 执行真正的 Retrofit 动态代理的方法\n                return (Observable) method.invoke(getRetrofitService(), args);\n            });\n        } else if (method.getReturnType() == Single.class) {\n            // 如果方法返回值是 Single 的话，则包一层再返回。\n            return Single.defer(() -> {\n                // 执行真正的 Retrofit 动态代理的方法\n                return (Single) method.invoke(getRetrofitService(), args);\n            });\n        }\n\n        // 返回值不是 Observable 或 Single 的话不处理。\n        return method.invoke(getRetrofitService(), args);\n    }\n\n    private Object getRetrofitService() {\n        if (mRetrofitService == null) {\n            mRetrofitService = mRetrofit.create(mServiceClass);\n        }\n        return mRetrofitService;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/cache/Cache.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.cache;\n\nimport android.app.Application;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\n\nimport java.util.Set;\n\n\n/**\n * ================================================\n * 用于缓存框架中所必需的组件,开发者可通过 {@link GlobalConfigModule.Builder#cacheFactory(Factory)} 为框架提供缓存策略\n * 开发者也可以用于自己日常中的使用\n *\n * @see GlobalConfigModule#provideCacheFactory(Application)\n * @see LruCache\n * Created by JessYan on 25/09/2017 16:36\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface Cache<K, V> {\n\n    /**\n     * 返回当前缓存已占用的总 size\n     *\n     * @return {@code size}\n     */\n    int size();\n\n    /**\n     * 返回当前缓存所能允许的最大 size\n     *\n     * @return {@code maxSize}\n     */\n    int getMaxSize();\n\n    /**\n     * 返回这个 {@code key} 在缓存中对应的 {@code value}, 如果返回 {@code null} 说明这个 {@code key} 没有对应的 {@code value}\n     *\n     * @param key {@code key}\n     * @return {@code value}\n     */\n    @Nullable\n    V get(K key);\n\n    /**\n     * 将 {@code key} 和 {@code value} 以条目的形式加入缓存,如果这个 {@code key} 在缓存中已经有对应的 {@code value}\n     * 则此 {@code value} 被新的 {@code value} 替换并返回,如果为 {@code null} 说明是一个新条目\n     *\n     * @param key   {@code key}\n     * @param value {@code value}\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value}, 则返回之前的 {@code value} 否则返回 {@code null}\n     */\n    @Nullable\n    V put(K key, V value);\n\n    /**\n     * 移除缓存中这个 {@code key} 所对应的条目,并返回所移除条目的 value\n     * 如果返回为 {@code null} 则有可能时因为这个 {@code key} 对应的 value 为 {@code null} 或条目不存在\n     *\n     * @param key {@code key}\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value} 并且删除成功则返回删除的 {@code value}, 否则返回 {@code null}\n     */\n    @Nullable\n    V remove(K key);\n\n    /**\n     * 如果这个 {@code key} 在缓存中有对应的 value 并且不为 {@code null}, 则返回 {@code true}\n     *\n     * @param key {@code key}\n     * @return {@code true} 为在容器中含有这个 {@code key}, 否则为 {@code false}\n     */\n    boolean containsKey(K key);\n\n    /**\n     * 返回当前缓存中含有的所有 {@code key}\n     *\n     * @return {@code keySet}\n     */\n    Set<K> keySet();\n\n    /**\n     * 清除缓存中所有的内容\n     */\n    void clear();\n\n    interface Factory {\n\n        /**\n         * Returns a new cache\n         *\n         * @param type 框架中需要缓存的模块类型\n         * @return {@link Cache}\n         */\n        @NonNull\n        Cache build(CacheType type);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/cache/CacheType.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.cache;\n\nimport android.app.Activity;\nimport android.app.ActivityManager;\nimport android.content.Context;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.integration.RepositoryManager;\n\n/**\n * ================================================\n * 构建 {@link Cache} 时,使用 {@link CacheType} 中声明的类型,来区分不同的模块\n * 从而为不同的模块构建不同的缓存策略\n *\n * @see Cache.Factory#build(CacheType)\n * Created by JessYan on 25/09/2017 18:05\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface CacheType {\n    int RETROFIT_SERVICE_CACHE_TYPE_ID = 0;\n    int CACHE_SERVICE_CACHE_TYPE_ID = 1;\n    int EXTRAS_TYPE_ID = 2;\n    int ACTIVITY_CACHE_TYPE_ID = 3;\n    int FRAGMENT_CACHE_TYPE_ID = 4;\n    /**\n     * {@link RepositoryManager}中存储 Retrofit Service 的容器\n     */\n    CacheType RETROFIT_SERVICE_CACHE = new CacheType() {\n        private static final int MAX_SIZE = 150;\n        private static final float MAX_SIZE_MULTIPLIER = 0.002f;\n\n        @Override\n        public int getCacheTypeId() {\n            return RETROFIT_SERVICE_CACHE_TYPE_ID;\n        }\n\n        @Override\n        public int calculateCacheSize(Context context) {\n            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n            int targetMemoryCacheSize = (int) (activityManager.getMemoryClass() * MAX_SIZE_MULTIPLIER * 1024);\n            if (targetMemoryCacheSize >= MAX_SIZE) {\n                return MAX_SIZE;\n            }\n            return targetMemoryCacheSize;\n        }\n    };\n\n    /**\n     * {@link RepositoryManager} 中储存 Cache Service 的容器\n     */\n    CacheType CACHE_SERVICE_CACHE = new CacheType() {\n        private static final int MAX_SIZE = 150;\n        private static final float MAX_SIZE_MULTIPLIER = 0.002f;\n\n        @Override\n        public int getCacheTypeId() {\n            return CACHE_SERVICE_CACHE_TYPE_ID;\n        }\n\n        @Override\n        public int calculateCacheSize(Context context) {\n            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n            int targetMemoryCacheSize = (int) (activityManager.getMemoryClass() * MAX_SIZE_MULTIPLIER * 1024);\n            if (targetMemoryCacheSize >= MAX_SIZE) {\n                return MAX_SIZE;\n            }\n            return targetMemoryCacheSize;\n        }\n    };\n\n    /**\n     * {@link AppComponent} 中的 extras\n     */\n    CacheType EXTRAS = new CacheType() {\n        private static final int MAX_SIZE = 500;\n        private static final float MAX_SIZE_MULTIPLIER = 0.005f;\n\n        @Override\n        public int getCacheTypeId() {\n            return EXTRAS_TYPE_ID;\n        }\n\n        @Override\n        public int calculateCacheSize(Context context) {\n            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n            int targetMemoryCacheSize = (int) (activityManager.getMemoryClass() * MAX_SIZE_MULTIPLIER * 1024);\n            if (targetMemoryCacheSize >= MAX_SIZE) {\n                return MAX_SIZE;\n            }\n            return targetMemoryCacheSize;\n        }\n    };\n\n    /**\n     * {@link Activity} 中存储数据的容器\n     */\n    CacheType ACTIVITY_CACHE = new CacheType() {\n        private static final int MAX_SIZE = 80;\n        private static final float MAX_SIZE_MULTIPLIER = 0.0008f;\n\n        @Override\n        public int getCacheTypeId() {\n            return ACTIVITY_CACHE_TYPE_ID;\n        }\n\n        @Override\n        public int calculateCacheSize(Context context) {\n            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n            int targetMemoryCacheSize = (int) (activityManager.getMemoryClass() * MAX_SIZE_MULTIPLIER * 1024);\n            if (targetMemoryCacheSize >= MAX_SIZE) {\n                return MAX_SIZE;\n            }\n            return targetMemoryCacheSize;\n        }\n    };\n\n    /**\n     * {@link Fragment} 中存储数据的容器\n     */\n    CacheType FRAGMENT_CACHE = new CacheType() {\n        private static final int MAX_SIZE = 80;\n        private static final float MAX_SIZE_MULTIPLIER = 0.0008f;\n\n        @Override\n        public int getCacheTypeId() {\n            return FRAGMENT_CACHE_TYPE_ID;\n        }\n\n        @Override\n        public int calculateCacheSize(Context context) {\n            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n            int targetMemoryCacheSize = (int) (activityManager.getMemoryClass() * MAX_SIZE_MULTIPLIER * 1024);\n            if (targetMemoryCacheSize >= MAX_SIZE) {\n                return MAX_SIZE;\n            }\n            return targetMemoryCacheSize;\n        }\n    };\n\n    /**\n     * 返回框架内需要缓存的模块对应的 {@code id}\n     *\n     * @return\n     */\n    int getCacheTypeId();\n\n    /**\n     * 计算对应模块需要的缓存大小\n     *\n     * @return\n     */\n    int calculateCacheSize(Context context);\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/cache/IntelligentCache.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.cache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.utils.Preconditions;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * ================================================\n * {@link IntelligentCache} 含有可将数据永久存储至内存中的存储容器 {@link #mMap}, 和当达到最大容量时可根据 LRU\n * 算法抛弃不合规数据的存储容器 {@link #mCache}\n * <p>\n * {@link IntelligentCache} 可根据您传入的 {@code key} 智能的判断您需要将数据存储至哪个存储容器, 从而针对数据\n * 的不同特性进行不同的存储优化\n * <p>\n * 调用 {@link IntelligentCache#put(Object, Object)} 方法, 使用 {@link #KEY_KEEP} + {@code key} 作为 key 传入的\n * {@code value} 可存储至 {@link #mMap} (数据永久存储至内存中, 适合比较重要的数据) 中, 否则储存至 {@link #mCache}\n * <p>\n * Created by JessYan on 12/04/2018 16:06\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class IntelligentCache<V> implements Cache<String, V> {\n    public static final String KEY_KEEP = \"Keep=\";\n    private final Map<String, V> mMap;//可将数据永久存储至内存中的存储容器\n    private final Cache<String, V> mCache;//当达到最大容量时可根据 LRU 算法抛弃不合规数据的存储容器\n\n    public IntelligentCache(int size) {\n        this.mMap = new HashMap<>();\n        this.mCache = new LruCache<>(size);\n    }\n\n    /**\n     * 使用此方法返回的值作为 key, 可以将数据永久存储至内存中\n     *\n     * @param key {@code key}\n     * @return Keep= + {@code key}\n     */\n    @NonNull\n    public static String getKeyOfKeep(@NonNull String key) {\n        Preconditions.checkNotNull(key, \"key == null\");\n        return IntelligentCache.KEY_KEEP + key;\n    }\n\n    /**\n     * 将 {@link #mMap} 和 {@link #mCache} 的 {@code size} 相加后返回\n     *\n     * @return 相加后的 {@code size}\n     */\n    @Override\n    public synchronized int size() {\n        return mMap.size() + mCache.size();\n    }\n\n    /**\n     * 将 {@link #mMap} 和 {@link #mCache} 的 {@code maxSize} 相加后返回\n     *\n     * @return 相加后的 {@code maxSize}\n     */\n    @Override\n    public synchronized int getMaxSize() {\n        return mMap.size() + mCache.getMaxSize();\n    }\n\n    /**\n     * 如果在 {@code key} 中使用 {@link #KEY_KEEP} 作为其前缀, 则操作 {@link #mMap}, 否则操作 {@link #mCache}\n     *\n     * @param key {@code key}\n     * @return {@code value}\n     */\n    @Nullable\n    @Override\n    public synchronized V get(String key) {\n        if (key.startsWith(KEY_KEEP)) {\n            return mMap.get(key);\n        }\n        return mCache.get(key);\n    }\n\n    /**\n     * 如果在 {@code key} 中使用 {@link #KEY_KEEP} 作为其前缀, 则操作 {@link #mMap}, 否则操作 {@link #mCache}\n     *\n     * @param key   {@code key}\n     * @param value {@code value}\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value}, 则返回之前的 {@code value} 否则返回 {@code null}\n     */\n    @Nullable\n    @Override\n    public synchronized V put(String key, V value) {\n        if (key.startsWith(KEY_KEEP)) {\n            return mMap.put(key, value);\n        }\n        return mCache.put(key, value);\n    }\n\n    /**\n     * 如果在 {@code key} 中使用 {@link #KEY_KEEP} 作为其前缀, 则操作 {@link #mMap}, 否则操作 {@link #mCache}\n     *\n     * @param key {@code key}\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value} 并且删除成功则返回删除的 {@code value}, 否则返回 {@code null}\n     */\n    @Nullable\n    @Override\n    public synchronized V remove(String key) {\n        if (key.startsWith(KEY_KEEP)) {\n            return mMap.remove(key);\n        }\n        return mCache.remove(key);\n    }\n\n    /**\n     * 如果在 {@code key} 中使用 {@link #KEY_KEEP} 作为其前缀, 则操作 {@link #mMap}, 否则操作 {@link #mCache}\n     *\n     * @param key {@code key}\n     * @return {@code true} 为在容器中含有这个 {@code key}, 否则为 {@code false}\n     */\n    @Override\n    public synchronized boolean containsKey(String key) {\n        if (key.startsWith(KEY_KEEP)) {\n            return mMap.containsKey(key);\n        }\n        return mCache.containsKey(key);\n    }\n\n    /**\n     * 将 {@link #mMap} 和 {@link #mCache} 的 {@code keySet} 合并返回\n     *\n     * @return 合并后的 {@code keySet}\n     */\n    @Override\n    public synchronized Set<String> keySet() {\n        Set<String> set = mCache.keySet();\n        set.addAll(mMap.keySet());\n        return set;\n    }\n\n    /**\n     * 清空 {@link #mMap} 和 {@link #mCache} 容器\n     */\n    @Override\n    public void clear() {\n        mCache.clear();\n        mMap.clear();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/cache/LruCache.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.cache;\n\nimport android.app.Application;\n\nimport androidx.annotation.Nullable;\n\nimport com.jess.arms.di.module.GlobalConfigModule;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n\n/**\n * ================================================\n * LRU 即 Least Recently Used,最近最少使用,也就是说,当缓存满了,会优先淘汰那些最近最不常访问的数据\n * 此种缓存策略为框架默认提供,可自行实现其他缓存策略,如磁盘缓存,为框架或开发者提供缓存的功能\n *\n * @see GlobalConfigModule#provideCacheFactory(Application)\n * @see Cache\n * Created by JessYan on 25/09/2017 16:57\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class LruCache<K, V> implements Cache<K, V> {\n    private final LinkedHashMap<K, V> cache = new LinkedHashMap<>(100, 0.75f, true);\n    private final int initialMaxSize;\n    private int maxSize;\n    private int currentSize = 0;\n\n    /**\n     * Constructor for LruCache.\n     *\n     * @param size 这个缓存的最大 size,这个 size 所使用的单位必须和 {@link #getItemSize(Object)} 所使用的单位一致.\n     */\n    public LruCache(int size) {\n        this.initialMaxSize = size;\n        this.maxSize = size;\n    }\n\n    /**\n     * 设置一个系数应用于当时构造函数中所传入的 size, 从而得到一个新的 {@link #maxSize}\n     * 并会立即调用 {@link #evict} 开始清除满足条件的条目\n     *\n     * @param multiplier 系数\n     */\n    public synchronized void setSizeMultiplier(float multiplier) {\n        if (multiplier < 0) {\n            throw new IllegalArgumentException(\"Multiplier must be >= 0\");\n        }\n        maxSize = Math.round(initialMaxSize * multiplier);\n        evict();\n    }\n\n    /**\n     * 返回每个 {@code item} 所占用的 size,默认为1,这个 size 的单位必须和构造函数所传入的 size 一致\n     * 子类可以重写这个方法以适应不同的单位,比如说 bytes\n     *\n     * @param item 每个 {@code item} 所占用的 size\n     * @return 单个 item 的 {@code size}\n     */\n    protected int getItemSize(V item) {\n        return 1;\n    }\n\n    /**\n     * 当缓存中有被驱逐的条目时,会回调此方法,默认空实现,子类可以重写这个方法\n     *\n     * @param key   被驱逐条目的 {@code key}\n     * @param value 被驱逐条目的 {@code value}\n     */\n    protected void onItemEvicted(K key, V value) {\n        // optional override\n    }\n\n    /**\n     * 返回当前缓存所能允许的最大 size\n     *\n     * @return {@code maxSize}\n     */\n    @Override\n    public synchronized int getMaxSize() {\n        return maxSize;\n    }\n\n    /**\n     * 返回当前缓存已占用的总 size\n     *\n     * @return {@code size}\n     */\n    @Override\n    public synchronized int size() {\n        return currentSize;\n    }\n\n    /**\n     * 如果这个 {@code key} 在缓存中有对应的 {@code value} 并且不为 {@code null},则返回 true\n     *\n     * @param key 用来映射的 {@code key}\n     * @return {@code true} 为在容器中含有这个 {@code key}, 否则为 {@code false}\n     */\n    @Override\n    public synchronized boolean containsKey(K key) {\n        return cache.containsKey(key);\n    }\n\n    /**\n     * 返回当前缓存中含有的所有 {@code key}\n     *\n     * @return {@code keySet}\n     */\n    @Override\n    public synchronized Set<K> keySet() {\n        return cache.keySet();\n    }\n\n    /**\n     * 返回这个 {@code key} 在缓存中对应的 {@code value}, 如果返回 {@code null} 说明这个 {@code key} 没有对应的 {@code value}\n     *\n     * @param key 用来映射的 {@code key}\n     * @return {@code value}\n     */\n    @Override\n    @Nullable\n    public synchronized V get(K key) {\n        return cache.get(key);\n    }\n\n    /**\n     * 将 {@code key} 和 {@code value} 以条目的形式加入缓存,如果这个 {@code key} 在缓存中已经有对应的 {@code value}\n     * 则此 {@code value} 被新的 {@code value} 替换并返回,如果为 {@code null} 说明是一个新条目\n     * <p>\n     * 如果 {@link #getItemSize} 返回的 size 大于或等于缓存所能允许的最大 size, 则不能向缓存中添加此条目\n     * 此时会回调 {@link #onItemEvicted(Object, Object)} 通知此方法当前被驱逐的条目\n     *\n     * @param key   通过这个 {@code key} 添加条目\n     * @param value 需要添加的 {@code value}\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value}, 则返回之前的 {@code value} 否则返回 {@code null}\n     */\n    @Override\n    @Nullable\n    public synchronized V put(K key, V value) {\n        final int itemSize = getItemSize(value);\n        if (itemSize >= maxSize) {\n            onItemEvicted(key, value);\n            return null;\n        }\n\n        final V result = cache.put(key, value);\n        if (value != null) {\n            currentSize += getItemSize(value);\n        }\n        if (result != null) {\n            currentSize -= getItemSize(result);\n        }\n        evict();\n\n        return result;\n    }\n\n    /**\n     * 移除缓存中这个 {@code key} 所对应的条目,并返回所移除条目的 {@code value}\n     * 如果返回为 {@code null} 则有可能时因为这个 {@code key} 对应的 {@code value} 为 {@code null} 或条目不存在\n     *\n     * @param key 使用这个 {@code key} 移除对应的条目\n     * @return 如果这个 {@code key} 在容器中已经储存有 {@code value} 并且删除成功则返回删除的 {@code value}, 否则返回 {@code null}\n     */\n    @Override\n    @Nullable\n    public synchronized V remove(K key) {\n        final V value = cache.remove(key);\n        if (value != null) {\n            currentSize -= getItemSize(value);\n        }\n        return value;\n    }\n\n    /**\n     * 清除缓存中所有的内容\n     */\n    @Override\n    public void clear() {\n        trimToSize(0);\n    }\n\n    /**\n     * 当指定的 size 小于当前缓存已占用的总 size 时,会开始清除缓存中最近最少使用的条目\n     *\n     * @param size {@code size}\n     */\n    protected synchronized void trimToSize(int size) {\n        Map.Entry<K, V> last;\n        while (currentSize > size) {\n            last = cache.entrySet().iterator().next();\n            final V toRemove = last.getValue();\n            currentSize -= getItemSize(toRemove);\n            final K key = last.getKey();\n            cache.remove(key);\n            onItemEvicted(key, toRemove);\n        }\n    }\n\n    /**\n     * 当缓存中已占用的总 size 大于所能允许的最大 size ,会使用  {@link #trimToSize(int)} 开始清除满足条件的条目\n     */\n    private void evict() {\n        trimToSize(maxSize);\n    }\n}\n\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/lifecycle/ActivityLifecycleForRxLifecycle.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.lifecycle;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.os.Bundle;\n\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.trello.rxlifecycle2.RxLifecycle;\nimport com.trello.rxlifecycle2.android.ActivityEvent;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\nimport dagger.Lazy;\nimport io.reactivex.subjects.Subject;\n\n/**\n * ================================================\n * 配合 {@link ActivityLifecycleable} 使用,使 {@link Activity} 具有 {@link RxLifecycle} 的特性\n * <p>\n * Created by JessYan on 25/08/2017 18:56\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic class ActivityLifecycleForRxLifecycle implements Application.ActivityLifecycleCallbacks {\n    @Inject\n    Lazy<FragmentLifecycleForRxLifecycle> mFragmentLifecycle;\n\n    @Inject\n    public ActivityLifecycleForRxLifecycle() {\n    }\n\n    /**\n     * 通过桥梁对象 {@code BehaviorSubject<ActivityEvent> mLifecycleSubject}\n     * 在每个 Activity 的生命周期中发出对应的生命周期事件\n     */\n    @Override\n    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.CREATE);\n            if (activity instanceof FragmentActivity) {\n                ((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifecycle.get(), true);\n            }\n        }\n    }\n\n    @Override\n    public void onActivityStarted(Activity activity) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.START);\n        }\n    }\n\n    @Override\n    public void onActivityResumed(Activity activity) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.RESUME);\n        }\n    }\n\n    @Override\n    public void onActivityPaused(Activity activity) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.PAUSE);\n        }\n    }\n\n    @Override\n    public void onActivityStopped(Activity activity) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.STOP);\n        }\n    }\n\n    @Override\n    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {\n\n    }\n\n    @Override\n    public void onActivityDestroyed(Activity activity) {\n        if (activity instanceof ActivityLifecycleable) {\n            obtainSubject(activity).onNext(ActivityEvent.DESTROY);\n        }\n    }\n\n    /**\n     * 从 {@link com.jess.arms.base.BaseActivity} 中获得桥梁对象 {@code BehaviorSubject<ActivityEvent> mLifecycleSubject}\n     *\n     * @see <a href=\"https://mcxiaoke.gitbooks.io/rxdocs/content/Subject.html\">BehaviorSubject 官方中文文档</a>\n     */\n    private Subject<ActivityEvent> obtainSubject(Activity activity) {\n        return ((ActivityLifecycleable) activity).provideLifecycleSubject();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/lifecycle/ActivityLifecycleable.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.lifecycle;\n\nimport android.app.Activity;\n\nimport com.trello.rxlifecycle2.RxLifecycle;\nimport com.trello.rxlifecycle2.android.ActivityEvent;\n\n/**\n * ================================================\n * 让 {@link Activity} 实现此接口,即可正常使用 {@link RxLifecycle}\n * <p>\n * Created by JessYan on 26/08/2017 17:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface ActivityLifecycleable extends Lifecycleable<ActivityEvent> {\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/lifecycle/FragmentLifecycleForRxLifecycle.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.lifecycle;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.trello.rxlifecycle2.RxLifecycle;\nimport com.trello.rxlifecycle2.android.FragmentEvent;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport javax.inject.Inject;\nimport javax.inject.Singleton;\n\nimport io.reactivex.subjects.Subject;\n\n/**\n * ================================================\n * 配合 {@link FragmentLifecycleable} 使用,使 {@link Fragment} 具有 {@link RxLifecycle} 的特性\n * <p>\n * Created by JessYan on 26/08/2017 16:02\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Singleton\npublic class FragmentLifecycleForRxLifecycle extends FragmentManager.FragmentLifecycleCallbacks {\n\n    @Inject\n    public FragmentLifecycleForRxLifecycle() {\n    }\n\n    @Override\n    public void onFragmentAttached(@NotNull @NonNull FragmentManager fm, @NotNull @NonNull Fragment f, @NotNull @NonNull Context context) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.ATTACH);\n        }\n    }\n\n    @Override\n    public void onFragmentCreated(@NotNull @NonNull FragmentManager fm, @NotNull @NonNull Fragment f, Bundle savedInstanceState) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.CREATE);\n        }\n    }\n\n    @Override\n    public void onFragmentViewCreated(@NotNull @NonNull FragmentManager fm, @NotNull @NonNull Fragment f, @NotNull @NonNull View v, Bundle savedInstanceState) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.CREATE_VIEW);\n        }\n    }\n\n    @Override\n    public void onFragmentStarted(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.START);\n        }\n    }\n\n    @Override\n    public void onFragmentResumed(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.RESUME);\n        }\n    }\n\n    @Override\n    public void onFragmentPaused(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.PAUSE);\n        }\n    }\n\n    @Override\n    public void onFragmentStopped(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.STOP);\n        }\n    }\n\n    @Override\n    public void onFragmentViewDestroyed(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.DESTROY_VIEW);\n        }\n    }\n\n    @Override\n    public void onFragmentDestroyed(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.DESTROY);\n        }\n    }\n\n    @Override\n    public void onFragmentDetached(@NotNull FragmentManager fm, @NotNull Fragment f) {\n        if (f instanceof FragmentLifecycleable) {\n            obtainSubject(f).onNext(FragmentEvent.DETACH);\n        }\n    }\n\n    private Subject<FragmentEvent> obtainSubject(Fragment fragment) {\n        return ((FragmentLifecycleable) fragment).provideLifecycleSubject();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/lifecycle/FragmentLifecycleable.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.lifecycle;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.trello.rxlifecycle2.RxLifecycle;\nimport com.trello.rxlifecycle2.android.FragmentEvent;\n\n/**\n * ================================================\n * 让 {@link Fragment} 实现此接口,即可正常使用 {@link RxLifecycle}\n * <p>\n * Created by JessYan on 26/08/2017 17:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface FragmentLifecycleable extends Lifecycleable<FragmentEvent> {\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/integration/lifecycle/Lifecycleable.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.integration.lifecycle;\n\nimport android.app.Activity;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\n\nimport com.jess.arms.utils.RxLifecycleUtils;\nimport com.trello.rxlifecycle2.RxLifecycle;\n\nimport io.reactivex.subjects.Subject;\n\n/**\n * ================================================\n * 让 {@link Activity}/{@link Fragment} 实现此接口,即可正常使用 {@link RxLifecycle}\n * 无需再继承 {@link RxLifecycle} 提供的 Activity/Fragment ,扩展性极强\n *\n * @see RxLifecycleUtils 详细用法请查看此类\n * Created by JessYan on 25/08/2017 18:39\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface Lifecycleable<E> {\n    @NonNull\n    Subject<E> provideLifecycleSubject();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/mvp/BaseModel.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.mvp;\n\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.LifecycleObserver;\nimport androidx.lifecycle.LifecycleOwner;\nimport androidx.lifecycle.OnLifecycleEvent;\n\nimport com.jess.arms.integration.IRepositoryManager;\n\n/**\n * ================================================\n * 基类 Model\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.3\">Model wiki 官方文档</a>\n * Created by JessYan on 08/05/2016 12:55\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class BaseModel implements IModel, LifecycleObserver {\n    protected IRepositoryManager mRepositoryManager;//用于管理网络请求层, 以及数据缓存层\n\n    public BaseModel(IRepositoryManager repositoryManager) {\n        this.mRepositoryManager = repositoryManager;\n    }\n\n    /**\n     * 在框架中 {@link BasePresenter#onDestroy()} 时会默认调用 {@link IModel#onDestroy()}\n     */\n    @Override\n    public void onDestroy() {\n        mRepositoryManager = null;\n    }\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)\n    void onDestroy(LifecycleOwner owner) {\n        owner.getLifecycle().removeObserver(this);\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/mvp/BasePresenter.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.mvp;\n\nimport android.app.Activity;\nimport android.app.Service;\nimport android.view.View;\n\nimport androidx.core.app.ComponentActivity;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.LifecycleObserver;\nimport androidx.lifecycle.LifecycleOwner;\nimport androidx.lifecycle.OnLifecycleEvent;\n\nimport com.jess.arms.integration.EventBusManager;\nimport com.jess.arms.utils.Preconditions;\nimport com.trello.rxlifecycle2.RxLifecycle;\n\nimport io.reactivex.disposables.CompositeDisposable;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Action;\n\n/**\n * ================================================\n * 基类 Presenter\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.4\">Presenter wiki 官方文档</a>\n * Created by JessYan on 4/28/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class BasePresenter<M extends IModel, V extends IView> implements IPresenter, LifecycleObserver {\n    protected final String TAG = this.getClass().getSimpleName();\n    protected CompositeDisposable mCompositeDisposable;\n    protected M mModel;\n    protected V mRootView;\n\n    /**\n     * 如果当前页面同时需要 Model 层和 View 层,则使用此构造函数(默认)\n     *\n     * @param model\n     * @param rootView\n     */\n    public BasePresenter(M model, V rootView) {\n        Preconditions.checkNotNull(model, \"%s cannot be null\", IModel.class.getName());\n        Preconditions.checkNotNull(rootView, \"%s cannot be null\", IView.class.getName());\n        this.mModel = model;\n        this.mRootView = rootView;\n        onStart();\n    }\n\n    /**\n     * 如果当前页面不需要操作数据,只需要 View 层,则使用此构造函数\n     *\n     * @param rootView\n     */\n    public BasePresenter(V rootView) {\n        Preconditions.checkNotNull(rootView, \"%s cannot be null\", IView.class.getName());\n        this.mRootView = rootView;\n        onStart();\n    }\n\n    public BasePresenter() {\n        onStart();\n    }\n\n    @Override\n    public void onStart() {\n        //将 LifecycleObserver 注册给 LifecycleOwner 后 @OnLifecycleEvent 才可以正常使用\n        if (mRootView != null && mRootView instanceof LifecycleOwner) {\n            ((LifecycleOwner) mRootView).getLifecycle().addObserver(this);\n            if (mModel != null && mModel instanceof LifecycleObserver) {\n                ((LifecycleOwner) mRootView).getLifecycle().addObserver((LifecycleObserver) mModel);\n            }\n        }\n        if (useEventBus())//如果要使用 EventBus 请将此方法返回 true\n        {\n            EventBusManager.getInstance().register(this);//注册 EventBus\n        }\n    }\n\n    /**\n     * 在框架中 {@link Activity#onDestroy()} 时会默认调用 {@link IPresenter#onDestroy()}\n     */\n    @Override\n    public void onDestroy() {\n        if (useEventBus())//如果要使用 EventBus 请将此方法返回 true\n        {\n            EventBusManager.getInstance().unregister(this);//注销 EventBus\n        }\n        unDispose();//解除订阅\n        if (mModel != null) {\n            mModel.onDestroy();\n        }\n        this.mModel = null;\n        this.mRootView = null;\n        this.mCompositeDisposable = null;\n    }\n\n    /**\n     * 只有当 {@code mRootView} 不为 null, 并且 {@code mRootView} 实现了 {@link LifecycleOwner} 时, 此方法才会被调用\n     * 所以当您想在 {@link Service} 以及一些自定义 {@link View} 或自定义类中使用 {@code Presenter} 时\n     * 您也将不能继续使用 {@link OnLifecycleEvent} 绑定生命周期\n     *\n     * @param owner link {@link ComponentActivity} and {@link Fragment}\n     */\n    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)\n    void onDestroy(LifecycleOwner owner) {\n        /**\n         * 注意, 如果在这里调用了 {@link #onDestroy()} 方法, 会出现某些地方引用 {@code mModel} 或 {@code mRootView} 为 null 的情况\n         * 比如在 {@link RxLifecycle} 终止 {@link Observable} 时, 在 {@link io.reactivex.Observable#doFinally(Action)} 中却引用了 {@code mRootView} 做一些释放资源的操作, 此时会空指针\n         * 或者如果你声明了多个 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 时在其他 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)\n         * 中引用了 {@code mModel} 或 {@code mRootView} 也可能会出现此情况\n         */\n        owner.getLifecycle().removeObserver(this);\n    }\n\n    /**\n     * 是否使用 EventBus\n     * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n     * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n     * 确保依赖后, 将此方法返回 true, Arms 会自动检测您依赖的 EventBus, 并自动注册\n     * 这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\n     *\n     * @return 返回 {@code true} (默认为使用 {@code true}), Arms 会自动注册 EventBus\n     */\n    public boolean useEventBus() {\n        return true;\n    }\n\n    /**\n     * 将 {@link Disposable} 添加到 {@link CompositeDisposable} 中统一管理\n     * 可在 {@link Activity#onDestroy()} 中使用 {@link #unDispose()} 停止正在执行的 RxJava 任务,避免内存泄漏\n     * 目前框架已使用 {@link RxLifecycle} 避免内存泄漏,此方法作为备用方案\n     *\n     * @param disposable\n     */\n    public void addDispose(Disposable disposable) {\n        if (mCompositeDisposable == null) {\n            mCompositeDisposable = new CompositeDisposable();\n        }\n        mCompositeDisposable.add(disposable);//将所有 Disposable 放入容器集中处理\n    }\n\n    /**\n     * 停止集合中正在执行的 RxJava 任务\n     */\n    public void unDispose() {\n        if (mCompositeDisposable != null) {\n            mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅\n        }\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/mvp/IModel.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.mvp;\n\n/**\n * ================================================\n * 框架要求框架中的每个 Model 都需要实现此类,以满足规范\n *\n * @see BaseModel\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.3\">Model wiki 官方文档</a>\n * Created by JessYan on 15/12/2016 10:45\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IModel {\n\n    /**\n     * 在框架中 {@link BasePresenter#onDestroy()} 时会默认调用 {@link IModel#onDestroy()}\n     */\n    void onDestroy();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/mvp/IPresenter.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.mvp;\n\nimport android.app.Activity;\n\n/**\n * ================================================\n * 框架要求框架中的每个 Presenter 都需要实现此类,以满足规范\n *\n * @see BasePresenter\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.4\">Presenter wiki 官方文档</a>\n * Created by JessYan on 4/28/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IPresenter {\n\n    /**\n     * 做一些初始化操作\n     */\n    void onStart();\n\n    /**\n     * 在框架中 {@link Activity#onDestroy()} 时会默认调用 {@link IPresenter#onDestroy()}\n     */\n    void onDestroy();\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/mvp/IView.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.mvp;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\n\nimport com.jess.arms.utils.ArmsUtils;\n\nimport static com.jess.arms.utils.Preconditions.checkNotNull;\n\n/**\n * ================================================\n * 框架要求框架中的每个 View 都需要实现此类, 以满足规范\n * <p>\n * 为了满足部分人的诉求以及向下兼容, {@link IView} 中的部分方法使用 JAVA 1.8 的默认方法实现, 这样实现类可以按实际需求选择是否实现某些方法\n * 不实现则使用默认方法中的逻辑, 不清楚默认方法的请自行学习\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.2\">View wiki 官方文档</a>\n * Created by JessYan on 4/22/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface IView {\n\n    /**\n     * 显示加载\n     */\n    default void showLoading() {\n\n    }\n\n    /**\n     * 隐藏加载\n     */\n    default void hideLoading() {\n\n    }\n\n    /**\n     * 显示信息\n     *\n     * @param message 消息内容, 不能为 {@code null}\n     */\n    void showMessage(@NonNull String message);\n\n    /**\n     * 跳转 {@link Activity}\n     *\n     * @param intent {@code intent} 不能为 {@code null}\n     */\n    default void launchActivity(@NonNull Intent intent) {\n        checkNotNull(intent);\n        ArmsUtils.startActivity(intent);\n    }\n\n    /**\n     * 杀死自己\n     */\n    default void killMyself() {\n\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/ArmsUtils.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.annotation.SuppressLint;\r\nimport android.app.Activity;\r\nimport android.content.Context;\r\nimport android.content.Intent;\r\nimport android.content.res.Resources;\r\nimport android.graphics.drawable.Drawable;\r\nimport android.os.Build;\r\nimport android.text.SpannableString;\r\nimport android.text.Spanned;\r\nimport android.text.SpannedString;\r\nimport android.text.style.AbsoluteSizeSpan;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\nimport android.view.ViewParent;\r\nimport android.view.WindowManager;\r\nimport android.widget.TextView;\r\nimport android.widget.Toast;\r\n\r\nimport com.google.android.material.snackbar.Snackbar;\r\nimport com.jess.arms.base.App;\r\nimport com.jess.arms.di.component.AppComponent;\r\nimport com.jess.arms.integration.AppManager;\r\n\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.security.MessageDigest;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.recyclerview.widget.DefaultItemAnimator;\r\nimport androidx.recyclerview.widget.RecyclerView;\r\n\r\n/**\r\n * ================================================\r\n * 一些框架常用的工具\r\n * <p>\r\n * Created by JessYan on 2015/11/23.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class ArmsUtils {\r\n    static public Toast mToast;\r\n\r\n    private ArmsUtils() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    /**\r\n     * 设置hint大小\r\n     *\r\n     * @param size\r\n     * @param v\r\n     * @param res\r\n     */\r\n    public static void setViewHintSize(Context context, int size, TextView v, int res) {\r\n        SpannableString ss = new SpannableString(getResources(context).getString(\r\n                res));\r\n        // 新建一个属性对象,设置文字的大小\r\n        AbsoluteSizeSpan ass = new AbsoluteSizeSpan(size, true);\r\n        // 附加属性到文本  \r\n        ss.setSpan(ass, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\r\n\r\n        // 设置hint  \r\n        v.setHint(new SpannedString(ss)); // 一定要进行转换,否则属性会消失\r\n    }\r\n\r\n    /**\r\n     * dp 转 px\r\n     *\r\n     * @param context {@link Context}\r\n     * @param dpValue {@code dpValue}\r\n     * @return {@code pxValue}\r\n     */\r\n    public static int dip2px(@NonNull Context context, float dpValue) {\r\n        final float scale = getResources(context).getDisplayMetrics().density;\r\n        return (int) (dpValue * scale + 0.5f);\r\n    }\r\n\r\n    /**\r\n     * px 转 dp\r\n     *\r\n     * @param context {@link Context}\r\n     * @param pxValue {@code pxValue}\r\n     * @return {@code dpValue}\r\n     */\r\n    public static int pix2dip(@NonNull Context context, int pxValue) {\r\n        final float scale = getResources(context).getDisplayMetrics().density;\r\n        return (int) (pxValue / scale + 0.5f);\r\n    }\r\n\r\n    /**\r\n     * sp 转 px\r\n     *\r\n     * @param context {@link Context}\r\n     * @param spValue {@code spValue}\r\n     * @return {@code pxValue}\r\n     */\r\n    public static int sp2px(@NonNull Context context, float spValue) {\r\n        final float fontScale = getResources(context).getDisplayMetrics().scaledDensity;\r\n        return (int) (spValue * fontScale + 0.5f);\r\n    }\r\n\r\n    /**\r\n     * px 转 sp\r\n     *\r\n     * @param context {@link Context}\r\n     * @param pxValue {@code pxValue}\r\n     * @return {@code spValue}\r\n     */\r\n    public static int px2sp(@NonNull Context context, float pxValue) {\r\n        final float fontScale = getResources(context).getDisplayMetrics().scaledDensity;\r\n        return (int) (pxValue / fontScale + 0.5f);\r\n    }\r\n\r\n    /**\r\n     * 获得资源\r\n     */\r\n    public static Resources getResources(Context context) {\r\n        return context.getResources();\r\n    }\r\n\r\n    /**\r\n     * 得到字符数组\r\n     */\r\n    public static String[] getStringArray(Context context, int id) {\r\n        return getResources(context).getStringArray(id);\r\n    }\r\n\r\n    /**\r\n     * 从 dimens 中获得尺寸\r\n     *\r\n     * @param context\r\n     * @param id\r\n     * @return\r\n     */\r\n    public static int getDimens(Context context, int id) {\r\n        return (int) getResources(context).getDimension(id);\r\n    }\r\n\r\n    /**\r\n     * 从 dimens 中获得尺寸\r\n     *\r\n     * @param context\r\n     * @param dimenName\r\n     * @return\r\n     */\r\n    public static float getDimens(Context context, String dimenName) {\r\n        return getResources(context).getDimension(getResources(context).getIdentifier(dimenName, \"dimen\", context.getPackageName()));\r\n    }\r\n\r\n    /**\r\n     * 从String 中获得字符\r\n     *\r\n     * @return\r\n     */\r\n\r\n    public static String getString(Context context, int stringID) {\r\n        return getResources(context).getString(stringID);\r\n    }\r\n\r\n    /**\r\n     * 从String 中获得字符\r\n     *\r\n     * @return\r\n     */\r\n    public static String getString(Context context, String strName) {\r\n        return getString(context, getResources(context).getIdentifier(strName, \"string\", context.getPackageName()));\r\n    }\r\n\r\n    /**\r\n     * findview\r\n     *\r\n     * @param view\r\n     * @param viewName\r\n     * @param <T>\r\n     * @return\r\n     */\r\n    public static <T extends View> T findViewByName(Context context, View view, String viewName) {\r\n        int id = getResources(context).getIdentifier(viewName, \"id\", context.getPackageName());\r\n        return view.findViewById(id);\r\n    }\r\n\r\n    /**\r\n     * findview\r\n     *\r\n     * @param activity\r\n     * @param viewName\r\n     * @param <T>\r\n     * @return\r\n     */\r\n    public static <T extends View> T findViewByName(Context context, Activity activity, String viewName) {\r\n        int id = getResources(context).getIdentifier(viewName, \"id\", context.getPackageName());\r\n        return activity.findViewById(id);\r\n    }\r\n\r\n    /**\r\n     * 根据 layout 名字获得 id\r\n     *\r\n     * @param layoutName\r\n     * @return\r\n     */\r\n    public static int findLayout(Context context, String layoutName) {\r\n        return getResources(context).getIdentifier(layoutName, \"layout\", context.getPackageName());\r\n    }\r\n\r\n    /**\r\n     * 填充view\r\n     *\r\n     * @param detailScreen\r\n     * @return\r\n     */\r\n    public static View inflate(Context context, int detailScreen) {\r\n        return View.inflate(context, detailScreen, null);\r\n    }\r\n\r\n    /**\r\n     * 单例 toast\r\n     *\r\n     * @param string\r\n     */\r\n    @SuppressLint(\"ShowToast\")\r\n    public static void makeText(Context context, String string) {\r\n        if (mToast == null) {\r\n            mToast = Toast.makeText(context, string, Toast.LENGTH_SHORT);\r\n        }\r\n        mToast.setText(string);\r\n        mToast.show();\r\n    }\r\n\r\n    /**\r\n     * 使用 {@link Snackbar} 显示文本消息\r\n     * Arms 已将 com.google.android.material:material 从依赖中移除 (目的是减小 Arms 体积, design 库中含有太多 View)\r\n     * 因为 Snackbar 在 com.google.android.material:material 库中, 所以如果框架使用者没有自行依赖 com.google.android.material:material\r\n     * Arms 则会使用 Toast 替代 Snackbar 显示信息, 如果框架使用者依赖了 arms-autolayout 库就不用依赖 com.google.android.material:material 了\r\n     * 因为在 arms-autolayout 库中已经依赖有 com.google.android.material:material\r\n     *\r\n     * @param text\r\n     */\r\n    public static void snackbarText(String text) {\r\n        AppManager.getAppManager().showSnackbar(text, false);\r\n    }\r\n\r\n    /**\r\n     * 使用 {@link Snackbar} 长时间显示文本消息\r\n     * Arms 已将 com.google.android.material:material 从依赖中移除 (目的是减小 Arms 体积, design 库中含有太多 View)\r\n     * 因为 Snackbar 在 com.google.android.material:material 库中, 所以如果框架使用者没有自行依赖 com.google.android.material:material\r\n     * Arms 则会使用 Toast 替代 Snackbar 显示信息, 如果框架使用者依赖了 arms-autolayout 库就不用依赖 com.google.android.material:material 了\r\n     * 因为在 arms-autolayout 库中已经依赖有 com.google.android.material:material\r\n     *\r\n     * @param text\r\n     */\r\n    public static void snackbarTextWithLong(String text) {\r\n        AppManager.getAppManager().showSnackbar(text, true);\r\n    }\r\n\r\n    /**\r\n     * 通过资源id获得drawable\r\n     *\r\n     * @param rID\r\n     * @return\r\n     */\r\n    public static Drawable getDrawablebyResource(Context context, int rID) {\r\n        return getResources(context).getDrawable(rID);\r\n    }\r\n\r\n    /**\r\n     * 跳转界面 1, 通过 {@link AppManager#startActivity(Class)}\r\n     *\r\n     * @param activityClass\r\n     */\r\n    public static void startActivity(Class activityClass) {\r\n        AppManager.getAppManager().startActivity(activityClass);\r\n    }\r\n\r\n    /**\r\n     * 跳转界面 2, 通过 {@link AppManager#startActivity(Intent)}\r\n     *\r\n     * @param\r\n     */\r\n    public static void startActivity(Intent content) {\r\n        AppManager.getAppManager().startActivity(content);\r\n    }\r\n\r\n    /**\r\n     * 跳转界面 3\r\n     *\r\n     * @param activity\r\n     * @param homeActivityClass\r\n     */\r\n    public static void startActivity(Activity activity, Class homeActivityClass) {\r\n        Intent intent = new Intent(activity.getApplicationContext(), homeActivityClass);\r\n        activity.startActivity(intent);\r\n    }\r\n\r\n    /**\r\n     * 跳转界面 4\r\n     *\r\n     * @param\r\n     */\r\n    public static void startActivity(Activity activity, Intent intent) {\r\n        activity.startActivity(intent);\r\n    }\r\n\r\n    /**\r\n     * 获得屏幕的宽度\r\n     *\r\n     * @return\r\n     */\r\n    public static int getScreenWidth(Context context) {\r\n        return getResources(context).getDisplayMetrics().widthPixels;\r\n    }\r\n\r\n    /**\r\n     * 获得屏幕的高度\r\n     *\r\n     * @return\r\n     */\r\n    public static int getScreenHeidth(Context context) {\r\n        return getResources(context).getDisplayMetrics().heightPixels;\r\n    }\r\n\r\n    /**\r\n     * 获得颜色\r\n     */\r\n    public static int getColor(Context context, int rid) {\r\n        return getResources(context).getColor(rid);\r\n    }\r\n\r\n    /**\r\n     * 获得颜色\r\n     */\r\n    public static int getColor(Context context, String colorName) {\r\n        return getColor(context, getResources(context).getIdentifier(colorName, \"color\", context.getPackageName()));\r\n    }\r\n\r\n    /**\r\n     * 移除孩子\r\n     *\r\n     * @param view\r\n     */\r\n    public static void removeChild(View view) {\r\n        ViewParent parent = view.getParent();\r\n        if (parent instanceof ViewGroup) {\r\n            ViewGroup group = (ViewGroup) parent;\r\n            group.removeView(view);\r\n        }\r\n    }\r\n\r\n    public static boolean isEmpty(Object obj) {\r\n        return obj == null;\r\n    }\r\n\r\n    /**\r\n     * MD5\r\n     *\r\n     * @param string\r\n     * @return\r\n     * @throws Exception\r\n     */\r\n    public static String encodeToMD5(String string) {\r\n        byte[] hash = new byte[0];\r\n        try {\r\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\r\n                hash = MessageDigest.getInstance(\"MD5\").digest(\r\n                        string.getBytes(StandardCharsets.UTF_8));\r\n            } else {\r\n                hash = MessageDigest.getInstance(\"MD5\").digest(\r\n                        string.getBytes(\"UTF-8\"));\r\n            }\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        }\r\n        StringBuilder hex = new StringBuilder(hash.length * 2);\r\n        for (byte b : hash) {\r\n            if ((b & 0xFF) < 0x10) {\r\n                hex.append(\"0\");\r\n            }\r\n            hex.append(Integer.toHexString(b & 0xFF));\r\n        }\r\n        return hex.toString();\r\n    }\r\n\r\n    /**\r\n     * 全屏,并且沉侵式状态栏\r\n     *\r\n     * @param activity\r\n     */\r\n    public static void statuInScreen(Activity activity) {\r\n        WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();\r\n        attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;\r\n        activity.getWindow().setAttributes(attrs);\r\n        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);\r\n        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);\r\n    }\r\n\r\n    /**\r\n     * 配置 RecyclerView\r\n     *\r\n     * @param recyclerView\r\n     * @param layoutManager\r\n     * @deprecated Use {@link #configRecyclerView(RecyclerView, RecyclerView.LayoutManager)} instead\r\n     */\r\n    @Deprecated\r\n    public static void configRecycleView(final RecyclerView recyclerView\r\n            , RecyclerView.LayoutManager layoutManager) {\r\n        recyclerView.setLayoutManager(layoutManager);\r\n        //如果可以确定每个item的高度是固定的，设置这个选项可以提高性能\r\n        recyclerView.setHasFixedSize(true);\r\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\r\n    }\r\n\r\n    /**\r\n     * 配置 RecyclerView\r\n     *\r\n     * @param recyclerView\r\n     * @param layoutManager\r\n     */\r\n    public static void configRecyclerView(final RecyclerView recyclerView\r\n            , RecyclerView.LayoutManager layoutManager) {\r\n        recyclerView.setLayoutManager(layoutManager);\r\n        //如果可以确定每个item的高度是固定的，设置这个选项可以提高性能\r\n        recyclerView.setHasFixedSize(true);\r\n        recyclerView.setItemAnimator(new DefaultItemAnimator());\r\n    }\r\n\r\n    /**\r\n     * 执行 {@link AppManager#killAll()}\r\n     */\r\n    public static void killAll() {\r\n        AppManager.getAppManager().killAll();\r\n    }\r\n\r\n    /**\r\n     * 执行 {@link AppManager#appExit()}\r\n     */\r\n    public static void exitApp() {\r\n        AppManager.getAppManager().appExit();\r\n    }\r\n\r\n    public static AppComponent obtainAppComponentFromContext(Context context) {\r\n        Preconditions.checkNotNull(context, \"%s cannot be null\", Context.class.getName());\r\n        Preconditions.checkState(context.getApplicationContext() instanceof App, \"%s must be implements %s\", context.getApplicationContext().getClass().getName(), App.class.getName());\r\n        return ((App) context.getApplicationContext()).getAppComponent();\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/CharacterHandler.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.text.InputFilter;\r\nimport android.text.Spanned;\r\nimport android.text.TextUtils;\r\n\r\nimport org.json.JSONArray;\r\nimport org.json.JSONException;\r\nimport org.json.JSONObject;\r\n\r\nimport java.io.StringReader;\r\nimport java.io.StringWriter;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\nimport javax.xml.transform.OutputKeys;\r\nimport javax.xml.transform.Source;\r\nimport javax.xml.transform.Transformer;\r\nimport javax.xml.transform.TransformerException;\r\nimport javax.xml.transform.TransformerFactory;\r\nimport javax.xml.transform.stream.StreamResult;\r\nimport javax.xml.transform.stream.StreamSource;\r\n\r\n/**\r\n * ================================================\r\n * 处理字符串的工具类\r\n * <p>\r\n * Created by JessYan on 2016/3/16\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class CharacterHandler {\r\n\r\n    public static final InputFilter EMOJI_FILTER = new InputFilter() {//emoji过滤器\r\n        Pattern emoji = Pattern.compile(\r\n                \"[\\ud83c\\udc00-\\ud83c\\udfff]|[\\ud83d\\udc00-\\ud83d\\udfff]|[\\u2600-\\u27ff]\",\r\n                Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);\r\n\r\n        @Override\r\n        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,\r\n                                   int dend) {\r\n\r\n            Matcher emojiMatcher = emoji.matcher(source);\r\n            if (emojiMatcher.find()) {\r\n                return \"\";\r\n            }\r\n\r\n            return null;\r\n        }\r\n    };\r\n\r\n    private CharacterHandler() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    /**\r\n     * 字符串转换成十六进制字符串\r\n     *\r\n     * @return String 每个Byte之间空格分隔，如: [61 6C 6B]\r\n     */\r\n    public static String str2HexStr(String str) {\r\n\r\n        char[] chars = \"0123456789ABCDEF\".toCharArray();\r\n        StringBuilder sb = new StringBuilder();\r\n        byte[] bs = str.getBytes();\r\n        int bit;\r\n\r\n        for (byte b : bs) {\r\n            bit = (b & 0x0f0) >> 4;\r\n            sb.append(chars[bit]);\r\n            bit = b & 0x0f;\r\n            sb.append(chars[bit]);\r\n        }\r\n        return sb.toString().trim();\r\n    }\r\n\r\n    /**\r\n     * json 格式化\r\n     *\r\n     * @param json\r\n     * @return\r\n     */\r\n    public static String jsonFormat(String json) {\r\n        if (TextUtils.isEmpty(json)) {\r\n            return \"Empty/Null json content\";\r\n        }\r\n        String message;\r\n        try {\r\n            json = json.trim();\r\n            if (json.startsWith(\"{\")) {\r\n                JSONObject jsonObject = new JSONObject(json);\r\n                message = jsonObject.toString(4);\r\n            } else if (json.startsWith(\"[\")) {\r\n                JSONArray jsonArray = new JSONArray(json);\r\n                message = jsonArray.toString(4);\r\n            } else {\r\n                message = json;\r\n            }\r\n        } catch (JSONException e) {\r\n            message = json;\r\n        } catch (OutOfMemoryError error) {\r\n            message = \"Output omitted because of Object size\";\r\n        }\r\n        return message;\r\n    }\r\n\r\n    /**\r\n     * xml 格式化\r\n     *\r\n     * @param xml\r\n     * @return\r\n     */\r\n    public static String xmlFormat(String xml) {\r\n        if (TextUtils.isEmpty(xml)) {\r\n            return \"Empty/Null xml content\";\r\n        }\r\n        String message;\r\n        try {\r\n            Source xmlInput = new StreamSource(new StringReader(xml));\r\n            StreamResult xmlOutput = new StreamResult(new StringWriter());\r\n            Transformer transformer = TransformerFactory.newInstance().newTransformer();\r\n            transformer.setOutputProperty(OutputKeys.INDENT, \"yes\");\r\n            transformer.setOutputProperty(\"{http://xml.apache.org/xslt}indent-amount\", \"2\");\r\n            transformer.transform(xmlInput, xmlOutput);\r\n            message = xmlOutput.getWriter().toString().replaceFirst(\">\", \">\\n\");\r\n        } catch (TransformerException e) {\r\n            message = xml;\r\n        }\r\n        return message;\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/DataHelper.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.content.Context;\r\nimport android.content.SharedPreferences;\r\nimport android.os.Environment;\r\nimport android.util.Base64;\r\n\r\nimport java.io.ByteArrayInputStream;\r\nimport java.io.ByteArrayOutputStream;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.ObjectInputStream;\r\nimport java.io.ObjectOutputStream;\r\n\r\n/**\r\n * ================================================\r\n * 处理数据或本地文件的工具类\r\n * <p>\r\n * Created by JessYan on 2016/3/15\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class DataHelper {\r\n    public static final String SP_NAME = \"config\";\r\n    private static SharedPreferences mSharedPreferences;\r\n\r\n    private DataHelper() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    /**\r\n     * 存储重要信息到sharedPreferences；\r\n     *\r\n     * @param key\r\n     * @param value\r\n     */\r\n    public static void setStringSF(Context context, String key, String value) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        mSharedPreferences.edit().putString(key, value).apply();\r\n    }\r\n\r\n    /**\r\n     * 返回存在sharedPreferences的信息\r\n     *\r\n     * @param key\r\n     * @return\r\n     */\r\n    public static String getStringSF(Context context, String key) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        return mSharedPreferences.getString(key, null);\r\n    }\r\n\r\n    /**\r\n     * 存储重要信息到sharedPreferences；\r\n     *\r\n     * @param key\r\n     * @param value\r\n     */\r\n    public static void setIntergerSF(Context context, String key, int value) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        mSharedPreferences.edit().putInt(key, value).apply();\r\n    }\r\n\r\n    /**\r\n     * 返回存在sharedPreferences的信息\r\n     *\r\n     * @param key\r\n     * @return\r\n     */\r\n    public static int getIntergerSF(Context context, String key) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        return mSharedPreferences.getInt(key, -1);\r\n    }\r\n\r\n    /**\r\n     * 清除某个内容\r\n     */\r\n    public static void removeSF(Context context, String key) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        mSharedPreferences.edit().remove(key).apply();\r\n    }\r\n\r\n    /**\r\n     * 清除Shareprefrence\r\n     */\r\n    public static void clearShareprefrence(Context context) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        mSharedPreferences.edit().clear().apply();\r\n    }\r\n\r\n    /**\r\n     * 将对象储存到sharepreference\r\n     *\r\n     * @param key\r\n     * @param device\r\n     * @param <T>\r\n     */\r\n    public static <T> boolean saveDeviceData(Context context, String key, T device) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\r\n        try {   //Device为自定义类\r\n            // 创建对象输出流，并封装字节流\r\n            ObjectOutputStream oos = new ObjectOutputStream(baos);\r\n            // 将对象写入字节流\r\n            oos.writeObject(device);\r\n            // 将字节流编码成base64的字符串\r\n            String oAuthBase64 = new String(Base64.encode(baos\r\n                    .toByteArray(), Base64.DEFAULT));\r\n            mSharedPreferences.edit().putString(key, oAuthBase64).apply();\r\n            return true;\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 将对象从shareprerence中取出来\r\n     *\r\n     * @param key\r\n     * @param <T>\r\n     * @return\r\n     */\r\n    public static <T> T getDeviceData(Context context, String key) {\r\n        if (mSharedPreferences == null) {\r\n            mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);\r\n        }\r\n        T device = null;\r\n        String productBase64 = mSharedPreferences.getString(key, null);\r\n\r\n        if (productBase64 == null) {\r\n            return null;\r\n        }\r\n        // 读取字节\r\n        byte[] base64 = Base64.decode(productBase64.getBytes(), Base64.DEFAULT);\r\n\r\n        // 封装到字节流\r\n        ByteArrayInputStream bais = new ByteArrayInputStream(base64);\r\n        try {\r\n            // 再次封装\r\n            ObjectInputStream bis = new ObjectInputStream(bais);\r\n\r\n            // 读取对象\r\n            //noinspection unchecked\r\n            device = (T) bis.readObject();\r\n\r\n        } catch (Exception e) {\r\n            // TODO Auto-generated catch block\r\n            e.printStackTrace();\r\n        }\r\n        return device;\r\n    }\r\n\r\n    /**\r\n     * 返回缓存文件夹\r\n     */\r\n    public static File getCacheFile(Context context) {\r\n        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {\r\n            File file;\r\n            file = context.getExternalCacheDir();//获取系统管理的sd卡缓存文件\r\n            if (file == null) {//如果获取的文件为空,就使用自己定义的缓存文件夹做缓存路径\r\n                file = new File(getCacheFilePath(context));\r\n                makeDirs(file);\r\n            }\r\n            return file;\r\n        } else {\r\n            return context.getCacheDir();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取自定义缓存文件地址\r\n     *\r\n     * @param context\r\n     * @return\r\n     */\r\n    public static String getCacheFilePath(Context context) {\r\n        String packageName = context.getPackageName();\r\n        return Environment.getExternalStorageDirectory().getPath() + packageName;\r\n    }\r\n\r\n    /**\r\n     * 创建未存在的文件夹\r\n     *\r\n     * @param file\r\n     * @return\r\n     */\r\n    public static File makeDirs(File file) {\r\n        if (!file.exists()) {\r\n            file.mkdirs();\r\n        }\r\n        return file;\r\n    }\r\n\r\n    /**\r\n     * 使用递归获取目录文件大小\r\n     *\r\n     * @param dir\r\n     * @return\r\n     */\r\n    public static long getDirSize(File dir) {\r\n        if (dir == null) {\r\n            return 0;\r\n        }\r\n        if (!dir.isDirectory()) {\r\n            return 0;\r\n        }\r\n        long dirSize = 0;\r\n        File[] files = dir.listFiles();\r\n        for (File file : files) {\r\n            if (file.isFile()) {\r\n                dirSize += file.length();\r\n            } else if (file.isDirectory()) {\r\n                dirSize += file.length();\r\n                dirSize += getDirSize(file); // 递归调用继续统计\r\n            }\r\n        }\r\n        return dirSize;\r\n    }\r\n\r\n    /**\r\n     * 使用递归删除文件夹\r\n     *\r\n     * @param dir\r\n     * @return\r\n     */\r\n    public static boolean deleteDir(File dir) {\r\n        if (dir == null) {\r\n            return false;\r\n        }\r\n        if (!dir.isDirectory()) {\r\n            return false;\r\n        }\r\n        File[] files = dir.listFiles();\r\n        for (File file : files) {\r\n            if (file.isFile()) {\r\n                file.delete();\r\n            } else if (file.isDirectory()) {\r\n                deleteDir(file); // 递归调用继续删除\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n\r\n    public static String bytyToString(InputStream in) throws IOException {\r\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\r\n        byte[] buf = new byte[1024];\r\n        while (in.read(buf) != -1) {\r\n            out.write(buf, 0, buf.length);\r\n        }\r\n        String result = out.toString();\r\n        out.close();\r\n        return result;\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/DeviceUtils.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.ActivityNotFoundException;\nimport android.content.ClipboardManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.graphics.Point;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.PowerManager;\nimport android.telephony.TelephonyManager;\nimport android.text.TextUtils;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\nimport android.view.Display;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.WindowManager;\nimport android.view.inputmethod.InputMethodManager;\n\nimport java.io.File;\nimport java.lang.reflect.Field;\nimport java.text.NumberFormat;\nimport java.util.List;\n\n/**\n * ================================================\n * 获取设备常用信息和处理设备常用操作的工具类\n * <p>\n * Created by JessYan on 2016/3/15\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\npublic class DeviceUtils {\n    // 手机网络类型\n    public static final int NETTYPE_WIFI = 0x01;\n    public static final int NETTYPE_CMWAP = 0x02;\n    public static final int NETTYPE_CMNET = 0x03;\n    public static boolean GTE_HC;\n    public static boolean GTE_ICS;\n    public static boolean PRE_HC;\n    public static float displayDensity = 0.0F;\n    private static Boolean _hasBigScreen = null;\n    private static Boolean _hasCamera = null;\n    private static Boolean _isTablet = null;\n    private static Integer _loadFactor = null;\n\n    static {\n        GTE_ICS = Build.VERSION.SDK_INT >= 14;\n        GTE_HC = Build.VERSION.SDK_INT >= 11;\n        PRE_HC = Build.VERSION.SDK_INT < 11;\n    }\n\n    private DeviceUtils() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    /**\n     * dp转px\n     *\n     * @param context\n     * @param dp\n     * @return\n     */\n    public static float dpToPixel(Context context, float dp) {\n        return dp * (getDisplayMetrics(context).densityDpi / 160F);\n    }\n\n    /**\n     * px转dp\n     *\n     * @param context\n     * @param f\n     * @return\n     */\n    public static float pixelsToDp(Context context, float f) {\n        return f / (getDisplayMetrics(context).densityDpi / 160F);\n    }\n\n    public static int getDefaultLoadFactor(Context context) {\n        if (_loadFactor == null) {\n            Integer integer = 0xf & context\n                    .getResources().getConfiguration().screenLayout;\n            _loadFactor = integer;\n            _loadFactor = Math.max(integer, 1);\n        }\n        return _loadFactor;\n    }\n\n    public static float getDensity(Context context) {\n        if (displayDensity == 0.0) {\n            displayDensity = getDisplayMetrics(context).density;\n        }\n        return displayDensity;\n    }\n\n    public static DisplayMetrics getDisplayMetrics(Context context) {\n        DisplayMetrics displaymetrics = new DisplayMetrics();\n        ((WindowManager) context.getSystemService(\n                Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(\n                displaymetrics);\n        return displaymetrics;\n    }\n\n    /**\n     * 屏幕高度\n     *\n     * @param context\n     * @return\n     */\n    public static float getScreenHeight(Context context) {\n        return getDisplayMetrics(context).heightPixels;\n    }\n\n    /**\n     * 屏幕宽度\n     *\n     * @param context\n     * @return\n     */\n    public static float getScreenWidth(Context context) {\n        return getDisplayMetrics(context).widthPixels;\n    }\n\n    /**\n     * 获取activity尺寸\n     *\n     * @param activity\n     * @return\n     */\n    public static int[] getRealScreenSize(Activity activity) {\n        int[] size = new int[2];\n        int screenWidth, screenHeight;\n        WindowManager w = activity.getWindowManager();\n        Display d = w.getDefaultDisplay();\n        DisplayMetrics metrics = new DisplayMetrics();\n        d.getMetrics(metrics);\n        // since SDK_INT = 1;\n        screenWidth = metrics.widthPixels;\n        screenHeight = metrics.heightPixels;\n        // includes window decorations (statusbar bar/menu bar)\n        if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17) {\n            try {\n                screenWidth = (Integer) Display.class.getMethod(\"getRawWidth\")\n                        .invoke(d);\n                screenHeight = (Integer) Display.class\n                        .getMethod(\"getRawHeight\").invoke(d);\n            } catch (Exception ignored) {\n            }\n        }\n        // includes window decorations (statusbar bar/menu bar)\n        if (Build.VERSION.SDK_INT >= 17) {\n            try {\n                Point realSize = new Point();\n                Display.class.getMethod(\"getRealSize\", Point.class).invoke(d,\n                        realSize);\n                screenWidth = realSize.x;\n                screenHeight = realSize.y;\n            } catch (Exception ignored) {\n            }\n        }\n        size[0] = screenWidth;\n        size[1] = screenHeight;\n        return size;\n    }\n\n    /**\n     * 获取状态栏高度\n     *\n     * @param context\n     * @return\n     */\n    public static int getStatusBarHeight(Context context) {\n        Class<?> c;\n        Object obj;\n        Field field;\n        int x;\n        try {\n            c = Class.forName(\"com.android.internal.R$dimen\");\n            obj = c.newInstance();\n            field = c.getField(\"status_bar_height\");\n            x = Integer.parseInt(field.get(obj).toString());\n            return context.getResources()\n                    .getDimensionPixelSize(x);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return 0;\n    }\n\n    public static boolean hasBigScreen(Context context) {\n        boolean flag = true;\n        if (_hasBigScreen == null) {\n            boolean flag1;\n            if ((0xf & context.getResources()\n                    .getConfiguration().screenLayout) >= 3) {\n                flag1 = flag;\n            } else {\n                flag1 = false;\n            }\n            Boolean boolean1 = flag1;\n            _hasBigScreen = boolean1;\n            if (!boolean1) {\n                if (getDensity(context) <= 1.5F) {\n                    flag = false;\n                }\n                _hasBigScreen = flag;\n            }\n        }\n        return _hasBigScreen;\n    }\n\n    /**\n     * 设备是否有相机\n     *\n     * @param context\n     * @return\n     */\n    public static boolean hasCamera(Context context) {\n        if (_hasCamera == null) {\n            PackageManager pckMgr = context\n                    .getPackageManager();\n            boolean flag = pckMgr\n                    .hasSystemFeature(\"android.hardware.camera.front\");\n            boolean flag1 = pckMgr.hasSystemFeature(\"android.hardware.camera\");\n            boolean flag2;\n            flag2 = flag || flag1;\n            _hasCamera = flag2;\n        }\n        return _hasCamera;\n    }\n\n    /**\n     * 设备是否有实体菜单\n     *\n     * @param context\n     * @return\n     */\n    public static boolean hasHardwareMenuKey(Context context) {\n        boolean flag;\n        if (PRE_HC) {\n            flag = true;\n        } else if (GTE_ICS) {\n            flag = ViewConfiguration.get(context).hasPermanentMenuKey();\n        } else {\n            flag = false;\n        }\n        return flag;\n    }\n\n    /**\n     * 当前是否有网\n     *\n     * @param context\n     * @return\n     */\n    public static boolean hasInternet(Context context) {\n        boolean flag;\n        ConnectivityManager manager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        flag = manager != null && manager.getActiveNetworkInfo() != null;\n        return flag;\n    }\n\n    /**\n     * 当前的包是否存在\n     *\n     * @param context\n     * @param pckName\n     * @return\n     */\n    public static boolean isPackageExist(Context context, String pckName) {\n        try {\n            PackageInfo pckInfo = context.getPackageManager()\n                    .getPackageInfo(pckName, 0);\n            if (pckInfo != null) {\n                return true;\n            }\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.e(\"TDvice\", e.getMessage());\n        }\n        return false;\n    }\n\n    public static void hideAnimatedView(View view) {\n        if (PRE_HC && view != null) {\n            view.setPadding(view.getWidth(), 0, 0, 0);\n        }\n    }\n\n    /**\n     * 隐藏软键盘\n     *\n     * @param context\n     * @param view\n     */\n    public static void hideSoftKeyboard(Context context, View view) {\n        if (view == null) {\n            return;\n        }\n        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(\n                Context.INPUT_METHOD_SERVICE);\n        if (inputMethodManager.isActive()) {\n            inputMethodManager.hideSoftInputFromWindow(\n                    view.getWindowToken(), 0);\n        }\n    }\n\n    /**\n     * 是否是横屏\n     *\n     * @param context\n     * @return\n     */\n    public static boolean isLandscape(Context context) {\n        boolean flag;\n        flag = context.getResources().getConfiguration().orientation == 2;\n        return flag;\n    }\n\n    /**\n     * 是否是竖屏\n     *\n     * @param context\n     * @return\n     */\n    public static boolean isPortrait(Context context) {\n        boolean flag = true;\n        if (context.getResources().getConfiguration().orientation != 1) {\n            flag = false;\n        }\n        return flag;\n    }\n\n    public static boolean isTablet(Context context) {\n        if (_isTablet == null) {\n            boolean flag;\n            flag = (0xf & context.getResources()\n                    .getConfiguration().screenLayout) >= 3;\n            _isTablet = flag;\n        }\n        return _isTablet;\n    }\n\n    public static void showAnimatedView(View view) {\n        if (PRE_HC && view != null) {\n            view.setPadding(0, 0, 0, 0);\n        }\n    }\n\n    public static void showSoftKeyboard(Dialog dialog) {\n        dialog.getWindow().setSoftInputMode(4);\n    }\n\n    public static void showSoftKeyboard(Context context, View view) {\n        ((InputMethodManager) context.getSystemService(\n                Context.INPUT_METHOD_SERVICE)).showSoftInput(view,\n                InputMethodManager.SHOW_FORCED);\n    }\n\n    public static void toogleSoftKeyboard(Context context, View view) {\n        ((InputMethodManager) context.getSystemService(\n                Context.INPUT_METHOD_SERVICE)).toggleSoftInput(0,\n                InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    public static boolean isSdcardReady() {\n        return Environment.MEDIA_MOUNTED.equals(Environment\n                .getExternalStorageState());\n    }\n\n    public static String getCurCountryLan(Context context) {\n        return context.getResources().getConfiguration().locale\n                .getLanguage()\n                + \"-\"\n                + context.getResources().getConfiguration().locale\n                .getCountry();\n    }\n\n    public static boolean isZhCN(Context context) {\n        String lang = context.getResources()\n                .getConfiguration().locale.getCountry();\n        return \"CN\".equalsIgnoreCase(lang);\n    }\n\n    public static String percent(double p1, double p2) {\n        String str;\n        double p3 = p1 / p2;\n        NumberFormat nf = NumberFormat.getPercentInstance();\n        nf.setMinimumFractionDigits(2);\n        str = nf.format(p3);\n        return str;\n    }\n\n    public static String percent2(double p1, double p2) {\n        String str;\n        double p3 = p1 / p2;\n        NumberFormat nf = NumberFormat.getPercentInstance();\n        nf.setMinimumFractionDigits(0);\n        str = nf.format(p3);\n        return str;\n    }\n\n    public static boolean isHaveMarket(Context context) {\n        Intent intent = new Intent();\n        intent.setAction(\"android.intent.action.MAIN\");\n        intent.addCategory(\"android.intent.category.APP_MARKET\");\n        PackageManager pm = context.getPackageManager();\n        List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0);\n        return infos.size() > 0;\n    }\n\n    public static void setFullScreen(Activity activity) {\n        WindowManager.LayoutParams params = activity.getWindow()\n                .getAttributes();\n        params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;\n        activity.getWindow().setAttributes(params);\n        activity.getWindow().addFlags(\n                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);\n    }\n\n    public static void cancelFullScreen(Activity activity) {\n        WindowManager.LayoutParams params = activity.getWindow()\n                .getAttributes();\n        params.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);\n        activity.getWindow().setAttributes(params);\n        activity.getWindow().clearFlags(\n                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);\n    }\n\n    public static PackageInfo getPackageInfo(Context context, String pckName) {\n        try {\n            return context.getPackageManager()\n                    .getPackageInfo(pckName, 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 获取版本号\n     *\n     * @param context\n     * @return\n     */\n    public static int getVersionCode(Context context) {\n        int versionCode;\n        try {\n            versionCode = context.getPackageManager()\n                    .getPackageInfo(context.getPackageName(),\n                            0).versionCode;\n        } catch (PackageManager.NameNotFoundException ex) {\n            versionCode = 0;\n        }\n        return versionCode;\n    }\n\n    /**\n     * 获取指定包名应用的版本号\n     *\n     * @param context\n     * @param packageName\n     * @return\n     */\n    public static int getVersionCode(Context context, String packageName) {\n        int versionCode;\n        try {\n            versionCode = context.getPackageManager()\n                    .getPackageInfo(packageName, 0).versionCode;\n        } catch (PackageManager.NameNotFoundException ex) {\n            versionCode = 0;\n        }\n        return versionCode;\n    }\n\n    /**\n     * 获取版本名\n     *\n     * @param context\n     * @return\n     */\n    public static String getVersionName(Context context) {\n        String name;\n        try {\n            name = context.getPackageManager()\n                    .getPackageInfo(context.getPackageName(),\n                            0).versionName;\n        } catch (PackageManager.NameNotFoundException ex) {\n            name = \"\";\n        }\n        return name;\n    }\n\n    public static boolean isScreenOn(Context context) {\n        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);\n        return pm.isScreenOn();\n    }\n\n    /**\n     * 安装应用\n     *\n     * @param context\n     * @param file\n     */\n    public static void installAPK(Context context, File file) {\n        if (file == null || !file.exists()) {\n            return;\n        }\n        Intent intent = new Intent();\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.setAction(Intent.ACTION_VIEW);\n        intent.setDataAndType(Uri.fromFile(file),\n                \"application/vnd.android.package-archive\");\n        context.startActivity(intent);\n    }\n\n    public static Intent getInstallApkIntent(File file) {\n        Intent intent = new Intent();\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.setAction(Intent.ACTION_VIEW);\n        intent.setDataAndType(Uri.fromFile(file),\n                \"application/vnd.android.package-archive\");\n        return intent;\n    }\n\n    /**\n     * 拨打电话\n     *\n     * @param context\n     * @param number\n     */\n    public static void openDial(Context context, String number) {\n        Uri uri = Uri.parse(\"tel:\" + number);\n        Intent it = new Intent(Intent.ACTION_DIAL, uri);\n        context.startActivity(it);\n    }\n\n    public static void openSMS(Context context, String smsBody, String tel) {\n        Uri uri = Uri.parse(\"smsto:\" + tel);\n        Intent it = new Intent(Intent.ACTION_SENDTO, uri);\n        it.putExtra(\"sms_body\", smsBody);\n        context.startActivity(it);\n    }\n\n    public static void openDail(Context context) {\n        Intent intent = new Intent(Intent.ACTION_DIAL);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n    }\n\n    public static void openSendMsg(Context context) {\n        Uri uri = Uri.parse(\"smsto:\");\n        Intent intent = new Intent(Intent.ACTION_SENDTO, uri);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n    }\n\n    public static void openCamera(Context context) {\n        Intent intent = new Intent(); // 调用照相机\n        intent.setAction(\"android.media.action.STILL_IMAGE_CAMERA\");\n        intent.setFlags(0x34c40000);\n        context.startActivity(intent);\n    }\n\n    public static String getIMEI(Context context) {\n        TelephonyManager tel = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n        return tel.getDeviceId();\n    }\n\n    public static String getPhoneType() {\n        return Build.MODEL;\n    }\n\n    public static void openApp(Context context, String packageName) {\n        Intent mainIntent = context.getPackageManager()\n                .getLaunchIntentForPackage(packageName);\n        if (mainIntent == null) {\n            mainIntent = new Intent(packageName);\n        }\n        context.startActivity(mainIntent);\n    }\n\n    public static boolean openAppActivity(Context context, String packageName,\n                                          String activityName) {\n        Intent intent = new Intent(Intent.ACTION_MAIN);\n        intent.addCategory(Intent.CATEGORY_LAUNCHER);\n        ComponentName cn = new ComponentName(packageName, activityName);\n        intent.setComponent(cn);\n        try {\n            context.startActivity(intent);\n            return true;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    /**\n     * wifi是否开启\n     *\n     * @param context\n     * @return\n     */\n    public static boolean isWifiOpen(Context context) {\n        boolean isWifiConnect = false;\n        ConnectivityManager cm = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        // check the networkInfos numbers\n        NetworkInfo[] networkInfos = cm.getAllNetworkInfo();\n        for (NetworkInfo networkInfo : networkInfos) {\n            if (networkInfo.getState() == NetworkInfo.State.CONNECTED) {\n                if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {\n                    isWifiConnect = false;\n                }\n                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {\n                    isWifiConnect = true;\n                }\n            }\n        }\n        return isWifiConnect;\n    }\n\n    /**\n     * 卸载软件\n     *\n     * @param context\n     * @param packageName\n     */\n    public static void uninstallApk(Context context, String packageName) {\n        if (isPackageExist(context, packageName)) {\n            Uri packageURI = Uri.parse(\"package:\" + packageName);\n            Intent uninstallIntent = new Intent(Intent.ACTION_DELETE,\n                    packageURI);\n            context.startActivity(uninstallIntent);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void copyTextToBoard(Context context, String string) {\n        if (TextUtils.isEmpty(string)) {\n            return;\n        }\n        ClipboardManager clip = (ClipboardManager) context\n                .getSystemService(Context.CLIPBOARD_SERVICE);\n        clip.setText(string);\n    }\n\n    /**\n     * 发送邮件\n     *\n     * @param context\n     * @param subject 主题\n     * @param content 内容\n     * @param emails  邮件地址\n     */\n    public static void sendEmail(Context context, String subject,\n                                 String content, String... emails) {\n        try {\n            Intent intent = new Intent(Intent.ACTION_SEND);\n            // 模拟器\n            // intent.setType(\"text/plain\");\n            intent.setType(\"message/rfc822\"); // 真机\n            intent.putExtra(Intent.EXTRA_EMAIL, emails);\n            intent.putExtra(Intent.EXTRA_SUBJECT, subject);\n            intent.putExtra(Intent.EXTRA_TEXT, content);\n            context.startActivity(intent);\n        } catch (ActivityNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static int getStatuBarHeight(Context context) {\n        Class<?> c;\n        Object obj;\n        Field field;\n        int x, sbar = 38;// 默认为38，貌似大部分是这样的\n        try {\n            c = Class.forName(\"com.android.internal.R$dimen\");\n            obj = c.newInstance();\n            field = c.getField(\"status_bar_height\");\n            x = Integer.parseInt(field.get(obj).toString());\n            sbar = context.getResources()\n                    .getDimensionPixelSize(x);\n\n        } catch (Exception e1) {\n            e1.printStackTrace();\n        }\n        return sbar;\n    }\n\n    public static boolean hasStatusBar(Activity activity) {\n        WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();\n        return (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != WindowManager.LayoutParams.FLAG_FULLSCREEN;\n    }\n\n    /**\n     * 调用系统安装了的应用分享\n     *\n     * @param context\n     * @param title\n     * @param url\n     */\n    public static void showSystemShareOption(Activity context,\n                                             final String title, final String url) {\n        Intent intent = new Intent(Intent.ACTION_SEND);\n        intent.setType(\"text/plain\");\n        intent.putExtra(Intent.EXTRA_SUBJECT, \"分享：\" + title);\n        intent.putExtra(Intent.EXTRA_TEXT, title + \" \" + url);\n        context.startActivity(Intent.createChooser(intent, \"选择分享\"));\n    }\n\n    /**\n     * 获取当前网络类型\n     *\n     * @return 0：没有网络 1：WIFI网络 2：WAP网络 3：NET网络\n     */\n    public static int getNetworkType(Context context) {\n        int netType = 0;\n        ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();\n        if (networkInfo == null) {\n            return netType;\n        }\n        int nType = networkInfo.getType();\n        if (nType == ConnectivityManager.TYPE_MOBILE) {\n            String extraInfo = networkInfo.getExtraInfo();\n            if (extraInfo != null && !extraInfo.isEmpty()) {\n                if (\"cmnet\".equalsIgnoreCase(extraInfo)) {\n                    netType = NETTYPE_CMNET;\n                } else {\n                    netType = NETTYPE_CMWAP;\n                }\n            }\n        } else if (nType == ConnectivityManager.TYPE_WIFI) {\n            netType = NETTYPE_WIFI;\n        }\n        return netType;\n    }\n\n    public static boolean netIsConnected(Context context) {\n        ConnectivityManager connectMgr = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        //手机网络连接状态\n        NetworkInfo mobNetInfo = connectMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);\n        //WIFI连接状态\n        NetworkInfo wifiNetInfo = connectMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);\n        //当前无可用的网络\n        return mobNetInfo.isConnected() || wifiNetInfo.isConnected();\n    }\n\n    /**\n     * 判断是否存在sd卡\n     *\n     * @return\n     */\n    public static boolean isExitsSdcard() {\n        return Environment.getExternalStorageState().equals(\n                Environment.MEDIA_MOUNTED);\n    }\n}\n\n\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/DrawableProvider.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.graphics.Bitmap;\r\nimport android.graphics.Matrix;\r\nimport android.graphics.drawable.Drawable;\r\nimport android.graphics.drawable.StateListDrawable;\r\nimport android.widget.TextView;\r\n\r\nimport androidx.exifinterface.media.ExifInterface;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * ================================================\r\n * 处理 {@link Drawable} 和 {@link Bitmap} 的工具类\r\n * <p>\r\n * Created by JessYan on 2015/11/24\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class DrawableProvider {\r\n\r\n    private DrawableProvider() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    /**\r\n     * 获得选择器\r\n     *\r\n     * @param normalDrawable\r\n     * @param pressDrawable\r\n     * @return\r\n     */\r\n    public static Drawable getStateListDrawable(Drawable normalDrawable, Drawable pressDrawable) {\r\n        StateListDrawable stateListDrawable = new StateListDrawable();\r\n        stateListDrawable.addState(new int[]{android.R.attr.state_checked}, pressDrawable);\r\n        stateListDrawable.addState(new int[]{}, normalDrawable);\r\n        return stateListDrawable;\r\n    }\r\n\r\n    /**\r\n     * 将 TextView/RadioButton 中设置的 drawable 动态的缩放\r\n     *\r\n     * @param percent\r\n     * @param tv\r\n     * @return\r\n     */\r\n    public static Drawable getScaleDrawableForRadioButton(float percent, TextView tv) {\r\n        Drawable[] compoundDrawables = tv.getCompoundDrawables();\r\n        Drawable drawable = null;\r\n        for (Drawable d : compoundDrawables) {\r\n            if (d != null) {\r\n                drawable = d;\r\n            }\r\n        }\r\n        return getScaleDrawable(percent, drawable);\r\n    }\r\n\r\n    /**\r\n     * 将 TextView/RadioButton 中设置的 drawable 动态的缩放\r\n     *\r\n     * @param tv\r\n     * @return\r\n     */\r\n    public static Drawable getScaleDrawableForRadioButton2(float width, TextView tv) {\r\n        Drawable[] compoundDrawables = tv.getCompoundDrawables();\r\n        Drawable drawable = null;\r\n        for (Drawable d : compoundDrawables) {\r\n            if (d != null) {\r\n                drawable = d;\r\n            }\r\n        }\r\n        return getScaleDrawable2(width, drawable);\r\n    }\r\n\r\n    /**\r\n     * 传入图片,将图片按传入比例缩放\r\n     *\r\n     * @param percent\r\n     * @return\r\n     */\r\n    public static Drawable getScaleDrawable(float percent, Drawable drawable) {\r\n        drawable.setBounds(0, 0, (int) (drawable.getIntrinsicWidth() * percent + 0.5f), (int) (drawable.getIntrinsicHeight() * percent + 0.5f));\r\n        return drawable;\r\n    }\r\n\r\n    /**\r\n     * 传入图片,将图片按传入宽度和原始宽度的比例缩放\r\n     *\r\n     * @param width\r\n     * @return\r\n     */\r\n    public static Drawable getScaleDrawable2(float width, Drawable drawable) {\r\n        float percent = width * 1.0f / drawable.getIntrinsicWidth();\r\n        return getScaleDrawable(percent, drawable);\r\n    }\r\n\r\n    /**\r\n     * 设置左边的drawable\r\n     *\r\n     * @param tv\r\n     * @param drawable\r\n     */\r\n    public static void setLeftDrawable(TextView tv, Drawable drawable) {\r\n        tv.setCompoundDrawables(drawable, null, null, null);\r\n    }\r\n\r\n    /**\r\n     * 改变Bitmap的长宽\r\n     *\r\n     * @param bitmap\r\n     * @return\r\n     */\r\n    public static Bitmap getReSizeBitmap(Bitmap bitmap, float targetWidth, float targetheight) {\r\n        Bitmap returnBm = null;\r\n        int width = bitmap.getWidth();\r\n        int height = bitmap.getHeight();\r\n        Matrix matrix = new Matrix();\r\n        matrix.postScale(targetWidth / width, targetheight / height); //长和宽放大缩小的比例\r\n        try {\r\n            returnBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        }\r\n        if (returnBm == null) {\r\n            returnBm = bitmap;\r\n        }\r\n        if (bitmap != returnBm) {\r\n            bitmap.recycle();\r\n        }\r\n        return returnBm;\r\n    }\r\n\r\n    /**\r\n     * 将图片按照某个角度进行旋转\r\n     *\r\n     * @param bm     需要旋转的图片\r\n     * @param degree 旋转角度\r\n     * @return 旋转后的图片\r\n     */\r\n    public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {\r\n        Bitmap returnBm = null;\r\n\r\n        // 根据旋转角度，生成旋转矩阵\r\n        Matrix matrix = new Matrix();\r\n        matrix.postRotate(degree);\r\n        try {\r\n            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片\r\n            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);\r\n        } catch (OutOfMemoryError e) {\r\n            e.printStackTrace();\r\n        }\r\n        if (returnBm == null) {\r\n            returnBm = bm;\r\n        }\r\n        if (bm != returnBm) {\r\n            bm.recycle();\r\n        }\r\n        return returnBm;\r\n    }\r\n\r\n    /**\r\n     * 读取图片的旋转的角度\r\n     *\r\n     * @param path 图片绝对路径\r\n     * @return 图片的旋转角度\r\n     */\r\n    public static int getBitmapDegree(String path) {\r\n        int degree = 0;\r\n        try {\r\n            // 从指定路径下读取图片，并获取其EXIF信息\r\n            ExifInterface exifInterface = new ExifInterface(path);\r\n            // 获取图片的旋转信息\r\n            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,\r\n                    ExifInterface.ORIENTATION_NORMAL);\r\n            switch (orientation) {\r\n                case ExifInterface.ORIENTATION_ROTATE_90:\r\n                    degree = 90;\r\n                    break;\r\n                case ExifInterface.ORIENTATION_ROTATE_180:\r\n                    degree = 180;\r\n                    break;\r\n                case ExifInterface.ORIENTATION_ROTATE_270:\r\n                    degree = 270;\r\n                    break;\r\n                default:\r\n                    break;\r\n            }\r\n        } catch (IOException e) {\r\n            e.printStackTrace();\r\n        }\r\n        return degree;\r\n    }\r\n}"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/FastBlur.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.util.Log;\nimport android.view.View;\n\n/**\n * ================================================\n * 处理高斯模糊的工具类\n * <p>\n * Created by JessYan on 03/06/2014.\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class FastBlur {\n\n    private FastBlur() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {\n\n        // Stack Blur v1.0 from\n        // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html\n        //\n        // Java Author: Mario Klingemann <mario at quasimondo.com>\n        // http://incubator.quasimondo.com\n        // created Feburary 29, 2004\n        // Android port : Yahel Bouaziz <yahel at kayenko.com>\n        // http://www.kayenko.com\n        // ported april 5th, 2012\n\n        // This is a compromise between Gaussian Blur and Box blur\n        // It creates much better looking blurs than Box Blur, but is\n        // 7x faster than my Gaussian Blur implementation.\n        //\n        // I called it Stack Blur because this describes best how this\n        // filter works internally: it creates a kind of moving stack\n        // of colors whilst scanning through the image. Thereby it\n        // just has to add one new block of color to the right side\n        // of the stack and remove the leftmost color. The remaining\n        // colors on the topmost layer of the stack are either added on\n        // or reduced by one, depending on if they are on the right or\n        // on the left side of the stack.\n        //\n        // If you are using this algorithm in your code please add\n        // the following line:\n        //\n        // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>\n\n        Bitmap bitmap;\n        if (canReuseInBitmap) {\n            bitmap = sentBitmap;\n        } else {\n            bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);\n        }\n\n        if (radius < 1) {\n            return (null);\n        }\n\n        int w = bitmap.getWidth();\n        int h = bitmap.getHeight();\n\n        int[] pix = new int[w * h];\n        bitmap.getPixels(pix, 0, w, 0, 0, w, h);\n\n        int wm = w - 1;\n        int hm = h - 1;\n        int wh = w * h;\n        int div = radius + radius + 1;\n\n        int[] r = new int[wh];\n        int[] g = new int[wh];\n        int[] b = new int[wh];\n        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;\n        int[] vmin = new int[Math.max(w, h)];\n\n        int divsum = (div + 1) >> 1;\n        divsum *= divsum;\n        int[] dv = new int[256 * divsum];\n        for (i = 0; i < 256 * divsum; i++) {\n            dv[i] = (i / divsum);\n        }\n\n        yw = yi = 0;\n\n        int[][] stack = new int[div][3];\n        int stackpointer;\n        int stackstart;\n        int[] sir;\n        int rbs;\n        int r1 = radius + 1;\n        int routsum, goutsum, boutsum;\n        int rinsum, ginsum, binsum;\n\n        for (y = 0; y < h; y++) {\n            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;\n            for (i = -radius; i <= radius; i++) {\n                p = pix[yi + Math.min(wm, Math.max(i, 0))];\n                sir = stack[i + radius];\n                sir[0] = (p & 0xff0000) >> 16;\n                sir[1] = (p & 0x00ff00) >> 8;\n                sir[2] = (p & 0x0000ff);\n                rbs = r1 - Math.abs(i);\n                rsum += sir[0] * rbs;\n                gsum += sir[1] * rbs;\n                bsum += sir[2] * rbs;\n                if (i > 0) {\n                    rinsum += sir[0];\n                    ginsum += sir[1];\n                    binsum += sir[2];\n                } else {\n                    routsum += sir[0];\n                    goutsum += sir[1];\n                    boutsum += sir[2];\n                }\n            }\n            stackpointer = radius;\n\n            for (x = 0; x < w; x++) {\n\n                r[yi] = dv[rsum];\n                g[yi] = dv[gsum];\n                b[yi] = dv[bsum];\n\n                rsum -= routsum;\n                gsum -= goutsum;\n                bsum -= boutsum;\n\n                stackstart = stackpointer - radius + div;\n                sir = stack[stackstart % div];\n\n                routsum -= sir[0];\n                goutsum -= sir[1];\n                boutsum -= sir[2];\n\n                if (y == 0) {\n                    vmin[x] = Math.min(x + radius + 1, wm);\n                }\n                p = pix[yw + vmin[x]];\n\n                sir[0] = (p & 0xff0000) >> 16;\n                sir[1] = (p & 0x00ff00) >> 8;\n                sir[2] = (p & 0x0000ff);\n\n                rinsum += sir[0];\n                ginsum += sir[1];\n                binsum += sir[2];\n\n                rsum += rinsum;\n                gsum += ginsum;\n                bsum += binsum;\n\n                stackpointer = (stackpointer + 1) % div;\n                sir = stack[(stackpointer) % div];\n\n                routsum += sir[0];\n                goutsum += sir[1];\n                boutsum += sir[2];\n\n                rinsum -= sir[0];\n                ginsum -= sir[1];\n                binsum -= sir[2];\n\n                yi++;\n            }\n            yw += w;\n        }\n        for (x = 0; x < w; x++) {\n            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;\n            yp = -radius * w;\n            for (i = -radius; i <= radius; i++) {\n                yi = Math.max(0, yp) + x;\n\n                sir = stack[i + radius];\n\n                sir[0] = r[yi];\n                sir[1] = g[yi];\n                sir[2] = b[yi];\n\n                rbs = r1 - Math.abs(i);\n\n                rsum += r[yi] * rbs;\n                gsum += g[yi] * rbs;\n                bsum += b[yi] * rbs;\n\n                if (i > 0) {\n                    rinsum += sir[0];\n                    ginsum += sir[1];\n                    binsum += sir[2];\n                } else {\n                    routsum += sir[0];\n                    goutsum += sir[1];\n                    boutsum += sir[2];\n                }\n\n                if (i < hm) {\n                    yp += w;\n                }\n            }\n            yi = x;\n            stackpointer = radius;\n            for (y = 0; y < h; y++) {\n                // Preserve alpha channel: ( 0xff000000 & pix[yi] )\n                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];\n\n                rsum -= routsum;\n                gsum -= goutsum;\n                bsum -= boutsum;\n\n                stackstart = stackpointer - radius + div;\n                sir = stack[stackstart % div];\n\n                routsum -= sir[0];\n                goutsum -= sir[1];\n                boutsum -= sir[2];\n\n                if (x == 0) {\n                    vmin[y] = Math.min(y + r1, hm) * w;\n                }\n                p = x + vmin[y];\n\n                sir[0] = r[p];\n                sir[1] = g[p];\n                sir[2] = b[p];\n\n                rinsum += sir[0];\n                ginsum += sir[1];\n                binsum += sir[2];\n\n                rsum += rinsum;\n                gsum += ginsum;\n                bsum += binsum;\n\n                stackpointer = (stackpointer + 1) % div;\n                sir = stack[stackpointer];\n\n                routsum += sir[0];\n                goutsum += sir[1];\n                boutsum += sir[2];\n\n                rinsum -= sir[0];\n                ginsum -= sir[1];\n                binsum -= sir[2];\n\n                yi += w;\n            }\n        }\n\n        bitmap.setPixels(pix, 0, w, 0, 0, w, h);\n\n        return (bitmap);\n    }\n\n    /**\n     * 给 {@link View} 设置高斯模糊背景图片\n     *\n     * @param context\n     * @param bkg\n     * @param view\n     */\n    public static void blur(Context context, Bitmap bkg, View view) {\n        long startMs = System.currentTimeMillis();\n        float radius = 15;\n        float scaleFactor = 8;\n        //放大到整个view的大小\n        bkg = DrawableProvider.getReSizeBitmap(bkg, view.getMeasuredWidth(), view.getMeasuredHeight());\n\n        Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth() / scaleFactor)\n                , (int) (view.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(overlay);\n        canvas.translate(-view.getLeft() / scaleFactor, -view.getTop() / scaleFactor);\n        canvas.scale(1 / scaleFactor, 1 / scaleFactor);\n        Paint paint = new Paint();\n        paint.setFlags(Paint.FILTER_BITMAP_FLAG);\n        canvas.drawBitmap(bkg, 0, 0, paint);\n        overlay = FastBlur.doBlur(overlay, (int) radius, true);\n        view.setBackgroundDrawable(new BitmapDrawable(context.getResources(), overlay));\n        Log.w(\"test\", \"cost \" + (System.currentTimeMillis() - startMs) + \"ms\");\n    }\n\n    /**\n     * 将 {@link Bitmap} 高斯模糊并返回\n     *\n     * @param bkg\n     * @param width\n     * @param height\n     * @return\n     */\n    public static Bitmap blurBitmap(Bitmap bkg, int width, int height) {\n        long startMs = System.currentTimeMillis();\n        float radius = 15;//越大模糊效果越大\n        float scaleFactor = 8;\n        //放大到整个view的大小\n        bkg = DrawableProvider.getReSizeBitmap(bkg, width, height);\n        Bitmap overlay = Bitmap.createBitmap((int) (width / scaleFactor)\n                , (int) (height / scaleFactor), Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(overlay);\n        canvas.scale(1 / scaleFactor, 1 / scaleFactor);\n        Paint paint = new Paint();\n        paint.setFlags(Paint.FILTER_BITMAP_FLAG);\n        canvas.drawBitmap(bkg, 0, 0, paint);\n        overlay = FastBlur.doBlur(overlay, (int) radius, true);\n        Log.w(\"test\", \"cost \" + (System.currentTimeMillis() - startMs) + \"ms\");\n        return overlay;\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/LogUtils.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.text.TextUtils;\r\nimport android.util.Log;\r\n\r\n/**\r\n * ================================================\r\n * 日志工具类\r\n * <p>\r\n * Created by JessYan on 2015/11/23.\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class LogUtils {\r\n    private static final String DEFAULT_TAG = \"MVPArms\";\r\n    private static boolean isLog = true;\r\n\r\n    private LogUtils() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    public static boolean isLog() {\r\n        return isLog;\r\n    }\r\n\r\n    public static void setLog(boolean isLog) {\r\n        LogUtils.isLog = isLog;\r\n    }\r\n\r\n    public static void debugInfo(String tag, String msg) {\r\n        if (!isLog || TextUtils.isEmpty(msg)) {\r\n            return;\r\n        }\r\n        Log.d(tag, msg);\r\n\r\n    }\r\n\r\n    public static void debugInfo(String msg) {\r\n        debugInfo(DEFAULT_TAG, msg);\r\n    }\r\n\r\n    public static void warnInfo(String tag, String msg) {\r\n        if (!isLog || TextUtils.isEmpty(msg)) {\r\n            return;\r\n        }\r\n        Log.w(tag, msg);\r\n\r\n    }\r\n\r\n    public static void warnInfo(String msg) {\r\n        warnInfo(DEFAULT_TAG, msg);\r\n    }\r\n\r\n    /**\r\n     * 这里使用自己分节的方式来输出足够长度的 message\r\n     *\r\n     * @param tag 标签\r\n     * @param msg 日志内容\r\n     */\r\n    public static void debugLongInfo(String tag, String msg) {\r\n        if (!isLog || TextUtils.isEmpty(msg)) {\r\n            return;\r\n        }\r\n        msg = msg.trim();\r\n        int index = 0;\r\n        int maxLength = 3500;\r\n        String sub;\r\n        while (index < msg.length()) {\r\n            if (msg.length() <= index + maxLength) {\r\n                sub = msg.substring(index);\r\n            } else {\r\n                sub = msg.substring(index, index + maxLength);\r\n            }\r\n\r\n            index += maxLength;\r\n            Log.d(tag, sub.trim());\r\n        }\r\n    }\r\n\r\n    public static void debugLongInfo(String msg) {\r\n        debugLongInfo(DEFAULT_TAG, msg);\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/PermissionUtil.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport android.Manifest;\n\nimport com.tbruyelle.rxpermissions2.Permission;\nimport com.tbruyelle.rxpermissions2.RxPermissions;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.reactivex.annotations.NonNull;\nimport me.jessyan.rxerrorhandler.core.RxErrorHandler;\nimport me.jessyan.rxerrorhandler.handler.ErrorHandleSubscriber;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 权限请求工具类\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.9\">PermissionUtil wiki 官方文档</a>\n * Created by JessYan on 17/10/2016 10:09\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class PermissionUtil {\n    public static final String TAG = \"Permission\";\n\n    private PermissionUtil() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    public static void requestPermission(final RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler, String... permissions) {\n        if (permissions == null || permissions.length == 0) {\n            return;\n        }\n\n        List<String> needRequest = new ArrayList<>();\n        for (String permission : permissions) { //过滤调已经申请过的权限\n            if (!rxPermissions.isGranted(permission)) {\n                needRequest.add(permission);\n            }\n        }\n\n        if (needRequest.isEmpty()) {//全部权限都已经申请过，直接执行操作\n            requestPermission.onRequestPermissionSuccess();\n        } else {//没有申请过,则开始申请\n            rxPermissions\n                    .requestEach(needRequest.toArray(new String[0]))\n                    .buffer(permissions.length)\n                    .subscribe(new ErrorHandleSubscriber<List<Permission>>(errorHandler) {\n                        @Override\n                        public void onNext(@NonNull List<Permission> permissions) {\n                            List<String> failurePermissions = new ArrayList<>();\n                            List<String> askNeverAgainPermissions = new ArrayList<>();\n                            for (Permission p : permissions) {\n                                if (!p.granted) {\n                                    if (p.shouldShowRequestPermissionRationale) {\n                                        failurePermissions.add(p.name);\n                                    } else {\n                                        askNeverAgainPermissions.add(p.name);\n                                    }\n                                }\n                            }\n                            if (failurePermissions.size() > 0) {\n                                Timber.tag(TAG).d(\"Request permissions failure\");\n                                requestPermission.onRequestPermissionFailure(failurePermissions);\n                            }\n\n                            if (askNeverAgainPermissions.size() > 0) {\n                                Timber.tag(TAG).d(\"Request permissions failure with ask never again\");\n                                requestPermission.onRequestPermissionFailureWithAskNeverAgain(askNeverAgainPermissions);\n                            }\n\n                            if (failurePermissions.size() == 0 && askNeverAgainPermissions.size() == 0) {\n                                Timber.tag(TAG).d(\"Request permissions success\");\n                                requestPermission.onRequestPermissionSuccess();\n                            }\n                        }\n                    });\n        }\n\n    }\n\n    /**\n     * 请求摄像头权限\n     */\n    public static void launchCamera(RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler) {\n        requestPermission(requestPermission, rxPermissions, errorHandler, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA);\n    }\n\n    /**\n     * 请求外部存储的权限\n     */\n    public static void externalStorage(RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler) {\n        requestPermission(requestPermission, rxPermissions, errorHandler, Manifest.permission.WRITE_EXTERNAL_STORAGE);\n    }\n\n    /**\n     * 请求发送短信权限\n     */\n    public static void sendSms(RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler) {\n        requestPermission(requestPermission, rxPermissions, errorHandler, Manifest.permission.SEND_SMS);\n    }\n\n    /**\n     * 请求打电话权限\n     */\n    public static void callPhone(RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler) {\n        requestPermission(requestPermission, rxPermissions, errorHandler, Manifest.permission.CALL_PHONE);\n    }\n\n    /**\n     * 请求获取手机状态的权限\n     */\n    public static void readPhonestate(RequestPermission requestPermission, RxPermissions rxPermissions, RxErrorHandler errorHandler) {\n        requestPermission(requestPermission, rxPermissions, errorHandler, Manifest.permission.READ_PHONE_STATE);\n    }\n\n    public interface RequestPermission {\n\n        /**\n         * 权限请求成功\n         */\n        void onRequestPermissionSuccess();\n\n        /**\n         * 用户拒绝了权限请求, 权限请求失败, 但还可以继续请求该权限\n         *\n         * @param permissions 请求失败的权限名\n         */\n        void onRequestPermissionFailure(List<String> permissions);\n\n        /**\n         * 用户拒绝了权限请求并且用户选择了以后不再询问, 权限请求失败, 这时将不能继续请求该权限, 需要提示用户进入设置页面打开该权限\n         *\n         * @param permissions 请求失败的权限名\n         */\n        void onRequestPermissionFailureWithAskNeverAgain(List<String> permissions);\n    }\n}\n\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/Preconditions.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport androidx.annotation.Nullable;\n\n/**\n * ================================================\n * Created by JessYan on 26/09/2016 13:59\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic final class Preconditions {\n\n    private Preconditions() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    public static void checkArgument(boolean expression) {\n        if (!expression) {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    public static void checkArgument(boolean expression, @Nullable Object errorMessage) {\n        if (!expression) {\n            throw new IllegalArgumentException(String.valueOf(errorMessage));\n        }\n    }\n\n    public static void checkArgument(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) {\n        if (!expression) {\n            throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));\n        }\n    }\n\n    public static void checkState(boolean expression) {\n        if (!expression) {\n            throw new IllegalStateException();\n        }\n    }\n\n    public static void checkState(boolean expression, @Nullable Object errorMessage) {\n        if (!expression) {\n            throw new IllegalStateException(String.valueOf(errorMessage));\n        }\n    }\n\n    public static void checkState(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) {\n        if (!expression) {\n            throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs));\n        }\n    }\n\n    public static <T> T checkNotNull(T reference) {\n        if (reference == null) {\n            throw new NullPointerException();\n        } else {\n            return reference;\n        }\n    }\n\n    public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {\n        if (reference == null) {\n            throw new NullPointerException(String.valueOf(errorMessage));\n        } else {\n            return reference;\n        }\n    }\n\n    public static <T> T checkNotNull(T reference, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs) {\n        if (reference == null) {\n            throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));\n        } else {\n            return reference;\n        }\n    }\n\n    public static int checkElementIndex(int index, int size) {\n        return checkElementIndex(index, size, \"index\");\n    }\n\n    public static int checkElementIndex(int index, int size, @Nullable String desc) {\n        if (index >= 0 && index < size) {\n            return index;\n        } else {\n            throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));\n        }\n    }\n\n    private static String badElementIndex(int index, int size, String desc) {\n        if (index < 0) {\n            return format(\"%s (%s) must not be negative\", new Object[]{desc, Integer.valueOf(index)});\n        } else if (size < 0) {\n            throw new IllegalArgumentException((new StringBuilder(26)).append(\"negative size: \").append(size).toString());\n        } else {\n            return format(\"%s (%s) must be less than size (%s)\", new Object[]{desc, Integer.valueOf(index), Integer.valueOf(size)});\n        }\n    }\n\n    public static int checkPositionIndex(int index, int size) {\n        return checkPositionIndex(index, size, \"index\");\n    }\n\n    public static int checkPositionIndex(int index, int size, @Nullable String desc) {\n        if (index >= 0 && index <= size) {\n            return index;\n        } else {\n            throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));\n        }\n    }\n\n    private static String badPositionIndex(int index, int size, String desc) {\n        if (index < 0) {\n            return format(\"%s (%s) must not be negative\", new Object[]{desc, Integer.valueOf(index)});\n        } else if (size < 0) {\n            throw new IllegalArgumentException((new StringBuilder(26)).append(\"negative size: \").append(size).toString());\n        } else {\n            return format(\"%s (%s) must not be greater than size (%s)\", new Object[]{desc, Integer.valueOf(index), Integer.valueOf(size)});\n        }\n    }\n\n    public static void checkPositionIndexes(int start, int end, int size) {\n        if (start < 0 || end < start || end > size) {\n            throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));\n        }\n    }\n\n    private static String badPositionIndexes(int start, int end, int size) {\n        return start >= 0 && start <= size ? (end >= 0 && end <= size ? format(\"end index (%s) must not be less than start index (%s)\", new Object[]{Integer.valueOf(end), Integer.valueOf(start)}) : badPositionIndex(end, size, \"end index\")) : badPositionIndex(start, size, \"start index\");\n    }\n\n    static String format(String template, @Nullable Object... args) {\n        template = String.valueOf(template);\n        StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);\n        int templateStart = 0;\n\n        int i;\n        int placeholderStart;\n        for (i = 0; i < args.length; templateStart = placeholderStart + 2) {\n            placeholderStart = template.indexOf(\"%s\", templateStart);\n            if (placeholderStart == -1) {\n                break;\n            }\n\n            builder.append(template.substring(templateStart, placeholderStart));\n            builder.append(args[i++]);\n        }\n\n        builder.append(template.substring(templateStart));\n        if (i < args.length) {\n            builder.append(\" [\");\n            builder.append(args[i++]);\n\n            while (i < args.length) {\n                builder.append(\", \");\n                builder.append(args[i++]);\n            }\n\n            builder.append(']');\n        }\n\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/RxLifecycleUtils.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport com.jess.arms.integration.lifecycle.ActivityLifecycleable;\nimport com.jess.arms.integration.lifecycle.FragmentLifecycleable;\nimport com.jess.arms.integration.lifecycle.Lifecycleable;\nimport com.jess.arms.mvp.IView;\nimport com.trello.rxlifecycle2.LifecycleTransformer;\nimport com.trello.rxlifecycle2.RxLifecycle;\nimport com.trello.rxlifecycle2.android.ActivityEvent;\nimport com.trello.rxlifecycle2.android.FragmentEvent;\nimport com.trello.rxlifecycle2.android.RxLifecycleAndroid;\n\nimport io.reactivex.annotations.NonNull;\n\n/**\n * ================================================\n * 使用此类操作 RxLifecycle 的特性\n * <p>\n * Created by JessYan on 26/08/2017 17:52\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n\npublic class RxLifecycleUtils {\n\n    private RxLifecycleUtils() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    /**\n     * 绑定 Activity 的指定生命周期\n     *\n     * @param view\n     * @param event\n     * @param <T>\n     * @return\n     */\n    public static <T> LifecycleTransformer<T> bindUntilEvent(@NonNull final IView view,\n                                                             final ActivityEvent event) {\n        Preconditions.checkNotNull(view, \"view == null\");\n        if (view instanceof ActivityLifecycleable) {\n            return bindUntilEvent((ActivityLifecycleable) view, event);\n        } else {\n            throw new IllegalArgumentException(\"view isn't ActivityLifecycleable\");\n        }\n    }\n\n    /**\n     * 绑定 Fragment 的指定生命周期\n     *\n     * @param view\n     * @param event\n     * @param <T>\n     * @return\n     */\n    public static <T> LifecycleTransformer<T> bindUntilEvent(@NonNull final IView view,\n                                                             final FragmentEvent event) {\n        Preconditions.checkNotNull(view, \"view == null\");\n        if (view instanceof FragmentLifecycleable) {\n            return bindUntilEvent((FragmentLifecycleable) view, event);\n        } else {\n            throw new IllegalArgumentException(\"view isn't FragmentLifecycleable\");\n        }\n    }\n\n    public static <T, R> LifecycleTransformer<T> bindUntilEvent(@NonNull final Lifecycleable<R> lifecycleable,\n                                                                final R event) {\n        Preconditions.checkNotNull(lifecycleable, \"lifecycleable == null\");\n        return RxLifecycle.bindUntilEvent(lifecycleable.provideLifecycleSubject(), event);\n    }\n\n    /**\n     * 绑定 Activity/Fragment 的生命周期\n     *\n     * @param view\n     * @param <T>\n     * @return\n     */\n    public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull IView view) {\n        Preconditions.checkNotNull(view, \"view == null\");\n        if (view instanceof Lifecycleable) {\n            return bindToLifecycle((Lifecycleable) view);\n        } else {\n            throw new IllegalArgumentException(\"view isn't Lifecycleable\");\n        }\n    }\n\n    public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull Lifecycleable lifecycleable) {\n        Preconditions.checkNotNull(lifecycleable, \"lifecycleable == null\");\n        if (lifecycleable instanceof ActivityLifecycleable) {\n            return RxLifecycleAndroid.bindActivity(((ActivityLifecycleable) lifecycleable).provideLifecycleSubject());\n        } else if (lifecycleable instanceof FragmentLifecycleable) {\n            return RxLifecycleAndroid.bindFragment(((FragmentLifecycleable) lifecycleable).provideLifecycleSubject());\n        } else {\n            throw new IllegalArgumentException(\"Lifecycleable not match\");\n        }\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/ThirdViewUtil.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.utils;\r\n\r\nimport android.app.Activity;\r\nimport android.app.Dialog;\r\nimport android.content.Context;\r\nimport android.content.pm.ApplicationInfo;\r\nimport android.content.pm.PackageManager;\r\nimport android.util.AttributeSet;\r\nimport android.view.View;\r\n\r\nimport androidx.annotation.Nullable;\r\n\r\nimport com.zhy.autolayout.AutoFrameLayout;\r\nimport com.zhy.autolayout.AutoLinearLayout;\r\nimport com.zhy.autolayout.AutoRelativeLayout;\r\n\r\nimport butterknife.ButterKnife;\r\nimport butterknife.Unbinder;\r\n\r\nimport static com.jess.arms.base.Platform.DEPENDENCY_AUTO_LAYOUT;\r\nimport static com.jess.arms.base.delegate.ActivityDelegate.LAYOUT_FRAMELAYOUT;\r\nimport static com.jess.arms.base.delegate.ActivityDelegate.LAYOUT_LINEARLAYOUT;\r\nimport static com.jess.arms.base.delegate.ActivityDelegate.LAYOUT_RELATIVELAYOUT;\r\n\r\n/**\r\n * ================================================\r\n * Created by JessYan on 17/03/2016 13:59\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class ThirdViewUtil {\r\n    private static int HAS_AUTO_LAYOUT_META = -1;//0 说明 AndroidManifest 里面没有使用 AutoLauout 的 Meta, 即不使用 AutoLayout, 1 为有 Meta, 即需要使用\r\n\r\n    private ThirdViewUtil() {\r\n        throw new IllegalStateException(\"you can't instantiate me!\");\r\n    }\r\n\r\n    public static boolean isUseAutolayout() {\r\n        return DEPENDENCY_AUTO_LAYOUT && HAS_AUTO_LAYOUT_META == 1;\r\n    }\r\n\r\n    public static Unbinder bindTarget(Object target, Object source) {\r\n        if (source instanceof Activity) {\r\n            return ButterKnife.bind(target, (Activity) source);\r\n        } else if (source instanceof View) {\r\n            return ButterKnife.bind(target, (View) source);\r\n        } else if (source instanceof Dialog) {\r\n            return ButterKnife.bind(target, (Dialog) source);\r\n        } else {\r\n            return Unbinder.EMPTY;\r\n        }\r\n    }\r\n\r\n    @Nullable\r\n    public static View convertAutoView(String name, Context context, AttributeSet attrs) {\r\n        //本框架并不强制您使用 AutoLayout\r\n        //如果您不想使用 AutoLayout, 请不要依赖 AutoLayout, 也不要在 AndroidManifest 中声明 AutoLayout 的 Meta 属性 (design_width, design_height)\r\n        if (!DEPENDENCY_AUTO_LAYOUT) {\r\n            return null;\r\n        }\r\n        if (HAS_AUTO_LAYOUT_META == -1) {\r\n            HAS_AUTO_LAYOUT_META = 1;\r\n            PackageManager packageManager = context.getPackageManager();\r\n            ApplicationInfo applicationInfo;\r\n            try {\r\n                applicationInfo = packageManager.getApplicationInfo(context\r\n                        .getPackageName(), PackageManager.GET_META_DATA);\r\n                if (applicationInfo == null || applicationInfo.metaData == null\r\n                        || !applicationInfo.metaData.containsKey(\"design_width\")\r\n                        || !applicationInfo.metaData.containsKey(\"design_height\")) {\r\n                    HAS_AUTO_LAYOUT_META = 0;\r\n                }\r\n            } catch (PackageManager.NameNotFoundException e) {\r\n                HAS_AUTO_LAYOUT_META = 0;\r\n            }\r\n        }\r\n\r\n        if (HAS_AUTO_LAYOUT_META == 0) {\r\n            return null;\r\n        }\r\n\r\n        View view = null;\r\n        switch (name) {\r\n            case LAYOUT_FRAMELAYOUT:\r\n                view = new AutoFrameLayout(context, attrs);\r\n                break;\r\n            case LAYOUT_LINEARLAYOUT:\r\n                view = new AutoLinearLayout(context, attrs);\r\n                break;\r\n            case LAYOUT_RELATIVELAYOUT:\r\n                view = new AutoRelativeLayout(context, attrs);\r\n                break;\r\n            default:\r\n                break;\r\n        }\r\n        return view;\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/UrlEncoderUtils.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\n/**\n * ================================================\n * Created by JessYan on 2018/9/14 14:10\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class UrlEncoderUtils {\n\n    private UrlEncoderUtils() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    /**\n     * 判断 str 是否已经 URLEncoder.encode() 过\n     * 经常遇到这样的情况, 拿到一个 URL, 但是搞不清楚到底要不要 URLEncoder.encode()\n     * 不做 URLEncoder.encode() 吧, 担心出错, 做 URLEncoder.encode() 吧, 又怕重复了\n     *\n     * @param str 需要判断的内容\n     * @return 返回 {@code true} 为被 URLEncoder.encode() 过\n     */\n    public static boolean hasUrlEncoded(String str) {\n        boolean encode = false;\n        for (int i = 0; i < str.length(); i++) {\n            char c = str.charAt(i);\n            if (c == '%' && (i + 2) < str.length()) {\n                // 判断是否符合urlEncode规范\n                char c1 = str.charAt(i + 1);\n                char c2 = str.charAt(i + 2);\n                if (isValidHexChar(c1) && isValidHexChar(c2)) {\n                    encode = true;\n                    break;\n                } else {\n                    break;\n                }\n            }\n        }\n        return encode;\n    }\n\n    /**\n     * 判断 c 是否是 16 进制的字符\n     *\n     * @param c 需要判断的字符\n     * @return 返回 {@code true} 为 16 进制的字符\n     */\n    private static boolean isValidHexChar(char c) {\n        return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/utils/ZipHelper.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.utils;\n\nimport android.os.Build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.zip.DataFormatException;\nimport java.util.zip.Deflater;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\nimport java.util.zip.Inflater;\n\n/**\n * ================================================\n * 处理压缩和解压的工具类\n * <p>\n * Created by JessYan on 10/05/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ZipHelper {\n\n    private ZipHelper() {\n        throw new IllegalStateException(\"you can't instantiate me!\");\n    }\n\n    /**\n     * zlib decompress 2 String\n     *\n     * @param bytesToDecompress\n     * @return\n     */\n    public static String decompressToStringForZlib(byte[] bytesToDecompress) {\n        return decompressToStringForZlib(bytesToDecompress, \"UTF-8\");\n    }\n\n    /**\n     * zlib decompress 2 String\n     *\n     * @param bytesToDecompress\n     * @param charsetName\n     * @return\n     */\n    public static String decompressToStringForZlib(byte[] bytesToDecompress, String charsetName) {\n        byte[] bytesDecompressed = decompressForZlib\n                (\n                        bytesToDecompress\n                );\n\n        String returnValue = null;\n\n        try {\n            returnValue = new String\n                    (\n                            bytesDecompressed,\n                            0,\n                            bytesDecompressed.length,\n                            charsetName\n                    );\n        } catch (UnsupportedEncodingException uee) {\n            uee.printStackTrace();\n        }\n\n        return returnValue;\n\n    }\n\n    /**\n     * zlib decompress 2 byte\n     *\n     * @param bytesToDecompress\n     * @return\n     */\n    public static byte[] decompressForZlib(byte[] bytesToDecompress) {\n        byte[] returnValues = null;\n\n        Inflater inflater = new Inflater();\n\n        int numberOfBytesToDecompress = bytesToDecompress.length;\n\n        inflater.setInput\n                (\n                        bytesToDecompress,\n                        0,\n                        numberOfBytesToDecompress\n                );\n\n        int numberOfBytesDecompressedSoFar = 0;\n        List<Byte> bytesDecompressedSoFar = new ArrayList<>();\n\n        try {\n            while (!inflater.needsInput()) {\n                byte[] bytesDecompressedBuffer = new byte[numberOfBytesToDecompress];\n\n                int numberOfBytesDecompressedThisTime = inflater.inflate\n                        (\n                                bytesDecompressedBuffer\n                        );\n\n                numberOfBytesDecompressedSoFar += numberOfBytesDecompressedThisTime;\n\n                for (int b = 0; b < numberOfBytesDecompressedThisTime; b++) {\n                    bytesDecompressedSoFar.add(bytesDecompressedBuffer[b]);\n                }\n            }\n\n            returnValues = new byte[bytesDecompressedSoFar.size()];\n            for (int b = 0; b < returnValues.length; b++) {\n                returnValues[b] = bytesDecompressedSoFar.get(b);\n            }\n\n        } catch (DataFormatException dfe) {\n            dfe.printStackTrace();\n        }\n\n        inflater.end();\n\n        return returnValues;\n    }\n\n    /**\n     * zlib compress 2 byte\n     *\n     * @param bytesToCompress\n     * @return\n     */\n    public static byte[] compressForZlib(byte[] bytesToCompress) {\n        Deflater deflater = new Deflater();\n        deflater.setInput(bytesToCompress);\n        deflater.finish();\n\n        byte[] bytesCompressed = new byte[Short.MAX_VALUE];\n\n        int numberOfBytesAfterCompression = deflater.deflate(bytesCompressed);\n\n        byte[] returnValues = new byte[numberOfBytesAfterCompression];\n\n        System.arraycopy\n                (\n                        bytesCompressed,\n                        0,\n                        returnValues,\n                        0,\n                        numberOfBytesAfterCompression\n                );\n\n        return returnValues;\n    }\n\n    /**\n     * zlib compress 2 byte\n     *\n     * @param stringToCompress\n     * @return\n     */\n    public static byte[] compressForZlib(String stringToCompress) {\n        byte[] returnValues = null;\n\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n                returnValues = compressForZlib\n                        (\n                                stringToCompress.getBytes(StandardCharsets.UTF_8)\n                        );\n            } else {\n                returnValues = compressForZlib\n                        (\n                                stringToCompress.getBytes(\"UTF-8\")\n                        );\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return returnValues;\n    }\n\n    /**\n     * gzip compress 2 byte\n     *\n     * @param string\n     * @return\n     * @throws IOException\n     */\n    public static byte[] compressForGzip(String string) {\n        ByteArrayOutputStream os = null;\n        GZIPOutputStream gos = null;\n        try {\n            os = new ByteArrayOutputStream(string.length());\n            gos = new GZIPOutputStream(os);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n                gos.write(string.getBytes(StandardCharsets.UTF_8));\n            } else {\n                gos.write(string.getBytes(\"UTF-8\"));\n            }\n            return os.toByteArray();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            closeQuietly(gos);\n            closeQuietly(os);\n        }\n        return null;\n    }\n\n    /**\n     * gzip decompress 2 string\n     *\n     * @param compressed\n     * @return\n     * @throws IOException\n     */\n    public static String decompressForGzip(byte[] compressed) {\n        return decompressForGzip(compressed, \"UTF-8\");\n    }\n\n    /**\n     * gzip decompress 2 string\n     *\n     * @param compressed\n     * @param charsetName\n     * @return\n     */\n    public static String decompressForGzip(byte[] compressed, String charsetName) {\n        final int BUFFER_SIZE = compressed.length;\n        GZIPInputStream gis = null;\n        ByteArrayInputStream is = null;\n        try {\n            is = new ByteArrayInputStream(compressed);\n            gis = new GZIPInputStream(is, BUFFER_SIZE);\n            StringBuilder string = new StringBuilder();\n            byte[] data = new byte[BUFFER_SIZE];\n            int bytesRead;\n            while ((bytesRead = gis.read(data)) != -1) {\n                string.append(new String(data, 0, bytesRead, charsetName));\n            }\n            return string.toString();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            closeQuietly(gis);\n            closeQuietly(is);\n        }\n        return null;\n    }\n\n    public static void closeQuietly(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (RuntimeException rethrown) {\n                throw rethrown;\n            } catch (Exception ignored) {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "arms/src/main/java/com/jess/arms/widget/CustomPopupWindow.java",
    "content": "/*\r\n * Copyright 2017 JessYan\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage com.jess.arms.widget;\r\n\r\nimport android.graphics.drawable.ColorDrawable;\r\nimport android.graphics.drawable.Drawable;\r\nimport android.view.ContextThemeWrapper;\r\nimport android.view.Gravity;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.widget.LinearLayout.LayoutParams;\r\nimport android.widget.PopupWindow;\r\n\r\n/**\r\n * ================================================\r\n * 因为继承于 {@link PopupWindow} ,所以它本身就是一个 {@link PopupWindow}\r\n * 因此如果此类里封装的功能并不能满足您的需求(不想过多封装 UI 的东西,这里只提供思想,觉得不满足需求可以自己仿照着封装)\r\n * 您可以直接调用 {@link PopupWindow} 的 Api 满足需求\r\n *\r\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.7\">CustomPopupWindow wiki 官方文档</a>\r\n * Created by JessYan on 4/22/2016\r\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\r\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\r\n * ================================================\r\n */\r\npublic class CustomPopupWindow extends PopupWindow {\r\n    private View mContentView;\r\n    private View mParentView;\r\n    private CustomPopupWindowListener mListener;\r\n    private boolean isOutsideTouch;\r\n    private boolean isFocus;\r\n    private Drawable mBackgroundDrawable;\r\n    private int mAnimationStyle;\r\n    private boolean isWrap;\r\n\r\n    private CustomPopupWindow(Builder builder) {\r\n        this.mContentView = builder.contentView;\r\n        this.mParentView = builder.parentView;\r\n        this.mListener = builder.listener;\r\n        this.isOutsideTouch = builder.isOutsideTouch;\r\n        this.isFocus = builder.isFocus;\r\n        this.mBackgroundDrawable = builder.backgroundDrawable;\r\n        this.mAnimationStyle = builder.animationStyle;\r\n        this.isWrap = builder.isWrap;\r\n        initLayout();\r\n    }\r\n\r\n    public static Builder builder() {\r\n        return new Builder();\r\n    }\r\n\r\n    /**\r\n     * 用于填充contentView,必须传ContextThemeWrapper(比如activity)不然popupwindow要报错\r\n     *\r\n     * @param context\r\n     * @param layoutId\r\n     * @return\r\n     */\r\n    public static View inflateView(ContextThemeWrapper context, int layoutId) {\r\n        return LayoutInflater.from(context)\r\n                .inflate(layoutId, null);\r\n    }\r\n\r\n    private void initLayout() {\r\n        mListener.initPopupView(mContentView);\r\n        setWidth(isWrap ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT);\r\n        setHeight(isWrap ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT);\r\n        setFocusable(isFocus);\r\n        setOutsideTouchable(isOutsideTouch);\r\n        setBackgroundDrawable(mBackgroundDrawable);\r\n        if (mAnimationStyle != -1)//如果设置了动画则使用动画\r\n        {\r\n            setAnimationStyle(mAnimationStyle);\r\n        }\r\n        setContentView(mContentView);\r\n    }\r\n\r\n    /**\r\n     * 获得用于展示popup内容的view\r\n     *\r\n     * @return\r\n     */\r\n    @Override\r\n    public View getContentView() {\r\n        return mContentView;\r\n    }\r\n\r\n    public void show() {//默认显示到中间\r\n        if (mParentView == null) {\r\n            showAtLocation(mContentView, Gravity.CENTER | Gravity.CENTER_HORIZONTAL, 0, 0);\r\n        } else {\r\n            showAtLocation(mParentView, Gravity.CENTER | Gravity.CENTER_HORIZONTAL, 0, 0);\r\n        }\r\n    }\r\n\r\n    public interface CustomPopupWindowListener {\r\n        void initPopupView(View contentView);\r\n    }\r\n\r\n    public static final class Builder {\r\n        private View contentView;\r\n        private View parentView;\r\n        private CustomPopupWindowListener listener;\r\n        private boolean isOutsideTouch = true;//默认为true\r\n        private boolean isFocus = true;//默认为true\r\n        private Drawable backgroundDrawable = new ColorDrawable(0x00000000);//默认为透明\r\n        private int animationStyle = -1;\r\n        private boolean isWrap;\r\n\r\n        private Builder() {\r\n        }\r\n\r\n        public Builder contentView(View contentView) {\r\n            this.contentView = contentView;\r\n            return this;\r\n        }\r\n\r\n        public Builder parentView(View parentView) {\r\n            this.parentView = parentView;\r\n            return this;\r\n        }\r\n\r\n        public Builder isWrap(boolean isWrap) {\r\n            this.isWrap = isWrap;\r\n            return this;\r\n        }\r\n\r\n        public Builder customListener(CustomPopupWindowListener listener) {\r\n            this.listener = listener;\r\n            return this;\r\n        }\r\n\r\n        public Builder isOutsideTouch(boolean isOutsideTouch) {\r\n            this.isOutsideTouch = isOutsideTouch;\r\n            return this;\r\n        }\r\n\r\n        public Builder isFocus(boolean isFocus) {\r\n            this.isFocus = isFocus;\r\n            return this;\r\n        }\r\n\r\n        public Builder backgroundDrawable(Drawable backgroundDrawable) {\r\n            this.backgroundDrawable = backgroundDrawable;\r\n            return this;\r\n        }\r\n\r\n        public Builder animationStyle(int animationStyle) {\r\n            this.animationStyle = animationStyle;\r\n            return this;\r\n        }\r\n\r\n        public CustomPopupWindow build() {\r\n            if (contentView == null) {\r\n                throw new IllegalStateException(\"ContentView is required\");\r\n            }\r\n            if (listener == null) {\r\n                throw new IllegalStateException(\"CustomPopupWindowListener is required\");\r\n            }\r\n\r\n            return new CustomPopupWindow(this);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "arms/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">arms</string>\n</resources>\n"
  },
  {
    "path": "arms-autolayout/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "arms-autolayout/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.android[\"compileSdkVersion\"]\n    buildToolsVersion rootProject.ext.android[\"buildToolsVersion\"]\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.android[\"minSdkVersion\"]\n        targetSdkVersion rootProject.ext.android[\"targetSdkVersion\"]\n        versionCode rootProject.ext.android[\"versionCode\"]\n        versionName rootProject.ext.android[\"versionName\"]\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compileOnly rootProject.ext.dependencies[\"appcompat\"]\n    compileOnly rootProject.ext.dependencies[\"annotations\"]\n    api(rootProject.ext.dependencies[\"design\"]) {\n        exclude module: 'annotation'\n        exclude module: 'appcompat'\n        exclude module: 'legacy-support-v4'\n        exclude module: 'recyclerview'\n    }\n    api(rootProject.ext.dependencies[\"cardview\"]) {\n        exclude module: 'annotation'\n    }\n    api(rootProject.ext.dependencies[\"autolayout\"]) {\n        exclude module: 'recyclerview'\n        exclude module: 'appcompat'\n        exclude module: 'vectordrawable-animated'\n    }\n}\n\napply from: '../bintray.gradle'"
  },
  {
    "path": "arms-autolayout/gradle.properties",
    "content": "POM_NAME=MVPArms-AndroidAutoLayout\n"
  },
  {
    "path": "arms-autolayout/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "arms-autolayout/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"com.jess.arms.widget.autolayout\" />\n"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoAppBarLayout.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.google.android.material.appbar.AppBarLayout;\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link AppBarLayout}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 4/14/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoAppBarLayout extends AppBarLayout {\n\n    private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public AutoAppBarLayout(Context context) {\n        super(context);\n    }\n\n    public AutoAppBarLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!isInEditMode()) {\n            mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    public static class LayoutParams extends AppBarLayout.LayoutParams\n            implements AutoLayoutHelper.AutoLayoutParams {\n        private AutoLayoutInfo mAutoLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(ViewGroup.MarginLayoutParams source) {\n            super(source);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo() {\n            return mAutoLayoutInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoCardView.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport androidx.cardview.widget.CardView;\n\nimport com.zhy.autolayout.AutoFrameLayout;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link CardView}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 9/3/16 21:40\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoCardView extends CardView {\n    private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public AutoCardView(Context context) {\n        super(context);\n    }\n\n    public AutoCardView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AutoCardView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    public AutoFrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new AutoFrameLayout.LayoutParams(getContext(), attrs);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!isInEditMode()) {\n            mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n}"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoCollapsingToolbarLayout.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.google.android.material.appbar.CollapsingToolbarLayout;\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link CollapsingToolbarLayout}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 4/14/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoCollapsingToolbarLayout extends CollapsingToolbarLayout {\n    private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public AutoCollapsingToolbarLayout(Context context) {\n        super(context);\n    }\n\n    public AutoCollapsingToolbarLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AutoCollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!isInEditMode()) {\n            mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    public static class LayoutParams extends CollapsingToolbarLayout.LayoutParams\n            implements AutoLayoutHelper.AutoLayoutParams {\n        private AutoLayoutInfo mAutoLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(ViewGroup.MarginLayoutParams source) {\n            super(source);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo() {\n            return mAutoLayoutInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoRadioGroup.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.RadioGroup;\n\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link RadioGroup}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 9/3/16 21:40\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoRadioGroup extends RadioGroup {\n    private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public AutoRadioGroup(Context context) {\n        super(context);\n    }\n\n    public AutoRadioGroup(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!isInEditMode()) {\n            mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    public static class LayoutParams extends RadioGroup.LayoutParams\n            implements AutoLayoutHelper.AutoLayoutParams {\n        private AutoLayoutInfo mAutoLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(MarginLayoutParams source) {\n            super(source);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo() {\n            return mAutoLayoutInfo;\n        }\n    }\n}"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoScrollView.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ScrollView;\n\nimport androidx.annotation.Nullable;\n\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link ScrollView}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 4/14/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoScrollView extends ScrollView {\n    private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n\n    public AutoScrollView(Context context) {\n        super(context);\n    }\n\n    public AutoScrollView(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AutoScrollView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!isInEditMode()) {\n            mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    public static class LayoutParams extends ScrollView.LayoutParams\n            implements AutoLayoutHelper.AutoLayoutParams {\n        private AutoLayoutInfo mAutoLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n            mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(MarginLayoutParams source) {\n            super(source);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo() {\n            return mAutoLayoutInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoTabLayout.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.material.tabs.TabLayout;\nimport com.zhy.autolayout.utils.AutoUtils;\nimport com.zhy.autolayout.utils.DimenUtils;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link TabLayout}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 4/14/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoTabLayout extends TabLayout {\n    private static final int NO_VALID = -1;\n    private int mTextSize;\n    private boolean mTextSizeBaseWidth = false;\n\n    public AutoTabLayout(Context context) {\n        this(context, null);\n    }\n\n    public AutoTabLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public AutoTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        initTextSizeBaseWidth(context, attrs);\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,\n                defStyleAttr, R.style.Widget_Design_TabLayout);\n        int tabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,\n                R.style.TextAppearance_Design_Tab);\n\n        mTextSize = loadTextSizeFromTextAppearance(tabTextAppearance);\n        a.recycle();\n    }\n\n    private void initTextSizeBaseWidth(Context context, AttributeSet attrs) {\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoTabLayout);\n        mTextSizeBaseWidth = a.getBoolean(R.styleable.AutoTabLayout_auto_textSize_base_width, false);\n        a.recycle();\n    }\n\n    private int loadTextSizeFromTextAppearance(int textAppearanceResId) {\n        TypedArray a = getContext().obtainStyledAttributes(textAppearanceResId,\n                R.styleable.TextAppearance);\n\n        try {\n            if (!DimenUtils.isPxVal(a.peekValue(R.styleable.TextAppearance_android_textSize))) {\n                return NO_VALID;\n            }\n            return a.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, NO_VALID);\n        } finally {\n            a.recycle();\n        }\n    }\n\n    @Override\n    public void addTab(@NonNull Tab tab, int position, boolean setSelected) {\n        super.addTab(tab, position, setSelected);\n        setUpTabTextSize(tab);\n    }\n\n    @Override\n    public void addTab(@NonNull Tab tab, boolean setSelected) {\n        super.addTab(tab, setSelected);\n        setUpTabTextSize(tab);\n    }\n\n    private void setUpTabTextSize(Tab tab) {\n        if (mTextSize == NO_VALID || tab.getCustomView() != null) {\n            return;\n        }\n\n        ViewGroup tabGroup = (ViewGroup) getChildAt(0);\n        ViewGroup tabContainer = (ViewGroup) tabGroup.getChildAt(tab.getPosition());\n        TextView textView = (TextView) tabContainer.getChildAt(1);\n\n        if (AutoUtils.autoed(textView)) {\n            return;\n        }\n        int autoTextSize;\n        if (mTextSizeBaseWidth) {\n            autoTextSize = AutoUtils.getPercentWidthSize(mTextSize);\n        } else {\n            autoTextSize = AutoUtils.getPercentHeightSize(mTextSize);\n        }\n\n        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, autoTextSize);\n    }\n}\n\n"
  },
  {
    "path": "arms-autolayout/src/main/java/com/jess/arms/widget/autolayout/AutoToolbar.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.widget.autolayout;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.appcompat.widget.Toolbar;\n\nimport com.zhy.autolayout.AutoLayoutInfo;\nimport com.zhy.autolayout.utils.AutoLayoutHelper;\nimport com.zhy.autolayout.utils.AutoUtils;\nimport com.zhy.autolayout.utils.DimenUtils;\n\nimport java.lang.reflect.Field;\n\n/**\n * ================================================\n * 实现 AndroidAutoLayout 规范的 {@link Toolbar}\n * 可使用 MVP_generator_solution 中的 AutoView 模版生成各种符合 AndroidAutoLayout 规范的 {@link View}\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.6\">AutoLayout wiki 官方文档</a>\n * Created by JessYan on 4/14/2016\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AutoToolbar extends Toolbar {\n    private static final int NO_VALID = -1;\n    private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);\n    private int mTextSize;\n    private int mSubTextSize;\n\n    public AutoToolbar(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,\n                defStyleAttr, R.style.Widget_AppCompat_Toolbar);\n\n        int titleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance,\n                R.style.TextAppearance_Widget_AppCompat_Toolbar_Title);\n\n        int subtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance,\n                R.style.TextAppearance_Widget_AppCompat_Toolbar_Subtitle);\n\n        mTextSize = loadTextSizeFromTextAppearance(titleTextAppearance);\n        mSubTextSize = loadTextSizeFromTextAppearance(subtitleTextAppearance);\n\n        a.recycle();\n    }\n\n    public AutoToolbar(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public AutoToolbar(Context context) {\n        this(context, null);\n    }\n\n    private int loadTextSizeFromTextAppearance(int textAppearanceResId) {\n        TypedArray a = getContext().obtainStyledAttributes(textAppearanceResId,\n                R.styleable.TextAppearance);\n        try {\n            if (!DimenUtils.isPxVal(a.peekValue(R.styleable.TextAppearance_android_textSize))) {\n                return NO_VALID;\n            }\n            return a.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, NO_VALID);\n        } finally {\n            a.recycle();\n        }\n    }\n\n    private void setUpTitleTextSize() {\n        CharSequence title = getTitle();\n        if (!TextUtils.isEmpty(title) && mTextSize != NO_VALID) {\n            setUpTitleTextSize(\"mTitleTextView\", mTextSize);\n        }\n        CharSequence subtitle = getSubtitle();\n        if (!TextUtils.isEmpty(subtitle) && mSubTextSize != NO_VALID) {\n            setUpTitleTextSize(\"mSubtitleTextView\", mSubTextSize);\n        }\n    }\n\n    private void setUpTitleTextSize(String name, int val) {\n        try {\n            //反射 Toolbar 的 TextView\n            Field f = getClass().getSuperclass().getDeclaredField(name);\n            f.setAccessible(true);\n            TextView textView = (TextView) f.get(this);\n            if (textView != null) {\n                int autoTextSize = AutoUtils.getPercentHeightSize(val);\n                textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, autoTextSize);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (!this.isInEditMode()) {\n            setUpTitleTextSize();\n            this.mHelper.adjustChildren();\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        super.onLayout(changed, l, t, r, b);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(this.getContext(), attrs);\n    }\n\n    public static class LayoutParams extends Toolbar.LayoutParams implements AutoLayoutHelper.AutoLayoutParams {\n        private AutoLayoutInfo mDimenLayoutInfo;\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n            this.mDimenLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(android.view.ViewGroup.LayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(MarginLayoutParams source) {\n            super(source);\n        }\n\n        @Override\n        public AutoLayoutInfo getAutoLayoutInfo() {\n            return this.mDimenLayoutInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "arms-autolayout/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"AutoTabLayout\">\n        <attr name=\"auto_textSize_base_width\" format=\"boolean\"></attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "arms-autolayout/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">arms-autolayout</string>\n</resources>\n"
  },
  {
    "path": "arms-imageloader-glide/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "arms-imageloader-glide/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.android[\"compileSdkVersion\"]\n    buildToolsVersion rootProject.ext.android[\"buildToolsVersion\"]\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.android[\"minSdkVersion\"]\n        targetSdkVersion rootProject.ext.android[\"targetSdkVersion\"]\n        versionCode rootProject.ext.android[\"versionCode\"]\n        versionName rootProject.ext.android[\"versionName\"]\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    api(rootProject.ext.dependencies[\"glide\"]) {\n        exclude module: 'annotation'\n        exclude module: 'fragment'\n        exclude module: 'vectordrawable-animated'\n    }\n    compileOnly project(':arms')\n}\n\napply from: '../bintray.gradle'"
  },
  {
    "path": "arms-imageloader-glide/gradle.properties",
    "content": "POM_NAME=MVPArms-ImageLoader-Glide\n"
  },
  {
    "path": "arms-imageloader-glide/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "arms-imageloader-glide/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"com.jess.arms.http.imageloader.glide\" />\n"
  },
  {
    "path": "arms-imageloader-glide/src/main/java/com/jess/arms/http/imageloader/glide/BlurTransformation.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader.glide;\n\nimport android.graphics.Bitmap;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\n\nimport com.bumptech.glide.load.Key;\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapTransformation;\nimport com.jess.arms.utils.FastBlur;\n\nimport java.security.MessageDigest;\n\n/**\n * ================================================\n * 高斯模糊\n * <p>\n * Created by JessYan on 03/04/2018 15:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class BlurTransformation extends BitmapTransformation {\n    public static final int DEFAULT_RADIUS = 15;\n    private static final String ID = BlurTransformation.class.getName();\n    private static final byte[] ID_BYTES = ID.getBytes(Key.CHARSET);\n    private int mRadius;\n\n    public BlurTransformation(@IntRange(from = 0) int radius) {\n        mRadius = radius;\n    }\n\n    @Override\n    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {\n        messageDigest.update(ID_BYTES);\n\n    }\n\n    @Override\n    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {\n        return FastBlur.doBlur(toTransform, mRadius, true);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        return o instanceof BlurTransformation;\n    }\n\n    @Override\n    public int hashCode() {\n        return ID.hashCode();\n    }\n}\n"
  },
  {
    "path": "arms-imageloader-glide/src/main/java/com/jess/arms/http/imageloader/glide/CacheStrategy.java",
    "content": "package com.jess.arms.http.imageloader.glide;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n\n/**\n * Incremental change is better than ambitious failure.\n *\n * @author : <a href=\"http://mysticcoder.coding.me\">MysticCoder</a>\n * @date : 2019/4/29\n * @desc :0对应DiskCacheStrategy.all,1对应DiskCacheStrategy.NONE,2对应DiskCacheStrategy.SOURCE,3对应DiskCacheStrategy.RESULT\n * see {@link com.bumptech.glide.load.engine.DiskCacheStrategy}\n */\n\npublic interface CacheStrategy {\n\n\n    int ALL = 0;\n\n    int NONE = 1;\n\n    int RESOURCE = 2;\n\n    int DATA = 3;\n\n    int AUTOMATIC = 4;\n\n    @IntDef({ALL, NONE, RESOURCE, DATA, AUTOMATIC})\n    @Retention(RetentionPolicy.SOURCE)\n    @interface Strategy {\n    }\n\n}"
  },
  {
    "path": "arms-imageloader-glide/src/main/java/com/jess/arms/http/imageloader/glide/GlideImageLoaderStrategy.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader.glide;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.GlideBuilder;\nimport com.bumptech.glide.Registry;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.resource.bitmap.RoundedCorners;\nimport com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\nimport com.jess.arms.http.imageloader.ImageConfig;\nimport com.jess.arms.utils.Preconditions;\n\nimport io.reactivex.Completable;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.functions.Action;\nimport io.reactivex.schedulers.Schedulers;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 此类只是简单的实现了 Glide 加载的策略,方便快速使用,但大部分情况会需要应对复杂的场景\n * 这时可自行实现 {@link BaseImageLoaderStrategy} 和 {@link ImageConfig} 替换现有策略\n *\n * @see GlobalConfigModule.Builder#imageLoaderStrategy(BaseImageLoaderStrategy)\n * Created by JessYan on 8/5/16 16:28\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class GlideImageLoaderStrategy implements BaseImageLoaderStrategy<ImageConfigImpl>, GlideAppliesOptions {\n\n    @Override\n    public void loadImage(@Nullable Context ctx, @Nullable ImageConfigImpl config) {\n        Preconditions.checkNotNull(ctx, \"Context is required\");\n        Preconditions.checkNotNull(config, \"ImageConfigImpl is required\");\n        Preconditions.checkNotNull(config.getImageView(), \"ImageView is required\");\n\n        GlideRequests requests;\n\n        requests = GlideArms.with(ctx);//如果context是activity则自动使用Activity的生命周期\n\n        GlideRequest<Drawable> glideRequest = requests.load(config.getUrl());\n\n        switch (config.getCacheStrategy()) {\n            //缓存策略\n            case CacheStrategy.NONE:\n                glideRequest.diskCacheStrategy(DiskCacheStrategy.NONE);\n                break;\n            case CacheStrategy.RESOURCE:\n                glideRequest.diskCacheStrategy(DiskCacheStrategy.RESOURCE);\n                break;\n            case CacheStrategy.DATA:\n                glideRequest.diskCacheStrategy(DiskCacheStrategy.DATA);\n                break;\n            case CacheStrategy.AUTOMATIC:\n                glideRequest.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC);\n                break;\n            default:\n                glideRequest.diskCacheStrategy(DiskCacheStrategy.ALL);\n                break;\n        }\n\n        if (config.isCrossFade()) {\n            glideRequest.transition(DrawableTransitionOptions.withCrossFade());\n        }\n\n        if (config.isCenterCrop()) {\n            glideRequest.centerCrop();\n        }\n\n        if (config.isCircle()) {\n            glideRequest.circleCrop();\n        }\n\n        if (config.isImageRadius()) {\n            glideRequest.transform(new RoundedCorners(config.getImageRadius()));\n        }\n\n        if (config.isBlurImage()) {\n            glideRequest.transform(new BlurTransformation(config.getBlurValue()));\n        }\n\n        if (config.getTransformation() != null) {//glide用它来改变图形的形状\n            glideRequest.transform(config.getTransformation());\n        }\n\n        if (config.getPlaceholder() != 0)//设置占位符\n        {\n            glideRequest.placeholder(config.getPlaceholder());\n        }\n\n        if (config.getErrorPic() != 0)//设置错误的图片\n        {\n            glideRequest.error(config.getErrorPic());\n        }\n\n        if (config.getFallback() != 0)//设置请求 url 为空图片\n        {\n            glideRequest.fallback(config.getFallback());\n        }\n\n        glideRequest\n                .into(config.getImageView());\n    }\n\n    @Override\n    public void clear(@Nullable final Context ctx, @Nullable ImageConfigImpl config) {\n        Preconditions.checkNotNull(ctx, \"Context is required\");\n        Preconditions.checkNotNull(config, \"ImageConfigImpl is required\");\n\n        if (config.getImageView() != null) {\n            GlideArms.get(ctx).getRequestManagerRetriever().get(ctx).clear(config.getImageView());\n        }\n\n        if (config.getImageViews() != null && config.getImageViews().length > 0) {//取消在执行的任务并且释放资源\n            for (ImageView imageView : config.getImageViews()) {\n                GlideArms.get(ctx).getRequestManagerRetriever().get(ctx).clear(imageView);\n            }\n        }\n\n        if (config.isClearDiskCache()) {//清除本地缓存\n            Completable.fromAction(new Action() {\n                @Override\n                public void run() throws Exception {\n                    Glide.get(ctx).clearDiskCache();\n                }\n            }).subscribeOn(Schedulers.io()).subscribe();\n        }\n\n        if (config.isClearMemory()) {//清除内存缓存\n            Completable.fromAction(new Action() {\n                @Override\n                public void run() throws Exception {\n                    Glide.get(ctx).clearMemory();\n                }\n            }).subscribeOn(AndroidSchedulers.mainThread()).subscribe();\n        }\n    }\n\n    @Override\n    public void applyGlideOptions(@NonNull Context context, @NonNull GlideBuilder builder) {\n        Timber.i(\"applyGlideOptions\");\n    }\n\n    @Override\n    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {\n        Timber.i(\"registerComponents\");\n    }\n}\n"
  },
  {
    "path": "arms-imageloader-glide/src/main/java/com/jess/arms/http/imageloader/glide/ImageConfigImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jess.arms.http.imageloader.glide;\n\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.load.resource.bitmap.BitmapTransformation;\nimport com.jess.arms.http.imageloader.BaseImageLoaderStrategy;\nimport com.jess.arms.http.imageloader.ImageConfig;\nimport com.jess.arms.http.imageloader.ImageLoader;\n\n/**\n * ================================================\n * 这里存放图片请求的配置信息,可以一直扩展字段,如果外部调用时想让图片加载框架\n * 做一些操作,比如清除缓存或者切换缓存策略,则可以定义一个 int 类型的变量,内部根据 switch(int) 做不同的操作\n * 其他操作同理\n * <p>\n * Created by JessYan on 8/5/16 15:19\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ImageConfigImpl extends ImageConfig {\n    private @CacheStrategy.Strategy\n    int cacheStrategy;//0对应DiskCacheStrategy.all,1对应DiskCacheStrategy.NONE,2对应DiskCacheStrategy.SOURCE,3对应DiskCacheStrategy.RESULT\n    private int fallback; //请求 url 为空,则使用此图片作为占位符\n    private int imageRadius;//图片每个圆角的大小\n    private int blurValue;//高斯模糊值, 值越大模糊效果越大\n    /**\n     * @see {@link Builder#transformation(BitmapTransformation)}\n     */\n    @Deprecated\n    private BitmapTransformation transformation;//glide用它来改变图形的形状\n    private ImageView[] imageViews;\n    private boolean isCrossFade;//是否使用淡入淡出过渡动画\n    private boolean isCenterCrop;//是否将图片剪切为 CenterCrop\n    private boolean isCircle;//是否将图片剪切为圆形\n    private boolean isClearMemory;//清理内存缓存\n    private boolean isClearDiskCache;//清理本地缓存\n\n    private ImageConfigImpl(Builder builder) {\n        this.url = builder.url;\n        this.imageView = builder.imageView;\n        this.placeholder = builder.placeholder;\n        this.errorPic = builder.errorPic;\n        this.fallback = builder.fallback;\n        this.cacheStrategy = builder.cacheStrategy;\n        this.imageRadius = builder.imageRadius;\n        this.blurValue = builder.blurValue;\n        this.transformation = builder.transformation;\n        this.imageViews = builder.imageViews;\n        this.isCrossFade = builder.isCrossFade;\n        this.isCenterCrop = builder.isCenterCrop;\n        this.isCircle = builder.isCircle;\n        this.isClearMemory = builder.isClearMemory;\n        this.isClearDiskCache = builder.isClearDiskCache;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public @CacheStrategy.Strategy\n    int getCacheStrategy() {\n        return cacheStrategy;\n    }\n\n    public BitmapTransformation getTransformation() {\n        return transformation;\n    }\n\n    public ImageView[] getImageViews() {\n        return imageViews;\n    }\n\n    public boolean isClearMemory() {\n        return isClearMemory;\n    }\n\n    public boolean isClearDiskCache() {\n        return isClearDiskCache;\n    }\n\n    public int getFallback() {\n        return fallback;\n    }\n\n    public int getBlurValue() {\n        return blurValue;\n    }\n\n    public boolean isBlurImage() {\n        return blurValue > 0;\n    }\n\n    public int getImageRadius() {\n        return imageRadius;\n    }\n\n    public boolean isImageRadius() {\n        return imageRadius > 0;\n    }\n\n    public boolean isCrossFade() {\n        return isCrossFade;\n    }\n\n    public boolean isCenterCrop() {\n        return isCenterCrop;\n    }\n\n    public boolean isCircle() {\n        return isCircle;\n    }\n\n    public static final class Builder {\n        private String url;\n        private ImageView imageView;\n        private int placeholder;\n        private int errorPic;\n        private int fallback; //请求 url 为空,则使用此图片作为占位符\n        private @CacheStrategy.Strategy\n        int cacheStrategy;//0对应DiskCacheStrategy.all,1对应DiskCacheStrategy.NONE,2对应DiskCacheStrategy.SOURCE,3对应DiskCacheStrategy.RESULT\n        private int imageRadius;//图片每个圆角的大小\n        private int blurValue;//高斯模糊值, 值越大模糊效果越大\n        /**\n         * @see {@link Builder#transformation(BitmapTransformation)}\n         */\n        @Deprecated\n        private BitmapTransformation transformation;//glide用它来改变图形的形状\n        private ImageView[] imageViews;\n        private boolean isCrossFade;//是否使用淡入淡出过渡动画\n        private boolean isCenterCrop;//是否将图片剪切为 CenterCrop\n        private boolean isCircle;//是否将图片剪切为圆形\n        private boolean isClearMemory;//清理内存缓存\n        private boolean isClearDiskCache;//清理本地缓存\n\n        private Builder() {\n        }\n\n        public Builder url(String url) {\n            this.url = url;\n            return this;\n        }\n\n        public Builder placeholder(int placeholder) {\n            this.placeholder = placeholder;\n            return this;\n        }\n\n        public Builder errorPic(int errorPic) {\n            this.errorPic = errorPic;\n            return this;\n        }\n\n        public Builder fallback(int fallback) {\n            this.fallback = fallback;\n            return this;\n        }\n\n        public Builder imageView(ImageView imageView) {\n            this.imageView = imageView;\n            return this;\n        }\n\n        public Builder cacheStrategy(@CacheStrategy.Strategy int cacheStrategy) {\n            this.cacheStrategy = cacheStrategy;\n            return this;\n        }\n\n        public Builder imageRadius(int imageRadius) {\n            this.imageRadius = imageRadius;\n            return this;\n        }\n\n        public Builder blurValue(int blurValue) { //blurValue 建议设置为 15\n            this.blurValue = blurValue;\n            return this;\n        }\n\n        /**\n         * 给图片添加 Glide 独有的 BitmapTransformation\n         * <p>\n         * 因为 BitmapTransformation 是 Glide 独有的类, 所以如果 BitmapTransformation 出现在 {@link ImageConfigImpl} 中\n         * 会使 {@link ImageLoader} 难以切换为其他图片加载框架, 在 {@link ImageConfigImpl} 中只能配置基础类型和 Android 包里的类\n         * 此 API 会在后面的版本中被删除, 请使用其他 API 替代\n         *\n         * @param transformation {@link BitmapTransformation}\n         * @deprecated 请使用 {@link #isCircle()}, {@link #isCenterCrop()}, {@link #isImageRadius()} 替代\n         * 如果有其他自定义 BitmapTransformation 的需求, 请自行扩展 {@link BaseImageLoaderStrategy}\n         */\n        @Deprecated\n        public Builder transformation(BitmapTransformation transformation) {\n            this.transformation = transformation;\n            return this;\n        }\n\n        public Builder imageViews(ImageView... imageViews) {\n            this.imageViews = imageViews;\n            return this;\n        }\n\n        public Builder isCrossFade(boolean isCrossFade) {\n            this.isCrossFade = isCrossFade;\n            return this;\n        }\n\n        public Builder isCenterCrop(boolean isCenterCrop) {\n            this.isCenterCrop = isCenterCrop;\n            return this;\n        }\n\n        public Builder isCircle(boolean isCircle) {\n            this.isCircle = isCircle;\n            return this;\n        }\n\n        public Builder isClearMemory(boolean isClearMemory) {\n            this.isClearMemory = isClearMemory;\n            return this;\n        }\n\n        public Builder isClearDiskCache(boolean isClearDiskCache) {\n            this.isClearDiskCache = isClearDiskCache;\n            return this;\n        }\n\n        public ImageConfigImpl build() {\n            return new ImageConfigImpl(this);\n        }\n    }\n}\n"
  },
  {
    "path": "arms-imageloader-glide/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">arms-glide</string>\n</resources>\n"
  },
  {
    "path": "bintray.gradle",
    "content": "apply plugin: 'com.jfrog.bintray'\napply plugin: 'com.github.dcendents.android-maven'\n\nProperties properties = new Properties()\nboolean isHasFile = false\nif (project.rootProject.findProject('local.properties') != null) {\n    isHasFile = true\n    properties.load(project.rootProject.file('local.properties').newDataInputStream())\n}\n\ndef gitUrl = 'https://github.com/JessYanCoding/MVPArms.git'   // Git仓库的url\ndef siteUrl = 'https://github.com/JessYanCoding/MVPArms'   // 项目的主页\n\nversion = rootProject.ext.android[\"versionName\"]\ngroup = \"me.jessyan\"\n\n\nbintray {\n    user = isHasFile ? properties.getProperty(\"bintray.user\") : System.getenv(\"bintray_user\")\n    key = isHasFile ? properties.getProperty(\"bintray.apikey\") : System.getenv(\"bintray_apikey\")\n\n    pkg {\n        repo = 'maven'\n        name = POM_NAME\n        licenses = [\"Apache-2.0\"]\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        publish = true // 是否是公开项目。\n\n        version {\n            name = rootProject.ext.android[\"versionName\"]\n            desc = 'A common Architecture for Android Applications developing based on MVP，integrates many Open Source Projects( like Dagger2,RxJava,Retrofit... ),to make your developing quicker and easier.'\n            released = new Date()\n            vcsTag = 'v' + rootProject.ext.android[\"versionName\"]\n            attributes = ['gradle-plugin': 'com.use.less:com.use.less.gradle:gradle-useless-plugin']\n        }\n    }\n    configurations = ['archives']\n}\n\n\ninstall {\n    repositories.mavenInstaller {\n        // This generates POM.xml with proper parameters\n        pom {\n            project {\n                packaging 'aar'\n                // Add your description here\n                name POM_NAME\n                description 'A common Architecture for Android Applications developing based on MVP，integrates many Open Source Projects( like Dagger2,RxJava,Retrofit... ),to make your developing quicker and easier.'\n                url siteUrl\n                // Set your license\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'JessYanCoding'        //填写bintray或者github的用户名\n                        name 'jessyan'         //姓名，可以是中文\n                        email 'jess.yan.effort@gmail.com'\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\ntask javadoc(type: Javadoc) {\n    failOnError false\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\nartifacts {\n    archives javadocJar\n    archives sourcesJar\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\napply from: \"config.gradle\"\nbuildscript {\n    repositories {\n        google()\n        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.6.0'\n        //Gradle Android Maven plugin\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'\n        //Gradle Bintray Plugin\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0'\n    }\n}\n\nallprojects {\n    tasks.withType(Test).configureEach {\n        maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1\n        if (!project.hasProperty(\"createReports\")) {\n            reports.html.required = false\n            reports.junitXml.required = false\n        }\n    }\n\n    repositories {\n        google()\n        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }\n        maven { url \"https://jitpack.io\" }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\nconfigurations.all {\n    resolutionStrategy {\n        eachDependency { details ->\n            // Force all of the primary libraries to use the same version.\n            if (details.requested.name == 'appcompat'\n                    && details.requested.name == 'annotation'\n                    && details.requested.name == 'recyclerview') {\n                details.useVersion rootProject.ext.version[\"androidXSdkVersion\"]\n            }\n        }\n    }\n}"
  },
  {
    "path": "config.gradle",
    "content": "ext {\n\n    android = [\n            compileSdkVersion: 29,\n            buildToolsVersion: \"29.0.3\",\n            minSdkVersion    : 14,\n            targetSdkVersion : 29,\n            versionCode      : 186,\n            versionName      : \"2.5.2\"\n    ]\n\n    version = [\n            androidSupportSdkVersion: \"28.0.0\",\n            androidXSdkVersion      : \"1.1.0\",\n            retrofitSdkVersion      : \"2.7.2\",\n            dagger2SdkVersion       : \"2.26\",\n            glideSdkVersion         : \"4.11.0\",\n            butterknifeSdkVersion   : \"10.2.1\",\n            rxlifecycleSdkVersion   : \"1.0\",\n            rxlifecycle2SdkVersion  : \"2.2.2\",\n            espressoSdkVersion      : \"3.0.1\",\n            canarySdkVersion        : \"2.2\"\n    ]\n\n    dependencies = [\n            //support\n            \"appcompat-v7\"             : \"com.android.support:appcompat-v7:${version[\"androidSupportSdkVersion\"]}\",\n            \"support-design\"           : \"com.android.support:design:${version[\"androidSupportSdkVersion\"]}\",\n            \"support-v4\"               : \"com.android.support:support-v4:${version[\"androidSupportSdkVersion\"]}\",\n            \"cardview-v7\"              : \"com.android.support:cardview-v7:${version[\"androidSupportSdkVersion\"]}\",\n            \"support-annotations\"      : \"com.android.support:support-annotations:${version[\"androidSupportSdkVersion\"]}\",\n            \"recyclerview-v7\"          : \"com.android.support:recyclerview-v7:${version[\"androidSupportSdkVersion\"]}\",\n\n            //androidx\n            \"appcompat\"                : \"androidx.appcompat:appcompat:${version[\"androidXSdkVersion\"]}\",\n            \"design\"                   : \"com.google.android.material:material:${version[\"androidXSdkVersion\"]}\",\n            \"legacy-support-v4\"        : \"androidx.legacy:legacy-support-v4:1.0.0\",\n            \"cardview\"                 : \"androidx.cardview:cardview:1.0.0\",\n            \"annotations\"              : \"androidx.annotation:annotation:${version[\"androidXSdkVersion\"]}\",\n            \"recyclerview\"             : \"androidx.recyclerview:recyclerview:${version[\"androidXSdkVersion\"]}\",\n\n            //network\n            \"retrofit\"                 : \"com.squareup.retrofit2:retrofit:${version[\"retrofitSdkVersion\"]}\",\n            \"retrofit-converter-gson\"  : \"com.squareup.retrofit2:converter-gson:${version[\"retrofitSdkVersion\"]}\",\n            \"retrofit-adapter-rxjava\"  : \"com.squareup.retrofit2:adapter-rxjava:${version[\"retrofitSdkVersion\"]}\",\n            \"retrofit-adapter-rxjava2\" : \"com.squareup.retrofit2:adapter-rxjava2:${version[\"retrofitSdkVersion\"]}\",\n            \"okhttp3\"                  : \"com.squareup.okhttp3:okhttp:3.12.9\",\n            \"okhttp4\"                  : \"com.squareup.okhttp3:okhttp:4.0.0\",\n            \"okhttp-urlconnection\"     : \"com.squareup.okhttp:okhttp-urlconnection:2.0.0\",\n            \"glide\"                    : \"com.github.bumptech.glide:glide:${version[\"glideSdkVersion\"]}\",\n            \"glide-compiler\"           : \"com.github.bumptech.glide:compiler:${version[\"glideSdkVersion\"]}\",\n            \"glide-loader-okhttp3\"     : \"com.github.bumptech.glide:okhttp3-integration:${version[\"glideSdkVersion\"]}\",\n            \"picasso\"                  : \"com.squareup.picasso:picasso:2.5.2\",\n\n            //view\n            \"autolayout\"               : \"com.zhy:autolayout:1.4.5\",\n            \"butterknife\"              : \"com.jakewharton:butterknife:${version[\"butterknifeSdkVersion\"]}\",\n            \"butterknife-compiler\"     : \"com.jakewharton:butterknife-compiler:${version[\"butterknifeSdkVersion\"]}\",\n            \"pickerview\"               : \"com.contrarywind:Android-PickerView:3.2.5\",\n            \"photoview\"                : \"com.github.chrisbanes.photoview:library:1.2.3\",\n            \"numberprogressbar\"        : \"com.daimajia.numberprogressbar:library:1.2@aar\",\n            \"nineoldandroids\"          : \"com.nineoldandroids:library:2.4.0\",\n            \"paginate\"                 : \"com.github.markomilos:paginate:0.5.1\",\n            \"vlayout\"                  : \"com.alibaba.android:vlayout:1.1.0@aar\",\n            \"autosize\"                 : \"me.jessyan:autosize:1.2.1\",\n\n            //rx1\n            \"rxandroid\"                : \"io.reactivex:rxandroid:1.2.1\",\n            \"rxjava\"                   : \"io.reactivex:rxjava:1.3.0\",\n            \"rxlifecycle\"              : \"com.trello:rxlifecycle:${version[\"rxlifecycleSdkVersion\"]}\",\n            \"rxlifecycle-components\"   : \"com.trello:rxlifecycle-components:${version[\"rxlifecycleSdkVersion\"]}\",\n            \"rxcache\"                  : \"com.github.VictorAlbertos.RxCache:runtime:1.7.0-1.x\",\n            \"rxcache-jolyglot-gson\"    : \"com.github.VictorAlbertos.Jolyglot:gson:0.0.4\",\n            \"rxbinding-recyclerview-v7\": \"com.jakewharton.rxbinding:rxbinding-recyclerview-v7:1.0.1\",\n            \"rxpermissions\"            : \"com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar\",\n            \"rxerrorhandler\"           : \"me.jessyan:rxerrorhandler:1.0.1\",\n\n            //rx2\n            \"rxandroid2\"               : \"io.reactivex.rxjava2:rxandroid:2.1.1\",\n            \"rxjava2\"                  : \"io.reactivex.rxjava2:rxjava:2.2.18\",\n            \"rxlifecycle2\"             : \"com.trello.rxlifecycle2:rxlifecycle:${version[\"rxlifecycle2SdkVersion\"]}\",\n            \"rxlifecycle2-android\"     : \"com.trello.rxlifecycle2:rxlifecycle-android:${version[\"rxlifecycle2SdkVersion\"]}\",\n            \"rxlifecycle2-components\"  : \"com.trello.rxlifecycle2:rxlifecycle-components:${version[\"rxlifecycle2SdkVersion\"]}\",\n            \"rxcache2\"                 : \"com.github.VictorAlbertos.RxCache:runtime:1.8.3-2.x\",\n            \"rxpermissions2\"           : \"com.github.tbruyelle:rxpermissions:0.10.2\",\n            \"rxerrorhandler2\"          : \"me.jessyan:rxerrorhandler:2.1.1\",\n\n            //tools\n            \"dagger2\"                  : \"com.google.dagger:dagger:${version[\"dagger2SdkVersion\"]}\",\n            \"dagger2-android\"          : \"com.google.dagger:dagger-android:${version[\"dagger2SdkVersion\"]}\",\n            \"dagger2-android-support\"  : \"com.google.dagger:dagger-android-support:${version[\"dagger2SdkVersion\"]}\",\n            \"dagger2-compiler\"         : \"com.google.dagger:dagger-compiler:${version[\"dagger2SdkVersion\"]}\",\n            \"dagger2-android-processor\": \"com.google.dagger:dagger-android-processor:${version[\"dagger2SdkVersion\"]}\",\n            \"androideventbus\"          : \"org.simple:androideventbus:1.0.5.1\",\n            \"eventbus\"                 : \"org.greenrobot:eventbus:3.2.0\",\n            \"otto\"                     : \"com.squareup:otto:1.3.8\",\n            \"gson\"                     : \"com.google.code.gson:gson:2.8.6\",\n            \"multidex\"                 : \"com.android.support:multidex:1.0.3\",\n            \"javax.annotation\"         : \"javax.annotation:jsr250-api:1.0\",\n            \"arouter\"                  : \"com.alibaba:arouter-api:1.3.1\",\n            \"arouter-compiler\"         : \"com.alibaba:arouter-compiler:1.1.4\",\n            \"progressmanager\"          : \"me.jessyan:progressmanager:1.5.0\",\n            \"retrofit-url-manager\"     : \"me.jessyan:retrofit-url-manager:1.4.0\",\n            \"lifecyclemodel\"           : \"me.jessyan:lifecyclemodel:1.0.1\",\n\n            //test\n            \"junit\"                    : \"junit:junit:4.12\",\n            \"androidJUnitRunner\"       : \"androidx.test.runner.AndroidJUnitRunner\",\n            \"runner\"                   : \"com.android.support.test:runner:1.0.1\",\n            \"espresso-core\"            : \"com.android.support.test.espresso:espresso-core:${version[\"espressoSdkVersion\"]}\",\n            \"espresso-contrib\"         : \"com.android.support.test.espresso:espresso-contrib:${version[\"espressoSdkVersion\"]}\",\n            \"espresso-intents\"         : \"com.android.support.test.espresso:espresso-intents:${version[\"espressoSdkVersion\"]}\",\n            \"mockito-core\"             : \"org.mockito:mockito-core:1.+\",\n            \"timber\"                   : \"com.jakewharton.timber:timber:4.7.1\",\n            \"logger\"                   : \"com.orhanobut:logger:2.2.0\",\n            \"canary-debug\"             : \"com.squareup.leakcanary:leakcanary-android:${version[\"canarySdkVersion\"]}\",\n            \"canary-release\"           : \"com.squareup.leakcanary:leakcanary-android-no-op:1.6.3\",\n            \"umeng-analytics\"          : \"com.umeng.analytics:analytics:6.0.1\"\n    ]\n}\n"
  },
  {
    "path": "demo/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "demo/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.ext.android[\"compileSdkVersion\"]\n    buildToolsVersion rootProject.ext.android[\"buildToolsVersion\"]\n    useLibrary 'org.apache.http.legacy'\n\n    compileOptions {\n        targetCompatibility JavaVersion.VERSION_1_8\n        sourceCompatibility JavaVersion.VERSION_1_8\n    }\n\n    defaultConfig {\n        applicationId \"me.jessyan.mvparms.demo\"\n        minSdkVersion rootProject.ext.android[\"minSdkVersion\"]\n        targetSdkVersion rootProject.ext.android[\"targetSdkVersion\"]\n        versionCode rootProject.ext.android[\"versionCode\"]\n        versionName rootProject.ext.android[\"versionName\"]\n        testInstrumentationRunner rootProject.ext.dependencies[\"androidJUnitRunner\"]\n    }\n\n    buildTypes {\n        debug {\n            buildConfigField \"boolean\", \"LOG_DEBUG\", \"true\"\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n\n        release {\n            buildConfigField \"boolean\", \"LOG_DEBUG\", \"false\"\n            minifyEnabled true\n            shrinkResources true\n            zipAlignEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    lintOptions {\n        disable 'InvalidPackage'\n        disable \"ResourceType\"\n        abortOnError false\n    }\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n\n    //androidx\n    implementation rootProject.ext.dependencies[\"cardview\"]\n\n    //tools\n    //注意 Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n    //现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n    //依赖后 Arms 会自动检测您依赖的 EventBus 并自动注册\n    //建议使用 AndroidEventBus, 特别是组件化项目, 原因请看 https://github.com/hehonghui/AndroidEventBus/issues/49\n    //这种做法可以让使用者有自行选择三方库的权利, 并且还可以减轻 Arms 的体积\n    implementation rootProject.ext.dependencies[\"androideventbus\"]\n//    implementation rootProject.ext.dependencies[\"eventbus\"]\n\n    annotationProcessor rootProject.ext.dependencies[\"dagger2-compiler\"]\n    implementation rootProject.ext.dependencies[\"progressmanager\"]\n    implementation rootProject.ext.dependencies[\"retrofit-url-manager\"]\n    implementation rootProject.ext.dependencies[\"lifecyclemodel\"]\n\n    //view\n    annotationProcessor(rootProject.ext.dependencies[\"butterknife-compiler\"]) {\n        exclude module: 'annotation'\n    }\n    implementation(rootProject.ext.dependencies[\"paginate\"]) {\n        exclude module: 'recyclerview'\n    }\n\n    //arms\n    implementation project(':arms')\n//    implementation 'me.jessyan:arms:2.5.2'\n\n    //Arms 核心库不再包含 AndroidAutoLayout, 现在可自行选择屏幕适配方案, 不想使用 AndroidAutoLayout 就不要依赖 arms-autolayout\n//    implementation 'me.jessyan:arms-autolayout:2.5.2'\n\n    //现在已经将 Demo 中的屏幕适配框架从 AndroidAutoLayout 替换为 AndroidAutoSize, AndroidAutoLayout 和 AndroidAutoSize 可以在项目中共存\n    //所以旧项目只要依赖 arms-autolayout 即可兼容之前的旧页面, 新页面可以使用 AndroidAutoSize 进行适配, 等有时间了再将旧页面全部替换为 AndroidAutoSize\n    implementation rootProject.ext.dependencies[\"autosize\"]\n\n    //Arms 核心库不再包含 Glide, 想使用其他图片加载框架或者想自行扩展 ImageLoaderStrategy 就不要依赖 arms-imageloader-glide\n    //依赖 arms-imageloader-glide 后还需要在 GlobalConfiguration 中手动注册 GlideImageLoaderStrategy\n//    implementation 'me.jessyan:arms-imageloader-glide:2.5.2'\n    implementation project(':arms-imageloader-glide')\n\n    //test\n    testImplementation rootProject.ext.dependencies[\"junit\"]\n    debugImplementation rootProject.ext.dependencies[\"canary-debug\"]\n}\n"
  },
  {
    "path": "demo/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/jess/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# 混淆规则在 arms moudule 下的 proguard-rules.pro 中, 混淆前先参阅 https://github.com/JessYanCoding/MVPArms/wiki#1.5"
  },
  {
    "path": "demo/src/androidTest/java/me/jessyan/mvparms/demo/ApplicationTest.java",
    "content": "package me.jessyan.mvparms.demo;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "demo/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"me.jessyan.mvparms.demo\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n\n    <application\n        android:name=\"com.jess.arms.base.BaseApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/arms_logo\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:ignore=\"AllowBackup,GoogleAppIndexingWarning\">\n        <activity android:name=\".mvp.ui.activity.UserActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <!-- 只要依赖 AutoSize 就必须填写设计图尺寸, 否则报错, 不想使用 AutoSize 就不要依赖 AutoSize\n        只要填写完设计图的尺寸, AutoSize 就会自动启动, 以下 dp 尺寸是根据公式 px / (dpi / 160) 求出, 运算时使用测试机的 dpi 即可\n        AutoSize 的详细介绍请看这里 https://juejin.im/post/5bce688e6fb9a05cf715d1c2\n        -->\n        <meta-data\n            android:name=\"design_width_in_dp\"\n            android:value=\"360\" />\n        <meta-data\n            android:name=\"design_height_in_dp\"\n            android:value=\"640\" />\n\n        <!-- Arms 配置 -->\n        <meta-data\n            android:name=\"me.jessyan.mvparms.demo.app.GlobalConfiguration\"\n            android:value=\"ConfigModule\" />\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/ActivityLifecycleCallbacksImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport java.util.Objects;\n\nimport me.jessyan.mvparms.demo.R;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 {@link Application.ActivityLifecycleCallbacks} 的用法\n * <p>\n * Created by JessYan on 04/09/2017 17:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ActivityLifecycleCallbacksImpl implements Application.ActivityLifecycleCallbacks {\n\n    @Override\n    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {\n        Timber.i(\"%s - onActivityCreated\", activity);\n    }\n\n    @Override\n    public void onActivityStarted(Activity activity) {\n        Timber.i(\"%s - onActivityStarted\", activity);\n        if (!activity.getIntent().getBooleanExtra(\"isInitToolbar\", false)) {\n            //由于加强框架的兼容性,故将 setContentView 放到 onActivityCreated 之后,onActivityStarted 之前执行\n            //而 findViewById 必须在 Activity setContentView() 后才有效,所以将以下代码从之前的 onActivityCreated 中移动到 onActivityStarted 中执行\n            activity.getIntent().putExtra(\"isInitToolbar\", true);\n            //这里全局给Activity设置toolbar和title,你想象力有多丰富,这里就有多强大,以前放到BaseActivity的操作都可以放到这里\n            if (activity.findViewById(R.id.toolbar) != null) {\n                if (activity instanceof AppCompatActivity) {\n                    ((AppCompatActivity) activity).setSupportActionBar(activity.findViewById(R.id.toolbar));\n                    Objects.requireNonNull(((AppCompatActivity) activity).getSupportActionBar()).setDisplayShowTitleEnabled(false);\n                } else {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                        activity.setActionBar(activity.findViewById(R.id.toolbar));\n                        Objects.requireNonNull(activity.getActionBar()).setDisplayShowTitleEnabled(false);\n                    }\n                }\n            }\n            if (activity.findViewById(R.id.toolbar_title) != null) {\n                ((TextView) activity.findViewById(R.id.toolbar_title)).setText(activity.getTitle());\n            }\n            if (activity.findViewById(R.id.toolbar_back) != null) {\n                activity.findViewById(R.id.toolbar_back).setOnClickListener(v -> activity.onBackPressed());\n            }\n        }\n    }\n\n    @Override\n    public void onActivityResumed(Activity activity) {\n        Timber.i(\"%s - onActivityResumed\", activity);\n    }\n\n    @Override\n    public void onActivityPaused(Activity activity) {\n        Timber.i(\"%s - onActivityPaused\", activity);\n    }\n\n    @Override\n    public void onActivityStopped(Activity activity) {\n        Timber.i(\"%s - onActivityStopped\", activity);\n    }\n\n    @Override\n    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {\n        Timber.i(\"%s - onActivitySaveInstanceState\", activity);\n    }\n\n    @Override\n    public void onActivityDestroyed(Activity activity) {\n        Timber.i(\"%s - onActivityDestroyed\", activity);\n        //横竖屏切换或配置改变时, Activity 会被重新创建实例, 但 Bundle 中的基础数据会被保存下来,移除该数据是为了保证重新创建的实例可以正常工作\n        activity.getIntent().removeExtra(\"isInitToolbar\");\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/AppLifecyclesImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport com.jess.arms.base.delegate.AppLifecycles;\n\nimport androidx.annotation.NonNull;\nimport butterknife.ButterKnife;\nimport me.jessyan.mvparms.demo.BuildConfig;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 {@link AppLifecycles} 的用法\n * <p>\n * Created by JessYan on 04/09/2017 17:12\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class AppLifecyclesImpl implements AppLifecycles {\n\n    @Override\n    public void attachBaseContext(@NonNull Context base) {\n//          MultiDex.install(base);  //这里比 onCreate 先执行,常用于 MultiDex 初始化,插件化框架的初始化\n    }\n\n    @Override\n    public void onCreate(@NonNull Application application) {\n        if (BuildConfig.LOG_DEBUG) {//Timber初始化\n            //Timber 是一个日志框架容器,外部使用统一的Api,内部可以动态的切换成任何日志框架(打印策略)进行日志打印\n            //并且支持添加多个日志框架(打印策略),做到外部调用一次 Api,内部却可以做到同时使用多个策略\n            //比如添加三个策略,一个打印日志,一个将日志保存本地,一个将日志上传服务器\n            Timber.plant(new Timber.DebugTree());\n            // 如果你想将框架切换为 Logger 来打印日志,请使用下面的代码,如想切换为其他日志框架请根据下面的方式扩展\n//                    Logger.addLogAdapter(new AndroidLogAdapter());\n//                    Timber.plant(new Timber.DebugTree() {\n//                        @Override\n//                        protected void log(int priority, String tag, String message, Throwable t) {\n//                            Logger.log(priority, tag, message, t);\n//                        }\n//                    });\n            ButterKnife.setDebug(true);\n        }\n        //LeakCanary v2.0+ 版本会自动完成框架的初始化, 以及对 Activity#onDestroy、Fragment#onDestroy、Fragment#onDestroyView 的监听\n        //原理和 AndroidAutoSize 一致, 所以注释掉下面 v1.0 的初始化代码\n        //使用 IntelligentCache.KEY_KEEP 作为 key 的前缀, 可以使储存的数据永久存储在内存中\n        //否则存储在 LRU 算法的存储空间中, 前提是 extras 使用的是 IntelligentCache (框架默认使用)\n//        ArmsUtils.obtainAppComponentFromContext(application).extras()\n//                .put(IntelligentCache.getKeyOfKeep(RefWatcher.class.getName())\n//                        , BuildConfig.USE_CANARY ? LeakCanary.install(application) : RefWatcher.DISABLED);\n    }\n\n    @Override\n    public void onTerminate(@NonNull Application application) {\n\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/EventBusTags.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\n/**\n * ================================================\n * 放置 AndroidEventBus 的 Tag, 便于检索\n * Arms 核心库现在并不会依赖某个 EventBus, 要想使用 EventBus, 还请在项目中自行依赖对应的 EventBus\n * 现在支持两种 EventBus, greenrobot 的 EventBus 和畅销书 《Android源码设计模式解析与实战》的作者 何红辉 所作的 AndroidEventBus\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#3.5\">EventBusTags wiki 官方文档</a>\n * Created by JessYan on 8/30/2016 16:39\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface EventBusTags {\n\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/FragmentLifecycleCallbacksImpl.java",
    "content": "/*\n * Copyright 2018 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 {@link FragmentManager.FragmentLifecycleCallbacks} 的用法\n * <p>\n * Created by JessYan on 23/08/2018 17:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class FragmentLifecycleCallbacksImpl extends FragmentManager.FragmentLifecycleCallbacks {\n\n    @Override\n    public void onFragmentAttached(@NotNull @NonNull FragmentManager fm, Fragment f, @NotNull Context context) {\n        Timber.i(\"%s - onFragmentAttached\", f.toString());\n    }\n\n    @Override\n    public void onFragmentCreated(@NotNull FragmentManager fm, Fragment f, Bundle savedInstanceState) {\n        Timber.i(\"%s - onFragmentCreated\", f.toString());\n        // 在配置变化的时候将这个 Fragment 保存下来,在 Activity 由于配置变化重建时重复利用已经创建的 Fragment。\n        // https://developer.android.com/reference/android/app/Fragment.html?hl=zh-cn#setRetainInstance(boolean)\n        // 如果在 XML 中使用 <Fragment/> 标签,的方式创建 Fragment 请务必在标签中加上 android:id 或者 android:tag 属性,否则 setRetainInstance(true) 无效\n        // 在 Activity 中绑定少量的 Fragment 建议这样做,如果需要绑定较多的 Fragment 不建议设置此参数,如 ViewPager 需要展示较多 Fragment\n        f.setRetainInstance(true);\n    }\n\n    @Override\n    public void onFragmentViewCreated(@NotNull FragmentManager fm, Fragment f, @NotNull View v, Bundle savedInstanceState) {\n        Timber.i(\"%s - onFragmentViewCreated\", f.toString());\n    }\n\n    @Override\n    public void onFragmentActivityCreated(@NotNull FragmentManager fm, Fragment f, Bundle savedInstanceState) {\n        Timber.i(\"%s - onFragmentActivityCreated\", f.toString());\n    }\n\n    @Override\n    public void onFragmentStarted(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentStarted\", f.toString());\n    }\n\n    @Override\n    public void onFragmentResumed(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentResumed\", f.toString());\n    }\n\n    @Override\n    public void onFragmentPaused(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentPaused\", f.toString());\n    }\n\n    @Override\n    public void onFragmentStopped(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentStopped\", f.toString());\n    }\n\n    @Override\n    public void onFragmentSaveInstanceState(@NotNull FragmentManager fm, Fragment f, @NotNull Bundle outState) {\n        Timber.i(\"%s - onFragmentSaveInstanceState\", f.toString());\n    }\n\n    @Override\n    public void onFragmentViewDestroyed(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentViewDestroyed\", f.toString());\n    }\n\n    @Override\n    public void onFragmentDestroyed(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentDestroyed\", f.toString());\n    }\n\n    @Override\n    public void onFragmentDetached(@NotNull FragmentManager fm, Fragment f) {\n        Timber.i(\"%s - onFragmentDetached\", f.toString());\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/GlobalConfiguration.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.FragmentManager;\n\nimport com.jess.arms.base.delegate.AppLifecycles;\nimport com.jess.arms.di.module.GlobalConfigModule;\nimport com.jess.arms.http.imageloader.glide.GlideImageLoaderStrategy;\nimport com.jess.arms.http.log.RequestInterceptor;\nimport com.jess.arms.integration.ConfigModule;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport me.jessyan.mvparms.demo.BuildConfig;\nimport me.jessyan.mvparms.demo.mvp.model.api.Api;\nimport me.jessyan.progressmanager.ProgressManager;\nimport me.jessyan.retrofiturlmanager.RetrofitUrlManager;\n\n/**\n * ================================================\n * App 的全局配置信息在此配置, 需要将此实现类声明到 AndroidManifest 中\n * ConfigModule 的实现类可以有无数多个, 在 Application 中只是注册回调, 并不会影响性能 (多个 ConfigModule 在多 Module 环境下尤为受用)\n * ConfigModule 接口的实现类对象是通过反射生成的, 这里会有些性能损耗\n *\n * @see com.jess.arms.base.delegate.AppDelegate\n * @see com.jess.arms.integration.ManifestParser\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki\">请配合官方 Wiki 文档学习本框架</a>\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog\">更新日志, 升级必看!</a>\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki/Issues\">常见 Issues, 踩坑必看!</a>\n * @see <a href=\"https://github.com/JessYanCoding/ArmsComponent/wiki\">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>\n * Created by JessYan on 12/04/2017 17:25\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic final class GlobalConfiguration implements ConfigModule {\n//    public static String sDomain = Api.APP_DOMAIN;\n\n    @Override\n    public void applyOptions(@NonNull Context context, @NonNull GlobalConfigModule.Builder builder) {\n        if (!BuildConfig.LOG_DEBUG) { //Release 时, 让框架不再打印 Http 请求和响应的信息\n            builder.printHttpLogLevel(RequestInterceptor.Level.NONE);\n        }\n\n        builder.baseurl(Api.APP_DOMAIN)\n                //强烈建议自己自定义图片加载逻辑, 因为 arms-imageloader-glide 提供的 GlideImageLoaderStrategy 并不能满足复杂的需求\n                //请参考 https://github.com/JessYanCoding/MVPArms/wiki#3.4\n                .imageLoaderStrategy(new GlideImageLoaderStrategy())\n\n                //想支持多 BaseUrl, 以及运行时动态切换任意一个 BaseUrl, 请使用 https://github.com/JessYanCoding/RetrofitUrlManager\n                //如果 BaseUrl 在 App 启动时不能确定, 需要请求服务器接口动态获取, 请使用以下代码\n                //以下方式是 Arms 框架自带的切换 BaseUrl 的方式, 在整个 App 生命周期内只能切换一次, 若需要无限次的切换 BaseUrl, 以及各种复杂的应用场景还是需要使用 RetrofitUrlManager 框架\n                //以下代码只是配置, 还要使用 Okhttp (AppComponent 中提供) 请求服务器获取到正确的 BaseUrl 后赋值给 GlobalConfiguration.sDomain\n                //切记整个过程必须在第一次调用 Retrofit 接口之前完成, 如果已经调用过 Retrofit 接口, 此种方式将不能切换 BaseUrl\n//                .baseurl(new BaseUrl() {\n//                    @Override\n//                    public HttpUrl url() {\n//                        return HttpUrl.parse(sDomain);\n//                    }\n//                })\n\n                //可根据当前项目的情况以及环境为框架某些部件提供自定义的缓存策略, 具有强大的扩展性\n//                .cacheFactory(new Cache.Factory() {\n//                    @NonNull\n//                    @Override\n//                    public Cache build(CacheType type) {\n//                        switch (type.getCacheTypeId()){\n//                            case CacheType.EXTRAS_TYPE_ID:\n//                                return new IntelligentCache(500);\n//                            case CacheType.CACHE_SERVICE_CACHE_TYPE_ID:\n//                                return new Cache(type.calculateCacheSize(context));//自定义 Cache\n//                            default:\n//                                return new LruCache(200);\n//                        }\n//                    }\n//                })\n\n                //若觉得框架默认的打印格式并不能满足自己的需求, 可自行扩展自己理想的打印格式 (以下只是简单实现)\n//                .formatPrinter(new FormatPrinter() {\n//                    @Override\n//                    public void printJsonRequest(Request request, String bodyString) {\n//                        Timber.i(\"printJsonRequest:\" + bodyString);\n//                    }\n//\n//                    @Override\n//                    public void printFileRequest(Request request) {\n//                        Timber.i(\"printFileRequest:\" + request.url().toString());\n//                    }\n//\n//                    @Override\n//                    public void printJsonResponse(long chainMs, boolean isSuccessful, int code,\n//                                                  String headers, MediaType contentType, String bodyString,\n//                                                  List<String> segments, String message, String responseUrl) {\n//                        Timber.i(\"printJsonResponse:\" + bodyString);\n//                    }\n//\n//                    @Override\n//                    public void printFileResponse(long chainMs, boolean isSuccessful, int code, String headers,\n//                                                  List<String> segments, String message, String responseUrl) {\n//                        Timber.i(\"printFileResponse:\" + responseUrl);\n//                    }\n//                })\n\n                //可以自定义一个单例的线程池供全局使用\n//                .executorService(Executors.newCachedThreadPool())\n\n                //这里提供一个全局处理 Http 请求和响应结果的处理类, 可以比客户端提前一步拿到服务器返回的结果, 可以做一些操作, 比如 Token 超时后, 重新获取 Token\n                .globalHttpHandler(new GlobalHttpHandlerImpl(context))\n                //用来处理 RxJava 中发生的所有错误, RxJava 中发生的每个错误都会回调此接口\n                //RxJava 必须要使用 ErrorHandleSubscriber (默认实现 Subscriber 的 onError 方法), 此监听才生效\n                .responseErrorListener(new ResponseErrorListenerImpl())\n                .gsonConfiguration((context1, gsonBuilder) -> {//这里可以自己自定义配置 Gson 的参数\n                    gsonBuilder\n                            .serializeNulls()//支持序列化值为 null 的参数\n                            .enableComplexMapKeySerialization();//支持将序列化 key 为 Object 的 Map, 默认只能序列化 key 为 String 的 Map\n                })\n                .retrofitConfiguration((context1, retrofitBuilder) -> {//这里可以自己自定义配置 Retrofit 的参数, 甚至您可以替换框架配置好的 OkHttpClient 对象 (但是不建议这样做, 这样做您将损失框架提供的很多功能)\n//                    retrofitBuilder.addConverterFactory(FastJsonConverterFactory.create());//比如使用 FastJson 替代 Gson\n                })\n                .okhttpConfiguration((context1, okhttpBuilder) -> {//这里可以自己自定义配置 Okhttp 的参数\n//                    okhttpBuilder.sslSocketFactory(); //支持 Https, 详情请百度\n                    okhttpBuilder.writeTimeout(10, TimeUnit.SECONDS);\n                    //使用一行代码监听 Retrofit／Okhttp 上传下载进度监听,以及 Glide 加载进度监听, 详细使用方法请查看 https://github.com/JessYanCoding/ProgressManager\n                    ProgressManager.getInstance().with(okhttpBuilder);\n                    //让 Retrofit 同时支持多个 BaseUrl 以及动态改变 BaseUrl, 详细使用方法请查看 https://github.com/JessYanCoding/RetrofitUrlManager\n                    RetrofitUrlManager.getInstance().with(okhttpBuilder);\n                })\n                .rxCacheConfiguration((context1, rxCacheBuilder) -> {//这里可以自己自定义配置 RxCache 的参数\n                    rxCacheBuilder.useExpiredDataIfLoaderNotAvailable(true);\n                    //想自定义 RxCache 的缓存文件夹或者解析方式, 如改成 FastJson, 请 return rxCacheBuilder.persistence(cacheDirectory, new FastJsonSpeaker());\n                    //否则请 return null;\n                    return null;\n                });\n    }\n\n    @Override\n    public void injectAppLifecycle(@NonNull Context context, @NonNull List<AppLifecycles> lifecycles) {\n        //AppLifecycles 中的所有方法都会在基类 Application 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑\n        //可以根据不同的逻辑添加多个实现类\n        lifecycles.add(new AppLifecyclesImpl());\n    }\n\n    @Override\n    public void injectActivityLifecycle(@NonNull Context context, @NonNull List<Application.ActivityLifecycleCallbacks> lifecycles) {\n        //ActivityLifecycleCallbacks 中的所有方法都会在 Activity (包括三方库) 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑\n        //可以根据不同的逻辑添加多个实现类\n        lifecycles.add(new ActivityLifecycleCallbacksImpl());\n    }\n\n    @Override\n    public void injectFragmentLifecycle(@NonNull Context context, @NonNull List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {\n        //FragmentLifecycleCallbacks 中的所有方法都会在 Fragment (包括三方库) 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑\n        //可以根据不同的逻辑添加多个实现类\n        lifecycles.add(new FragmentLifecycleCallbacksImpl());\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/GlobalHttpHandlerImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.gson.reflect.TypeToken;\nimport com.jess.arms.http.GlobalHttpHandler;\nimport com.jess.arms.http.log.RequestInterceptor;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport java.util.List;\n\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport okhttp3.Interceptor;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 {@link GlobalHttpHandler} 的用法\n * <p>\n * Created by JessYan on 04/09/2017 17:06\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class GlobalHttpHandlerImpl implements GlobalHttpHandler {\n    private Context context;\n\n    public GlobalHttpHandlerImpl(Context context) {\n        this.context = context;\n    }\n\n    /**\n     * 这里可以先客户端一步拿到每一次 Http 请求的结果, 可以先解析成 Json, 再做一些操作, 如检测到 token 过期后\n     * 重新请求 token, 并重新执行请求\n     *\n     * @param httpResult 服务器返回的结果 (已被框架自动转换为字符串)\n     * @param chain      {@link okhttp3.Interceptor.Chain}\n     * @param response   {@link Response}\n     * @return {@link Response}\n     */\n    @NonNull\n    @Override\n    public Response onHttpResultResponse(@Nullable String httpResult, @NonNull Interceptor.Chain chain, @NonNull Response response) {\n        if (!TextUtils.isEmpty(httpResult) && RequestInterceptor.isJson(response.body().contentType())) {\n            try {\n                List<User> list = ArmsUtils.obtainAppComponentFromContext(context).gson().fromJson(httpResult, new TypeToken<List<User>>() {\n                }.getType());\n                User user = list.get(0);\n                Timber.w(\"Result ------> \" + user.getLogin() + \"    ||   Avatar_url------> \" + user.getAvatarUrl());\n            } catch (Exception e) {\n                e.printStackTrace();\n                return response;\n            }\n        }\n\n        /* 这里如果发现 token 过期, 可以先请求最新的 token, 然后在拿新的 token 放入 Request 里去重新请求\n        注意在这个回调之前已经调用过 proceed(), 所以这里必须自己去建立网络请求, 如使用 Okhttp 使用新的 Request 去请求\n        create a new request and modify it accordingly using the new token\n        Request newRequest = chain.request().newBuilder().header(\"token\", newToken)\n                             .build();\n\n        retry the request\n\n        response.body().close();\n        如果使用 Okhttp 将新的请求, 请求成功后, 再将 Okhttp 返回的 Response return 出去即可\n        如果不需要返回新的结果, 则直接把参数 response 返回出去即可*/\n        return response;\n    }\n\n    /**\n     * 这里可以在请求服务器之前拿到 {@link Request}, 做一些操作比如给 {@link Request} 统一添加 token 或者 header 以及参数加密等操作\n     *\n     * @param chain   {@link okhttp3.Interceptor.Chain}\n     * @param request {@link Request}\n     * @return {@link Request}\n     */\n    @NonNull\n    @Override\n    public Request onHttpRequestBefore(@NonNull Interceptor.Chain chain, @NonNull Request request) {\n        /* 如果需要在请求服务器之前做一些操作, 则重新构建一个做过操作的 Request 并 return, 如增加 Header、Params 等请求信息, 不做操作则直接返回参数 request\n        return chain.request().newBuilder().header(\"token\", tokenId)\n                              .build(); */\n        return request;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/ResponseErrorListenerImpl.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app;\n\nimport android.content.Context;\nimport android.net.ParseException;\n\nimport com.google.gson.JsonIOException;\nimport com.google.gson.JsonParseException;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport org.json.JSONException;\n\nimport java.net.SocketTimeoutException;\nimport java.net.UnknownHostException;\n\nimport me.jessyan.rxerrorhandler.handler.listener.ResponseErrorListener;\nimport retrofit2.HttpException;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 {@link ResponseErrorListener} 的用法\n * <p>\n * Created by JessYan on 04/09/2017 17:18\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class ResponseErrorListenerImpl implements ResponseErrorListener {\n\n    @Override\n    public void handleResponseError(Context context, Throwable t) {\n        Timber.tag(\"Catch-Error\").w(t);\n        //这里不光只能打印错误, 还可以根据不同的错误做出不同的逻辑处理\n        //这里只是对几个常用错误进行简单的处理, 展示这个类的用法, 在实际开发中请您自行对更多错误进行更严谨的处理\n        String msg = \"未知错误\";\n        if (t instanceof UnknownHostException) {\n            msg = \"网络不可用\";\n        } else if (t instanceof SocketTimeoutException) {\n            msg = \"请求网络超时\";\n        } else if (t instanceof HttpException) {\n            HttpException httpException = (HttpException) t;\n            msg = convertStatusCode(httpException);\n        } else if (t instanceof JsonParseException || t instanceof ParseException || t instanceof JSONException || t instanceof JsonIOException) {\n            msg = \"数据解析错误\";\n        }\n        ArmsUtils.snackbarText(msg);\n    }\n\n    private String convertStatusCode(HttpException httpException) {\n        String msg;\n        if (httpException.code() == 500) {\n            msg = \"服务器发生错误\";\n        } else if (httpException.code() == 404) {\n            msg = \"请求地址不存在\";\n        } else if (httpException.code() == 403) {\n            msg = \"请求被服务器拒绝\";\n        } else if (httpException.code() == 307) {\n            msg = \"请求被重定向到其他页面\";\n        } else {\n            msg = httpException.message();\n        }\n        return msg;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/service/DemoService.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app.service;\n\nimport com.jess.arms.base.BaseService;\n\n/**\n * ================================================\n * 展示 {@link BaseService} 的用法\n * <p>\n * Created by JessYan on 09/07/2016 16:59\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class DemoService extends BaseService {\n    @Override\n    public void init() {\n\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/app/utils/RxUtils.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.app.utils;\n\nimport com.jess.arms.mvp.IView;\nimport com.jess.arms.utils.RxLifecycleUtils;\nimport com.trello.rxlifecycle2.LifecycleTransformer;\nimport com.trello.rxlifecycle2.RxLifecycle;\n\nimport io.reactivex.ObservableTransformer;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.schedulers.Schedulers;\n\n/**\n * ================================================\n * 放置便于使用 RxJava 的一些工具方法\n * <p>\n * Created by JessYan on 11/10/2016 16:39\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class RxUtils {\n\n    private RxUtils() {\n    }\n\n    public static <T> ObservableTransformer<T, T> applySchedulers(final IView view) {\n        return observable -> observable.subscribeOn(Schedulers.io())\n                .doOnSubscribe(disposable -> {\n                    view.showLoading();//显示进度条\n                })\n                .subscribeOn(AndroidSchedulers.mainThread())\n                .observeOn(AndroidSchedulers.mainThread())\n                .doFinally(() -> {\n                    view.hideLoading();//隐藏进度条\n                }).compose(RxLifecycleUtils.bindToLifecycle(view));\n    }\n\n    /**\n     * 此方法已废弃\n     *\n     * @param view\n     * @param <T>\n     * @return\n     * @see RxLifecycleUtils 此类可以实现 {@link RxLifecycle} 的所有功能, 使用方法和之前一致\n     * @deprecated Use {@link RxLifecycleUtils#bindToLifecycle(IView)} instead\n     */\n    @Deprecated\n    public static <T> LifecycleTransformer<T> bindToLifecycle(IView view) {\n        return RxLifecycleUtils.bindToLifecycle(view);\n    }\n\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/di/component/UserComponent.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.di.component;\n\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.di.scope.ActivityScope;\n\nimport dagger.BindsInstance;\nimport dagger.Component;\nimport me.jessyan.mvparms.demo.di.module.UserModule;\nimport me.jessyan.mvparms.demo.mvp.contract.UserContract;\nimport me.jessyan.mvparms.demo.mvp.ui.activity.UserActivity;\n\n/**\n * ================================================\n * 展示 Component 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.6\">Component wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 11:17\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@ActivityScope\n@Component(modules = UserModule.class, dependencies = AppComponent.class)\npublic interface UserComponent {\n    void inject(UserActivity activity);\n\n    @Component.Builder\n    interface Builder {\n        @BindsInstance\n        UserComponent.Builder view(UserContract.View view);\n\n        UserComponent.Builder appComponent(AppComponent appComponent);\n\n        UserComponent build();\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/di/module/UserModule.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.di.module;\n\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.recyclerview.widget.GridLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.jess.arms.di.scope.ActivityScope;\nimport com.tbruyelle.rxpermissions2.RxPermissions;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport dagger.Binds;\nimport dagger.Module;\nimport dagger.Provides;\nimport me.jessyan.mvparms.demo.mvp.contract.UserContract;\nimport me.jessyan.mvparms.demo.mvp.model.UserModel;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport me.jessyan.mvparms.demo.mvp.ui.adapter.UserAdapter;\n\n/**\n * ================================================\n * 展示 Module 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.5\">Module wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 11:10\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@Module\npublic abstract class UserModule {\n\n    @ActivityScope\n    @Provides\n    static RxPermissions provideRxPermissions(UserContract.View view) {\n        return new RxPermissions((FragmentActivity) view.getActivity());\n    }\n\n    @ActivityScope\n    @Provides\n    static RecyclerView.LayoutManager provideLayoutManager(UserContract.View view) {\n        return new GridLayoutManager(view.getActivity(), 2);\n    }\n\n    @ActivityScope\n    @Provides\n    static List<User> provideUserList() {\n        return new ArrayList<>();\n    }\n\n    @ActivityScope\n    @Provides\n    static RecyclerView.Adapter provideUserAdapter(List<User> list) {\n        return new UserAdapter(list);\n    }\n\n    @Binds\n    abstract UserContract.Model bindUserModel(UserModel model);\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/contract/UserContract.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.contract;\n\nimport android.app.Activity;\n\nimport com.jess.arms.mvp.IModel;\nimport com.jess.arms.mvp.IView;\nimport com.tbruyelle.rxpermissions2.RxPermissions;\n\nimport java.util.List;\n\nimport io.reactivex.Observable;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\n\n/**\n * ================================================\n * 展示 Contract 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.1\">Contract wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 10:47\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface UserContract {\n    //对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息\n    interface View extends IView {\n        void startLoadMore();\n\n        void endLoadMore();\n\n        Activity getActivity();\n\n        //申请权限\n        RxPermissions getRxPermissions();\n    }\n\n    //Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,如是否使用缓存\n    interface Model extends IModel {\n        Observable<List<User>> getUsers(int lastIdQueried, boolean update);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/UserModel.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model;\n\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.OnLifecycleEvent;\n\nimport com.jess.arms.di.scope.ActivityScope;\nimport com.jess.arms.integration.IRepositoryManager;\nimport com.jess.arms.mvp.BaseModel;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport io.reactivex.Observable;\nimport io.reactivex.ObservableSource;\nimport io.reactivex.functions.Function;\nimport io.rx_cache2.DynamicKey;\nimport io.rx_cache2.EvictDynamicKey;\nimport me.jessyan.mvparms.demo.mvp.contract.UserContract;\nimport me.jessyan.mvparms.demo.mvp.model.api.cache.CommonCache;\nimport me.jessyan.mvparms.demo.mvp.model.api.service.UserService;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport timber.log.Timber;\n\n/**\n * ================================================\n * 展示 Model 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.3\">Model wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 10:56\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@ActivityScope\npublic class UserModel extends BaseModel implements UserContract.Model {\n    public static final int USERS_PER_PAGE = 10;\n\n    @Inject\n    public UserModel(IRepositoryManager repositoryManager) {\n        super(repositoryManager);\n    }\n\n    @Override\n    public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {\n        //使用rxcache缓存,上拉刷新则不读取缓存,加载更多读取缓存\n        return Observable.just(mRepositoryManager\n                .obtainRetrofitService(UserService.class)\n                .getUsers(lastIdQueried, USERS_PER_PAGE))\n                .flatMap((Function<Observable<List<User>>, ObservableSource<List<User>>>) listObservable -> mRepositoryManager.obtainCacheService(CommonCache.class)\n                        .getUsers(listObservable\n                                , new DynamicKey(lastIdQueried)\n                                , new EvictDynamicKey(update))\n                        .map(listReply -> listReply.getData()));\n\n    }\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)\n    void onPause() {\n        Timber.d(\"Release Resource\");\n    }\n\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/api/Api.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.api;\n\n/**\n * ================================================\n * 存放一些与 API 有关的东西,如请求地址,请求码等\n * <p>\n * Created by JessYan on 08/05/2016 11:25\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface Api {\n    String APP_DOMAIN = \"https://api.github.com\";\n    String REQUEST_SUCCESS = \"0\";\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/api/cache/CommonCache.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.api.cache;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport io.reactivex.Observable;\nimport io.rx_cache2.DynamicKey;\nimport io.rx_cache2.EvictProvider;\nimport io.rx_cache2.LifeCache;\nimport io.rx_cache2.Reply;\nimport io.rx_cache2.internal.RxCache;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\n\n/**\n * ================================================\n * 展示 {@link RxCache#using(Class)} 中需要传入的 Providers 的使用方式\n * <p>\n * Created by JessYan on 08/30/2016 13:53\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface CommonCache {\n\n    @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)\n    Observable<Reply<List<User>>> getUsers(Observable<List<User>> users, DynamicKey idLastUserQueried, EvictProvider evictProvider);\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/api/service/CommonService.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.api.service;\n\n/**\n * ================================================\n * 存放通用的一些 API\n * <p>\n * Created by JessYan on 08/05/2016 12:05\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface CommonService {\n\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/api/service/UserService.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.api.service;\n\nimport java.util.List;\n\nimport io.reactivex.Observable;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport retrofit2.Retrofit;\nimport retrofit2.http.GET;\nimport retrofit2.http.Headers;\nimport retrofit2.http.Query;\n\n/**\n * ================================================\n * 展示 {@link Retrofit#create(Class)} 中需要传入的 ApiService 的使用方式\n * 存放关于用户的一些 API\n * <p>\n * Created by JessYan on 08/05/2016 12:05\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic interface UserService {\n    String HEADER_API_VERSION = \"Accept: application/vnd.github.v3+json\";\n\n    @Headers({HEADER_API_VERSION})\n    @GET(\"/users\")\n    Observable<List<User>> getUsers(@Query(\"since\") int lastIdQueried, @Query(\"per_page\") int perPage);\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/entity/BaseResponse.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.entity;\n\nimport java.io.Serializable;\n\nimport me.jessyan.mvparms.demo.mvp.model.api.Api;\n\n/**\n * ================================================\n * 如果你服务器返回的数据格式固定为这种方式(这里只提供思想,服务器返回的数据格式可能不一致,可根据自家服务器返回的格式作更改)\n * 指定范型即可改变 {@code data} 字段的类型, 达到重用 {@link BaseResponse}, 如果你实在看不懂, 请忽略\n * <p>\n * Created by JessYan on 26/09/2016 15:19\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class BaseResponse<T> implements Serializable {\n    private T data;\n    private String code;\n    private String msg;\n\n    public T getData() {\n        return data;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    /**\n     * 请求是否成功\n     *\n     * @return\n     */\n    public boolean isSuccess() {\n        return code.equals(Api.REQUEST_SUCCESS);\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/model/entity/User.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.model.entity;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * ================================================\n * User 实体类\n * <p>\n * Created by JessYan on 04/09/2016 17:14\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class User {\n    private final int id;\n    private final String login;\n    private final String avatar_url;\n\n    public User(int id, String login, String avatarUrl) {\n        this.id = id;\n        this.login = login;\n        this.avatar_url = avatarUrl;\n    }\n\n    public String getAvatarUrl() {\n        if (avatar_url.isEmpty()) {\n            return avatar_url;\n        }\n        return avatar_url.split(\"\\\\?\")[0];\n    }\n\n\n    public int getId() {\n        return id;\n    }\n\n    public String getLogin() {\n        return login;\n    }\n\n    @NotNull\n    @Override\n    public String toString() {\n        return \"id -> \" + id + \" login -> \" + login;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/presenter/UserPresenter.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.presenter;\n\nimport android.app.Application;\n\nimport androidx.core.app.ComponentActivity;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.OnLifecycleEvent;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.jess.arms.di.scope.ActivityScope;\nimport com.jess.arms.integration.AppManager;\nimport com.jess.arms.mvp.BasePresenter;\nimport com.jess.arms.utils.PermissionUtil;\nimport com.jess.arms.utils.RxLifecycleUtils;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.schedulers.Schedulers;\nimport me.jessyan.mvparms.demo.mvp.contract.UserContract;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport me.jessyan.rxerrorhandler.core.RxErrorHandler;\nimport me.jessyan.rxerrorhandler.handler.ErrorHandleSubscriber;\nimport me.jessyan.rxerrorhandler.handler.RetryWithDelay;\n\n/**\n * ================================================\n * 展示 Presenter 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.4\">Presenter wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 10:59\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\n@ActivityScope\npublic class UserPresenter extends BasePresenter<UserContract.Model, UserContract.View> {\n    @Inject\n    RxErrorHandler mErrorHandler;\n    @Inject\n    AppManager mAppManager;\n    @Inject\n    Application mApplication;\n    @Inject\n    List<User> mUsers;\n    @Inject\n    RecyclerView.Adapter mAdapter;\n    private int lastUserId = 1;\n    private boolean isFirst = true;\n    private int preEndIndex;\n\n\n    @Inject\n    public UserPresenter(UserContract.Model model, UserContract.View rootView) {\n        super(model, rootView);\n    }\n\n    /**\n     * 使用 2017 Google IO 发布的 Architecture Components 中的 Lifecycles 的新特性 (此特性已被加入 Support library)\n     * 使 {@code Presenter} 可以与 {@link ComponentActivity} 和 {@link Fragment} 的部分生命周期绑定\n     */\n    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)\n    void onCreate() {\n        requestUsers(true);//打开 App 时自动加载列表\n    }\n\n    public void requestUsers(final boolean pullToRefresh) {\n        //请求外部存储权限用于适配android6.0的权限管理机制\n        PermissionUtil.externalStorage(new PermissionUtil.RequestPermission() {\n            @Override\n            public void onRequestPermissionSuccess() {\n                //request permission success, do something.\n                requestFromModel(pullToRefresh);\n            }\n\n            @Override\n            public void onRequestPermissionFailure(List<String> permissions) {\n                mRootView.showMessage(\"Request permissions failure\");\n                mRootView.hideLoading();//隐藏下拉刷新的进度条\n            }\n\n            @Override\n            public void onRequestPermissionFailureWithAskNeverAgain(List<String> permissions) {\n                mRootView.showMessage(\"Need to go to the settings\");\n                mRootView.hideLoading();//隐藏下拉刷新的进度条\n            }\n        }, mRootView.getRxPermissions(), mErrorHandler);\n    }\n\n    private void requestFromModel(boolean pullToRefresh) {\n        if (pullToRefresh) {\n            lastUserId = 1;//下拉刷新默认只请求第一页\n        }\n\n        //关于RxCache缓存库的使用请参考 http://www.jianshu.com/p/b58ef6b0624b\n\n        boolean isEvictCache = pullToRefresh;//是否驱逐缓存,为ture即不使用缓存,每次下拉刷新即需要最新数据,则不使用缓存\n\n        if (pullToRefresh && isFirst) {//默认在第一次下拉刷新时使用缓存\n            isFirst = false;\n            isEvictCache = false;\n        }\n\n        mModel.getUsers(lastUserId, isEvictCache)\n                .subscribeOn(Schedulers.io())\n                .retryWhen(new RetryWithDelay(3, 2))//遇到错误时重试,第一个参数为重试几次,第二个参数为重试的间隔\n                .doOnSubscribe(disposable -> {\n                    if (pullToRefresh) {\n                        mRootView.showLoading();//显示下拉刷新的进度条\n                    } else {\n                        mRootView.startLoadMore();//显示上拉加载更多的进度条\n                    }\n                }).subscribeOn(AndroidSchedulers.mainThread())\n                .observeOn(AndroidSchedulers.mainThread())\n                .doFinally(() -> {\n                    if (pullToRefresh) {\n                        mRootView.hideLoading();//隐藏下拉刷新的进度条\n                    } else {\n                        mRootView.endLoadMore();//隐藏上拉加载更多的进度条\n                    }\n                })\n                .compose(RxLifecycleUtils.bindToLifecycle(mRootView))//使用 Rxlifecycle,使 Disposable 和 Activity 一起销毁\n                .subscribe(new ErrorHandleSubscriber<List<User>>(mErrorHandler) {\n                    @Override\n                    public void onNext(List<User> users) {\n                        lastUserId = users.get(users.size() - 1).getId();//记录最后一个id,用于下一次请求\n                        if (pullToRefresh) {\n                            mUsers.clear();//如果是下拉刷新则清空列表\n                        }\n                        preEndIndex = mUsers.size();//更新之前列表总长度,用于确定加载更多的起始位置\n                        mUsers.addAll(users);\n                        if (pullToRefresh) {\n                            mAdapter.notifyDataSetChanged();\n                        } else {\n                            mAdapter.notifyItemRangeInserted(preEndIndex, users.size());\n                        }\n                    }\n                });\n    }\n\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        this.mAdapter = null;\n        this.mUsers = null;\n        this.mErrorHandler = null;\n        this.mAppManager = null;\n        this.mApplication = null;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/ui/activity/UserActivity.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.ui.activity;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.RecyclerView;\nimport androidx.swiperefreshlayout.widget.SwipeRefreshLayout;\n\nimport com.jess.arms.base.BaseActivity;\nimport com.jess.arms.base.DefaultAdapter;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.utils.ArmsUtils;\nimport com.paginate.Paginate;\nimport com.tbruyelle.rxpermissions2.RxPermissions;\n\nimport javax.inject.Inject;\n\nimport butterknife.BindView;\nimport me.jessyan.mvparms.demo.R;\nimport me.jessyan.mvparms.demo.di.component.DaggerUserComponent;\nimport me.jessyan.mvparms.demo.mvp.contract.UserContract;\nimport me.jessyan.mvparms.demo.mvp.presenter.UserPresenter;\nimport timber.log.Timber;\n\nimport static com.jess.arms.utils.Preconditions.checkNotNull;\n\n\n/**\n * ================================================\n * 展示 View 的用法\n *\n * @see <a href=\"https://github.com/JessYanCoding/MVPArms/wiki#2.4.2\">View wiki 官方文档</a>\n * Created by JessYan on 09/04/2016 10:59\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class UserActivity extends BaseActivity<UserPresenter> implements UserContract.View, SwipeRefreshLayout.OnRefreshListener {\n\n    @BindView(R.id.recyclerView)\n    RecyclerView mRecyclerView;\n    @BindView(R.id.swipeRefreshLayout)\n    SwipeRefreshLayout mSwipeRefreshLayout;\n    @Inject\n    RxPermissions mRxPermissions;\n    @Inject\n    RecyclerView.LayoutManager mLayoutManager;\n    @Inject\n    RecyclerView.Adapter mAdapter;\n\n    private Paginate mPaginate;\n    private boolean isLoadingMore;\n\n    @Override\n    public void setupActivityComponent(@NonNull AppComponent appComponent) {\n        DaggerUserComponent\n                .builder()\n                .appComponent(appComponent)\n                .view(this)\n                .build()\n                .inject(this);\n    }\n\n    @Override\n    public int initView(@Nullable Bundle savedInstanceState) {\n        return R.layout.activity_user;\n    }\n\n    @Override\n    public void initData(@Nullable Bundle savedInstanceState) {\n        initRecyclerView();\n        mRecyclerView.setAdapter(mAdapter);\n        initPaginate();\n    }\n\n\n    @Override\n    public void onRefresh() {\n        mPresenter.requestUsers(true);\n    }\n\n    /**\n     * 初始化RecyclerView\n     */\n    private void initRecyclerView() {\n        mSwipeRefreshLayout.setOnRefreshListener(this);\n        ArmsUtils.configRecyclerView(mRecyclerView, mLayoutManager);\n    }\n\n\n    @Override\n    public void showLoading() {\n        Timber.tag(TAG).w(\"showLoading\");\n        mSwipeRefreshLayout.setRefreshing(true);\n    }\n\n    @Override\n    public void hideLoading() {\n        Timber.tag(TAG).w(\"hideLoading\");\n        mSwipeRefreshLayout.setRefreshing(false);\n    }\n\n    @Override\n    public void showMessage(@NonNull String message) {\n        checkNotNull(message);\n        ArmsUtils.snackbarText(message);\n    }\n\n    @Override\n    public void launchActivity(@NonNull Intent intent) {\n        checkNotNull(intent);\n        ArmsUtils.startActivity(intent);\n    }\n\n    @Override\n    public void killMyself() {\n        finish();\n    }\n\n    /**\n     * 开始加载更多\n     */\n    @Override\n    public void startLoadMore() {\n        isLoadingMore = true;\n    }\n\n    /**\n     * 结束加载更多\n     */\n    @Override\n    public void endLoadMore() {\n        isLoadingMore = false;\n    }\n\n    @Override\n    public Activity getActivity() {\n        return this;\n    }\n\n    @Override\n    public RxPermissions getRxPermissions() {\n        return mRxPermissions;\n    }\n\n    /**\n     * 初始化Paginate,用于加载更多\n     */\n    private void initPaginate() {\n        if (mPaginate == null) {\n            Paginate.Callbacks callbacks = new Paginate.Callbacks() {\n                @Override\n                public void onLoadMore() {\n                    mPresenter.requestUsers(false);\n                }\n\n                @Override\n                public boolean isLoading() {\n                    return isLoadingMore;\n                }\n\n                @Override\n                public boolean hasLoadedAllItems() {\n                    return false;\n                }\n            };\n\n            mPaginate = Paginate.with(mRecyclerView, callbacks)\n                    .setLoadingTriggerThreshold(0)\n                    .build();\n            mPaginate.setHasMoreDataToLoad(false);\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        DefaultAdapter.releaseAllHolder(mRecyclerView);//super.onDestroy()之后会unbind,所有view被置为null,所以必须在之前调用\n        super.onDestroy();\n        this.mRxPermissions = null;\n        this.mPaginate = null;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/ui/adapter/UserAdapter.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.ui.adapter;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.jess.arms.base.BaseHolder;\nimport com.jess.arms.base.DefaultAdapter;\n\nimport java.util.List;\n\nimport me.jessyan.mvparms.demo.R;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\nimport me.jessyan.mvparms.demo.mvp.ui.holder.UserItemHolder;\n\n/**\n * ================================================\n * 展示 {@link DefaultAdapter} 的用法\n * <p>\n * Created by JessYan on 09/04/2016 12:57\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class UserAdapter extends DefaultAdapter<User> {\n\n    public UserAdapter(List<User> infos) {\n        super(infos);\n    }\n\n    @NonNull\n    @Override\n    public BaseHolder<User> getHolder(@NonNull View v, int viewType) {\n        return new UserItemHolder(v);\n    }\n\n    @Override\n    public int getLayoutId(int viewType) {\n        return R.layout.recycle_list;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/java/me/jessyan/mvparms/demo/mvp/ui/holder/UserItemHolder.java",
    "content": "/*\n * Copyright 2017 JessYan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage me.jessyan.mvparms.demo.mvp.ui.holder;\n\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.jess.arms.base.BaseHolder;\nimport com.jess.arms.base.DefaultAdapter;\nimport com.jess.arms.di.component.AppComponent;\nimport com.jess.arms.http.imageloader.ImageLoader;\nimport com.jess.arms.http.imageloader.glide.ImageConfigImpl;\nimport com.jess.arms.utils.ArmsUtils;\n\nimport butterknife.BindView;\nimport me.jessyan.mvparms.demo.R;\nimport me.jessyan.mvparms.demo.mvp.model.entity.User;\n\n/**\n * ================================================\n * 展示 {@link BaseHolder} 的用法\n * <p>\n * Created by JessYan on 9/4/16 12:56\n * <a href=\"mailto:jess.yan.effort@gmail.com\">Contact me</a>\n * <a href=\"https://github.com/JessYanCoding\">Follow me</a>\n * ================================================\n */\npublic class UserItemHolder extends BaseHolder<User> {\n\n    @BindView(R.id.iv_avatar)\n    ImageView mAvatar;\n    @BindView(R.id.tv_name)\n    TextView mName;\n    private AppComponent mAppComponent;\n    /**\n     * 用于加载图片的管理类, 默认使用 Glide, 使用策略模式, 可替换框架\n     */\n    private ImageLoader mImageLoader;\n\n    public UserItemHolder(View itemView) {\n        super(itemView);\n        //可以在任何可以拿到 Context 的地方, 拿到 AppComponent, 从而得到用 Dagger 管理的单例对象\n        mAppComponent = ArmsUtils.obtainAppComponentFromContext(itemView.getContext());\n        mImageLoader = mAppComponent.imageLoader();\n    }\n\n    @Override\n    public void setData(@NonNull User data, int position) {\n        mName.setText(data.getLogin());\n\n        //itemView 的 Context 就是 Activity, Glide 会自动处理并和该 Activity 的生命周期绑定\n        mImageLoader.loadImage(itemView.getContext(),\n                ImageConfigImpl\n                        .builder()\n                        .url(data.getAvatarUrl())\n                        .imageView(mAvatar)\n                        .build());\n    }\n\n    /**\n     * 在 Activity 的 onDestroy 中使用 {@link DefaultAdapter#releaseAllHolder(RecyclerView)} 方法 (super.onDestroy() 之前)\n     * {@link BaseHolder#onRelease()} 才会被调用, 可以在此方法中释放一些资源\n     */\n    @Override\n    protected void onRelease() {\n        //只要传入的 Context 为 Activity, Glide 就会自己做好生命周期的管理, 其实在上面的代码中传入的 Context 就是 Activity\n        //所以在 onRelease 方法中不做 clear 也是可以的, 但是在这里想展示一下 clear 的用法\n        mImageLoader.clear(mAppComponent.application(), ImageConfigImpl.builder()\n                .imageViews(mAvatar)\n                .build());\n        this.mAvatar = null;\n        this.mName = null;\n        this.mAppComponent = null;\n        this.mImageLoader = null;\n    }\n}\n"
  },
  {
    "path": "demo/src/main/res/anim/translate_center_to_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"300\">\n    <translate\n        android:fromXDelta=\"0%\"\n        android:toXDelta=\"-100%\" />\n\n\n</set>\n"
  },
  {
    "path": "demo/src/main/res/anim/translate_center_to_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"300\">\n    <translate\n        android:fromXDelta=\"0%\"\n        android:toXDelta=\"100%\" />\n\n\n</set>\n"
  },
  {
    "path": "demo/src/main/res/anim/translate_left_to_center.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"300\">\n    <translate\n        android:fromXDelta=\"-100%\"\n        android:toXDelta=\"0%\" />\n\n\n</set>\n"
  },
  {
    "path": "demo/src/main/res/anim/translate_right_to_center.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"300\">\n    <translate\n        android:fromXDelta=\"100%\"\n        android:toXDelta=\"0%\" />\n\n\n</set>\n"
  },
  {
    "path": "demo/src/main/res/layout/activity_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_title\" />\n\n    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout\n        android:id=\"@+id/swipeRefreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingLeft=\"4dp\"\n        android:paddingTop=\"4dp\">\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/recyclerView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:scrollbars=\"vertical\"\n            tools:listitem=\"@layout/recycle_list\" />\n\n    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>\n</LinearLayout>"
  },
  {
    "path": "demo/src/main/res/layout/include_title.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.appcompat.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/toolbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:background=\"?attr/colorPrimary\"\n    app:contentInsetStart=\"0dp\"\n    tools:ignore=\"ContentDescription\">\n\n    <RelativeLayout\n        android:id=\"@+id/toolbar_back\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"start\">\n\n        <ImageView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:src=\"@mipmap/ic_arrow_back_white_24dp\" />\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/toolbar_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"18sp\"\n        tools:text=\"@string/app_name\" />\n\n</androidx.appcompat.widget.Toolbar>"
  },
  {
    "path": "demo/src/main/res/layout/recycle_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"174dp\"\n    android:layout_marginRight=\"4dp\"\n    tools:ignore=\"ContentDescription\"\n    android:layout_marginBottom=\"4dp\">\n\n    <ImageView\n        android:id=\"@+id/iv_avatar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"centerCrop\"\n        tools:src=\"#000000\" />\n\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal|bottom\"\n        android:layout_marginBottom=\"3dp\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"18sp\"\n        tools:text=\"ss\" />\n\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "demo/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3FA862</color>\n    <color name=\"colorPrimaryDark\">#3FA862</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"white\">#FFFFFF</color>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">MVPArms</string>\n</resources>\n"
  },
  {
    "path": "demo/src/main/res/values/styles.xml",
    "content": "<resources>\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:windowAnimationStyle\">@style/Animation_Activity</item>\n    </style>\n\n    <style name=\"Animation_Activity\">\n        <item name=\"android:activityOpenEnterAnimation\">@anim/translate_right_to_center</item>\n        <item name=\"android:activityOpenExitAnimation\">@anim/translate_center_to_left</item>\n        <item name=\"android:activityCloseEnterAnimation\">@anim/translate_left_to_center</item>\n        <item name=\"android:activityCloseExitAnimation\">@anim/translate_center_to_right</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "demo/src/test/java/me/jessyan/mvparms/demo/ExampleUnitTest.java",
    "content": "package me.jessyan.mvparms.demo;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * To work on unit tests, switch the Test Artifact in the Build Variants view.\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Feb 26 13:45:30 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.4-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "## Project-wide Gradle settings.\n#\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n#\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx1024m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n#\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n#Thu May 25 20:59:18 CST 2017\norg.gradle.jvmargs=-Xmx1536m\nandroid.enableBuildCache=true\nandroid.useAndroidX=true\nandroid.enableJetifier=true\nandroid.injected.testOnly=false\nandroid.databinding.incremental=true\nandroid.lifecycleProcessor.incremental=true\nkapt.incremental.apt=true\nkapt.use.worker.api=true\nkapt.include.compile.classpath=false\norg.gradle.parallel=true\norg.gradle.caching=true\norg.gradle.configureondemand=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':demo', ':arms', ':arms-autolayout', ':arms-imageloader-glide'\n"
  }
]