├── .gitignore
├── .idea
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── org
│ │ └── zzy
│ │ └── imagemonitor
│ │ ├── MainActivity.java
│ │ └── MyApplication.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable-xxhdpi
│ ├── ic_test_four.jpg
│ ├── ic_test_one.jpg
│ ├── ic_test_three.jpg
│ └── ic_test_two.jpg
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_launcher_foreground.xml
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── network_security_config.xml
├── build.gradle
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── largeimage-plugin
├── build.gradle
├── src
│ └── main
│ │ ├── groovy
│ │ └── org
│ │ │ └── zzy
│ │ │ └── largeimage
│ │ │ ├── Config.java
│ │ │ ├── LargeImageExtension.java
│ │ │ ├── LargeImageMonitorPlugin.java
│ │ │ ├── adapter
│ │ │ ├── LargeImageClassAdapter.java
│ │ │ ├── OkHttpClassAdapter.java
│ │ │ └── UrlConnectionClassAdapter.java
│ │ │ ├── method
│ │ │ ├── FrescoMethodAdapter.java
│ │ │ ├── GlideMethodAdapter.java
│ │ │ ├── ImageLoaderMethodAdapter.java
│ │ │ ├── OkHttpMethodAdapter.java
│ │ │ ├── PicassoMethodAdapter.java
│ │ │ └── UrlConnectionMethodAdapter.java
│ │ │ ├── transform
│ │ │ ├── LargeImageTransform.java
│ │ │ ├── OkHttpTransform.java
│ │ │ └── UrlConnectionTransform.java
│ │ │ └── weaver
│ │ │ ├── LargeImageWeaver.java
│ │ │ ├── OkHttpWeaver.java
│ │ │ └── UrlConnectionWeaver.java
│ │ └── resources
│ │ └── META-INF
│ │ └── gradle-plugins
│ │ └── largeimage-monitor.properties
└── upload.gradle
├── largeimage
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ └── org
│ │ │ └── zzy
│ │ │ └── lib
│ │ │ └── largeimage
│ │ │ ├── LargeImage.java
│ │ │ ├── LargeImageInfo.java
│ │ │ ├── LargeImageManager.java
│ │ │ ├── Test.java
│ │ │ ├── activity
│ │ │ ├── LargeImageListActivity.java
│ │ │ └── SettingActivity.java
│ │ │ ├── adapter
│ │ │ └── LargeImageListAdapter.java
│ │ │ ├── aop
│ │ │ ├── fresco
│ │ │ │ ├── FrescoHook.java
│ │ │ │ └── FrescoLargeImageProcessor.java
│ │ │ ├── glide
│ │ │ │ ├── GlideHook.java
│ │ │ │ └── GlideLargeImageListener.java
│ │ │ ├── imageloader
│ │ │ │ ├── ImageLoaderHook.java
│ │ │ │ └── ImageLoaderLargeImageListener.java
│ │ │ ├── okhttp
│ │ │ │ └── LargeImageInterceptor.java
│ │ │ ├── picasso
│ │ │ │ ├── PicassoHook.java
│ │ │ │ └── PicassoLargeImageTransformation.java
│ │ │ └── urlconnection
│ │ │ │ ├── ObsoleteUrlFactory.java
│ │ │ │ └── UrlConnectionHook.java
│ │ │ └── util
│ │ │ ├── ConvertUtils.java
│ │ │ ├── ImageUtil.java
│ │ │ ├── Reflector.java
│ │ │ └── ResHelper.java
│ │ └── res
│ │ ├── drawable-xxhdpi
│ │ ├── checkbox_checked.png
│ │ ├── checkbox_unchecked.png
│ │ ├── ic_default.jpg
│ │ └── ic_failed.jpg
│ │ ├── drawable
│ │ ├── ic_alarm.xml
│ │ ├── ic_arrow_back_black_24dp.xml
│ │ ├── ic_background.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_logo.xml
│ │ ├── ic_more_vert_black_24dp.xml
│ │ ├── ic_satellite.xml
│ │ └── switch_background.xml
│ │ ├── layout
│ │ ├── activity_largeimage_list.xml
│ │ ├── activity_setting.xml
│ │ └── dialog_custom.xml
│ │ ├── menu
│ │ └── toolbar.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── upload.gradle
├── settings.gradle
└── wiki
├── LargeImageTheory.md
├── alipay.jpg
├── example1.jpg
├── example2.jpg
├── example3.jpg
├── example4.jpg
├── logo.png
└── wxpay.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LargeImageMonitor
2 |
3 |
4 |
5 |
6 |
7 | [](https://bintray.com/zzy/imageMonitor/large-image-monitor/1.0.0/link)
8 | 
9 | 
10 | 
11 |
12 | ### 背景
13 | 在平时开发中,我们经常会出现OOM和APK体积过大的情况,其中有很大的原因在于图片过大。当图片占用内存过大,内存不足时就会导致OOM。而图片的文件太大,会导致在打包成APK后,APK的体积增加。对于本地加载的图片,UI给我们图时,我们或许会下意识看一眼文件大小,如果文件太大我们可能会跟UI小姐姐进行沟通。但是对于从网络加载图片,很多时候客户端拿到的只是一个URL,我们并不知道要加载的图片大小,这时候就有可能造成图片过大的情况。
14 |
15 | ### 介绍
16 | LargeImageMonitor是一个使用ASM进行字节码插桩的大图监控框架,可以对我们要加载的图片进行监控,如果出现图片超过阈值的情况会进行报警。
17 |
18 | ### 功能与特点
19 | 1.支持Glide,Fresco,Picasso,Universal Image Loader。
20 |
21 | 2.可以对图片的文件大小设置阈值。
22 |
23 | 3.可以对图片所占用的内存大小设置阈值。
24 |
25 | 4.可以通过弹窗或者列表的方式查看超过阈值的图片。
26 |
27 | 5.可以为Okhttp添加全局的应用监听器和网络监听器(包括第三方使用到的okhttp也会添加上)。
28 |
29 | 6.可以为Okhttp添加全局的自定义DNS,方便实现HTTPDNS(包括第三方使用到的okhttp也会添加上)。
30 |
31 | 6.支持Androidx。
32 |
33 | ### 效果
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ### 快速接入
44 | 1.在根目录的build.gralde中添加如下代码:
45 | ```groovy
46 | buildscript {
47 | //添加jcenter
48 | repositories {
49 | jcenter()
50 | }
51 | //添加插件classpath
52 | dependencies {
53 | classpath 'org.zzy.largeimage:large-image-monitor-plugin:1.0.0'
54 | }
55 | }
56 | ```
57 | 2.在要使用的模块的build.gradle中添加如下代码:
58 | ```groovy
59 | //添加使用插件
60 | apply plugin: 'largeimage-monitor'
61 | //添加依赖库
62 | implementation 'org.zzy.lib.largeimage:large-image-monitor:1.0.0'
63 | ```
64 | 3.在Application类中初始化框架:
65 | ```java
66 | //初始化大图监控
67 | LargeImage.getInstance()
68 | .install(this)//一定要调用该方法进行初始化
69 | .setFileSizeThreshold(400.0)//设置文件大小阈值单位为KB (可选)
70 | .setMemorySizeThreshold(100)//设置内存占用大小阈值单位为KB (可选)
71 | .setLargeImageOpen(true)//是否开启大图监控,默认为开启,如果false,则不会在大图列表和弹窗显示超标图片 (可选)
72 | .addOkHttpInterceptor(new CustomGlobalInterceptor())//添加OKhttp自定义全局应用监听器 (可选)
73 | .addOkHttpNetworkInterceptor(new CustomGlobalNetworkInterceptor())//添加Okhttp值得你故意全局网络监听器 (可选)
74 | .setDns(new CustomHttpDns);//设置自定义的全局DNS,可以自己实现HttpDns (可选)
75 | ```
76 |
77 | 4.记得打开浮窗权限
78 |
79 | ### 支持版本
80 | - Glide:(v4.10.0 - v4.11.0)
81 | - Fresco:(v0.1.0 - v2.2.0)
82 | - Picasso:(v2.4.0 - v2.71828)
83 | - ImageLoader:(v1.9.1 - v1.9.5)
84 | - Okhttp:(v3.0.0 - v3.14.7)
85 |
86 | ### TodoList
87 | - [ ] 对各大框架进行版本兼容。
88 | - [ ] 得到View的尺寸。
89 |
90 | ### Change Log
91 | v1.0.0 (2020/4/15)
92 | - 项目初始化实现基本功能
93 |
94 | ### 原理分析
95 | - [通过ASM实现大图监控](https://github.com/121880399/LargeImageMonitor/blob/master/wiki/LargeImageTheory.md)
96 |
97 | ### 鸣谢
98 | - [DoraemonKit](https://github.com/didi/DoraemonKit)
99 | - [Hunter](https://github.com/Leaking/Hunter)
100 | - [bintray-release](https://github.com/novoda/bintray-release)
101 |
102 | ## License
103 | Apache 2.0
104 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'largeimage-monitor'
3 | android {
4 | compileSdkVersion rootProject.ext.android["compileSdkVersion"]
5 |
6 | defaultConfig {
7 | applicationId rootProject.ext.android["applicationId"]
8 | minSdkVersion rootProject.ext.android["minSdkVersion"]
9 | targetSdkVersion rootProject.ext.android["targetSdkVersion"]
10 | versionCode rootProject.ext.android["versionCode"]
11 | versionName rootProject.ext.android["versionName"]
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 | //largeImageMonitor{
22 | // //开关测试成功
23 | // largeImagePluginSwitch = true
24 | //}
25 |
26 | dependencies {
27 | implementation fileTree(dir: 'libs', include: ['*.jar'])
28 | implementation rootProject.ext.dependencies["androidx"]
29 | implementation rootProject.ext.dependencies["glide"]
30 | implementation rootProject.ext.dependencies["picasso"]
31 | implementation rootProject.ext.dependencies["fresco"]
32 | implementation rootProject.ext.dependencies["image-loader"]
33 | implementation rootProject.ext.dependencies["image-monitor"]
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/org/zzy/imagemonitor/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.zzy.imagemonitor;
2 |
3 | import android.net.Uri;
4 | import android.os.Bundle;
5 | import android.widget.ImageView;
6 |
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.facebook.drawee.view.SimpleDraweeView;
12 | import com.nostra13.universalimageloader.core.ImageLoader;
13 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
14 | import com.squareup.picasso.Picasso;
15 |
16 | public class MainActivity extends AppCompatActivity {
17 |
18 | private ImageView mIVImageLoader;
19 | private ImageView mIVGlide;
20 | private SimpleDraweeView mIVFresco;
21 | private ImageView mIVPicasso;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_main);
27 | initView();
28 | initData();
29 | }
30 |
31 | private void initView(){
32 | mIVImageLoader = findViewById(R.id.iv_imageloader);
33 | mIVGlide = findViewById(R.id.iv_glide);
34 | mIVFresco = (SimpleDraweeView)findViewById(R.id.iv_fresco);
35 | mIVPicasso = findViewById(R.id.iv_picasso);
36 | }
37 |
38 |
39 | private void initData(){
40 | setImageLoader();
41 | setGlide();
42 | setFresco();
43 | setPicasso();
44 | }
45 |
46 | private void setImageLoader(){
47 | ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(this));
48 | //1.测试文件和内存大小未超过的图片,预期结果:不弹出提示 测试结果:通过
49 | // ImageLoader.getInstance().displayImage("https://c-ssl.duitang.com/uploads/item/202004/03/20200403204640_mNNyA.thumb.300_300_c.jpeg",mIVImageLoader);
50 | //2.测试内存大小超过的图片,测试文件大小超过的图片 预期结果:弹出提示(测试第一次加载和从缓存加载的一致性) 测试结果:通过
51 | // ImageLoader.getInstance().displayImage("http://desk.fd.zol-img.com.cn/t_s1680x1050/g5/M00/09/03/ChMkJ13I0eyIdyApAAMWAKdhvL4AAvKLwFDZMcAAxYY629.jpg",mIVImageLoader);
52 | //3.测试本地图片
53 | ImageLoader.getInstance().displayImage("drawable://"+R.drawable.ic_test_one,mIVImageLoader);
54 | }
55 |
56 | private void setGlide(){
57 | //1.测试文件和内存大小未超过的图片,预期结果:不弹出提示 测试结果:通过
58 | // Glide.with(this).load("https://c-ssl.duitang.com/uploads/item/202004/03/20200403204618_d2Ucc.thumb.300_300_c.jpeg").into(mIVGlide);
59 | //2.测试内存大小超过的图片,测试文件大小超过的图片 预期结果:弹出提示(测试第一次加载和从缓存加载的一致性) 测试结果:通过
60 | // Glide.with(this).load("http://desk.fd.zol-img.com.cn/t_s1680x1050/g5/M00/09/03/ChMkJ13I0O-IUxnqAA6O1fF1dWwAAvKJgAYVvEADo7t268.jpg").into(mIVGlide);
61 | //3.测试本地图片
62 | Glide.with(this).load(R.drawable.ic_test_two).into(mIVGlide);
63 | // Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_test_three);
64 | // Glide.with(this).load(bitmap).into(mIVGlide);
65 |
66 | }
67 |
68 | private void setFresco(){
69 | //1.测试文件和内存大小未超过的图片,预期结果:不弹出提示 测试结果:通过
70 | // Uri uri = Uri.parse("https://c-ssl.duitang.com/uploads/item/202004/03/20200403204602_5zHGC.thumb.300_300_c.jpeg");
71 | //2.测试内存大小超过的图片,测试文件大小超过的图片 预期结果:弹出提示(测试第一次加载和从缓存加载的一致性) 测试结果:通过
72 | // Uri uri = Uri.parse("https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/09/03/ChMkJl3I0dmIAiyXABDF46MVj1IAAvKLgFJsZUAEMX7384.jpg");
73 | //3.测试本地图片
74 | Uri uri = Uri.parse("res://"+"drawable/"+R.drawable.ic_test_three);
75 | mIVFresco.setImageURI(uri);
76 | }
77 |
78 | private void setPicasso(){
79 | //1.测试文件和内存大小未超过的图片,预期结果:不弹出提示 测试结果:通过
80 | // Picasso.get().load("https://c-ssl.duitang.com/uploads/item/202004/03/20200403204520_H2cti.thumb.300_300_c.jpeg").into(mIVPicasso);
81 | //2.测试内存大小超过的图片,测试文件大小超过的图片 预期结果:弹出提示(测试第一次加载和从缓存加载的一致性) 测试结果:通过
82 | // Picasso.get().load("https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/0B/0D/ChMkJ1vfv8CIbx2-AAYDrq1u-J8AAs9xAHJAuMABgPG789.jpg").into(mIVPicasso);
83 | //3.测试本地图片
84 | Picasso.get().load(R.drawable.ic_test_four).into(mIVPicasso);
85 |
86 |
87 | }
88 |
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/org/zzy/imagemonitor/MyApplication.java:
--------------------------------------------------------------------------------
1 | package org.zzy.imagemonitor;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.drawee.backends.pipeline.Fresco;
6 | import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
7 | import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
8 | import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;
9 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
10 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
11 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
12 | import com.nostra13.universalimageloader.core.decode.BaseImageDecoder;
13 | import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
14 | import com.nostra13.universalimageloader.utils.StorageUtils;
15 |
16 | import org.zzy.lib.largeimage.LargeImage;
17 |
18 | import java.io.File;
19 |
20 | /**
21 | * ================================================
22 | * 作 者:ZhouZhengyi
23 | * 创建日期:2020/4/3 11:16
24 | * 描 述:
25 | * 修订历史:
26 | * ================================================
27 | */
28 | public class MyApplication extends Application {
29 |
30 | @Override
31 | public void onCreate() {
32 | super.onCreate();
33 | //初始化大图监控
34 | LargeImage.getInstance().install(this).setFileSizeThreshold(400.0).setMemorySizeThreshold(100);
35 | Fresco.initialize(this);
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_test_four.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/drawable-xxhdpi/ic_test_four.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_test_one.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/drawable-xxhdpi/ic_test_one.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_test_three.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/drawable-xxhdpi/ic_test_three.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_test_two.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/drawable-xxhdpi/ic_test_two.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
27 |
28 |
35 |
43 |
44 |
53 |
61 |
62 |
69 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ImageMonitor
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from: "config.gradle"
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
8 | maven { url "http://maven.aliyun.com/nexus/content/repositories/jcente" }
9 | maven { url 'https://jitpack.io' }
10 |
11 | //https://jcenter.bintray.com/org/zzy/largeimage/large-image-monitor-plugin/1.0.0/
12 | // maven {
13 | // credentials {
14 | // username "${mavenUser}"
15 | // password "${mavenPassword}"
16 | // }
17 | // url 'http://127.0.0.1:8081/repository/maven-snapshots/'}
18 | }
19 | dependencies {
20 | classpath 'com.android.tools.build:gradle:3.6.1'
21 | // classpath 'org.zzy.lib:largeimage:1.0.0-SNAPSHOT'
22 | classpath 'com.novoda:bintray-release:0.9.2'
23 | classpath 'org.zzy.largeimage:large-image-monitor-plugin:1.0.0'
24 | // NOTE: Do not place your application dependencies here; they belong
25 | // in the individual module build.gradle files
26 | }
27 | }
28 |
29 | allprojects {
30 | tasks.withType(Javadoc).all { enabled = false }
31 | repositories {
32 | jcenter()
33 | google()
34 | maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
35 | maven { url "http://maven.aliyun.com/nexus/content/repositories/jcente" }
36 | maven { url 'https://jitpack.io' }
37 |
38 |
39 |
40 | // maven {
41 | // credentials {
42 | // username "${mavenUser}"
43 | // password "${mavenPassword}"
44 | // }
45 | // url 'http://127.0.0.1:8081/repository/maven-snapshots/'}
46 | }
47 | }
48 |
49 | task clean(type: Delete) {
50 | delete rootProject.buildDir
51 | }
52 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | android = [
3 | applicationId : "org.zzy.imagemonitor",
4 | compileSdkVersion : 29,
5 | minSdkVersion : 19,
6 | targetSdkVersion : 29,
7 | versionCode : 1,
8 | versionName : "1.0.0",
9 | //插件版本号
10 | pluginVersionName : "1.0.0",
11 | //jcenter
12 | jcenterArchivesVersionName: "1.0.0",
13 | ]
14 | dependencies = [
15 | "okhttp" : "com.squareup.okhttp3:okhttp:3.12.1",
16 | //将urlconnection代理到okhttp
17 | //"okhttp_urlconnection" : "com.squareup.okhttp3:okhttp-urlconnection:3.12.1",
18 | //"okio" : "com.squareup.okio:okio:1.15.0",
19 | "glide" : 'com.github.bumptech.glide:glide:4.11.0',
20 | "picasso" : 'com.squareup.picasso:picasso:2.71828',
21 | "fresco" : 'com.facebook.fresco:fresco:2.1.0',
22 | "image-loader" : 'com.nostra13.universalimageloader:universal-image-loader:1.9.5',
23 | "MMKV" : 'com.tencent:mmkv-static:1.1.0',
24 | "FloatWindow" : 'com.github.yhaolpz:FloatWindow:1.0.9',
25 | "androidx" : 'androidx.appcompat:appcompat:1.1.0',
26 | "recylcerview" : 'androidx.recyclerview:recyclerview:1.0.0',
27 | "image-monitor" : 'org.zzy.lib.largeimage:large-image-monitor:1.0.0',
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Mar 30 18:53:03 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/largeimage-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'groovy'
2 | //apply plugin: 'maven'
3 | apply from: 'upload.gradle'
4 |
5 | //上传到本地maven库
6 | //uploadArchives {
7 | // repositories {
8 | // mavenDeployer {
9 | // pom.groupId = "org.zzy.lib"
10 | // pom.artifactId = "largeimage"
11 | // pom.version = "1.0.0-SNAPSHOT"
12 | // //要上传的maven仓库地址
13 | // repository(url:"http://127.0.0.1:8081/repository/maven-snapshots/") {
14 | // authentication(userName: "admin", password: "admin123")
15 | // }
16 | // }
17 | // }
18 | //}
19 | dependencies {
20 | implementation gradleApi()
21 | implementation localGroovy()
22 | implementation 'com.android.tools.build:gradle:3.0.1'//版本不能太高,防止跟项目的起冲突
23 | implementation 'com.android.tools.build:gradle-api:3.0.0'
24 | implementation('com.quinn.hunter:hunter-transform:0.9.2') { //使用hunter框架
25 | exclude group: 'com.android.tools.build' //排除hunter带来的gradle,使用自定义gradle版本
26 | }
27 | //这里不引入asm的相关包是因为hunter中已经引入,如果想使用新版本则可以引入,但是要排除掉hunter使用的版本
28 | }
29 |
30 | repositories {
31 | google()
32 | jcenter()
33 | mavenCentral()
34 | }
35 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/Config.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage;
2 |
3 | /**
4 | * ================================================
5 | * 作 者:ZhouZhengyi
6 | * 创建日期:2020/4/5 21:50
7 | * 描 述:
8 | * 修订历史:
9 | * ================================================
10 | */
11 | public class Config {
12 | public static String TAG = "LargeImageMonitor";
13 | /**
14 | * 大图检测插件的开关
15 | */
16 | private boolean largeImagePluginSwitch = true;
17 |
18 | private Config(){}
19 |
20 | private static class Holder{
21 | private static Config INSTANCE = new Config();
22 | }
23 |
24 | public static Config getInstance(){
25 | return Holder.INSTANCE;
26 | }
27 |
28 | public boolean largeImagePluginSwitch() {
29 | return largeImagePluginSwitch;
30 | }
31 |
32 | public void init(LargeImageExtension extension){
33 | if(null != extension){
34 | this.largeImagePluginSwitch = extension.largeImagePluginSwitch;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/LargeImageExtension.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage;
2 |
3 | /**
4 | * ================================================
5 | * 作 者:ZhouZhengyi
6 | * 创建日期:2020/4/5 21:24
7 | * 描 述:JAVABean类,对应gradle中配置的参数
8 | * 属性必须为public类型,否则无法赋值
9 | * 修订历史:
10 | * ================================================
11 | */
12 | public class LargeImageExtension {
13 | /**
14 | * 大图检测插件的开关
15 | */
16 | public boolean largeImagePluginSwitch = true;
17 | }
18 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/LargeImageMonitorPlugin.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage;
2 |
3 | import com.android.build.gradle.AppExtension;
4 |
5 | import org.gradle.api.Action;
6 | import org.gradle.api.Plugin;
7 | import org.gradle.api.Project;
8 | import org.zzy.largeimage.transform.LargeImageTransform;
9 | import org.zzy.largeimage.transform.OkHttpTransform;
10 | import org.zzy.largeimage.transform.UrlConnectionTransform;
11 |
12 | import java.util.Collections;
13 | import java.util.List;
14 |
15 | /**
16 | * ================================================
17 | * 作 者:ZhouZhengyi
18 | * 创建日期:2020/3/31 20:49
19 | * 描 述:调试前执行gradle assembleDebug -Dorg.gradle.daemon=false -Dorg.gradle.debug=true命令,然后按debug按钮,接着执行task debug便会生效
20 | * 修订历史:2020/4/13 v1.0.0
21 | * github:https://github.com/121880399/LargeImageMonitor
22 | * ================================================
23 | */
24 | public class LargeImageMonitorPlugin implements Plugin {
25 |
26 | @Override
27 | public void apply(Project project) {
28 | List taskNames = project.getGradle().getStartParameter().getTaskNames();
29 | //如果是Release版本,则不进行字节码替换
30 | for(String taskName : taskNames){
31 | if(taskName.contains("Release")){
32 | return;
33 | }
34 | }
35 |
36 | AppExtension appExtension = (AppExtension)project.getProperties().get("android");
37 | //创建自定义扩展
38 | project.getExtensions().create("largeImageMonitor",LargeImageExtension.class);
39 | project.afterEvaluate(new Action() {
40 | @Override
41 | public void execute(Project project) {
42 | LargeImageExtension extension = project.getExtensions().getByType(LargeImageExtension.class);
43 | Config.getInstance().init(extension);
44 | }
45 | });
46 | //将自定义Transform添加到编译流程中
47 | appExtension.registerTransform(new LargeImageTransform(project), Collections.EMPTY_LIST);
48 | //添加OkHttp
49 | appExtension.registerTransform(new OkHttpTransform(project),Collections.EMPTY_LIST);
50 | //添加UrlConnection
51 | appExtension.registerTransform(new UrlConnectionTransform(project),Collections.EMPTY_LIST);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/adapter/LargeImageClassAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.adapter;
2 |
3 | import org.objectweb.asm.Opcodes;
4 | import org.objectweb.asm.ClassVisitor;
5 | import org.objectweb.asm.ClassWriter;
6 | import org.objectweb.asm.MethodVisitor;
7 | import org.zzy.largeimage.Config;
8 | import org.zzy.largeimage.method.FrescoMethodAdapter;
9 | import org.zzy.largeimage.method.GlideMethodAdapter;
10 | import org.zzy.largeimage.method.ImageLoaderMethodAdapter;
11 | import org.zzy.largeimage.method.PicassoMethodAdapter;
12 |
13 |
14 | /**
15 | * ================================================
16 | * 作 者:ZhouZhengyi
17 | * 创建日期:2020/3/31 21:27
18 | * 描 述:对Glide,Picasso,Fresco,ImageLoader框架中
19 | * 的方法进行字节码替换
20 | * 修订历史:
21 | * ================================================
22 | */
23 | public class LargeImageClassAdapter extends ClassVisitor {
24 | private static final String IMAGELOADER_METHOD_NAME_DESC = "(Ljava/lang/String;Lcom/nostra13/universalimageloader/core/imageaware/ImageAware;Lcom/nostra13/universalimageloader/core/DisplayImageOptions;Lcom/nostra13/universalimageloader/core/assist/ImageSize;Lcom/nostra13/universalimageloader/core/listener/ImageLoadingListener;Lcom/nostra13/universalimageloader/core/listener/ImageLoadingProgressListener;)V";
25 | /**
26 | * 当前类名
27 | */
28 | private String className;
29 |
30 | public LargeImageClassAdapter(ClassVisitor classWriter) {
31 | super(Opcodes.ASM5, classWriter);
32 | }
33 |
34 | @Override
35 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
36 | super.visit(version, access, name, signature, superName, interfaces);
37 | this.className = name;
38 | }
39 |
40 | @Override
41 | public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) {
42 | MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
43 | //如果插件开关关闭,则不插入字节码
44 | if(!Config.getInstance().largeImagePluginSwitch()) {
45 | return mv;
46 | }
47 |
48 | // TODO: 2020/4/2 这里考虑做版本兼容
49 | //对Glide4.11版本的SingleRequest类的构造方法进行字节码修改
50 | if(className.equals("com/bumptech/glide/request/SingleRequest") && methodName.equals("") && desc!=null){
51 | return mv == null ? null : new GlideMethodAdapter(mv,access,methodName,desc);
52 | }
53 |
54 | //对picasso的Request类的构造方法进行字节码修改
55 | if(className.equals("com/squareup/picasso/Request") && methodName.equals("") && desc!=null){
56 | return mv == null ? null : new PicassoMethodAdapter(mv,access,methodName,desc);
57 | }
58 |
59 | //对Fresco的ImageRequest类的构造方法进行字节码修改
60 | if(className.equals("com/facebook/imagepipeline/request/ImageRequest") && methodName.equals("") && desc!=null){
61 | return mv == null ? null : new FrescoMethodAdapter(mv,access,methodName,desc);
62 | }
63 |
64 | //对ImageLoader的ImageLoader类的displayImage方法进行字节码修改
65 | if(className.equals("com/nostra13/universalimageloader/core/ImageLoader") && methodName.equals("displayImage") && desc.equals(IMAGELOADER_METHOD_NAME_DESC)){
66 | log(className,access,methodName,desc,signature);
67 | return mv == null ? null : new ImageLoaderMethodAdapter(mv,access,methodName,desc);
68 | }
69 | return mv;
70 | }
71 |
72 | private void log(String className, int access, String name, String desc, String signature) {
73 | System.out.println("LargeImageClassAdapter===matched====>" + " className===" + className + " access===" + access + " methodName===" + name + " desc===" + desc + " signature===" + signature);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/adapter/OkHttpClassAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.adapter;
2 |
3 | import org.objectweb.asm.ClassVisitor;
4 | import org.objectweb.asm.MethodVisitor;
5 | import org.objectweb.asm.Opcodes;
6 | import org.zzy.largeimage.Config;
7 | import org.zzy.largeimage.method.OkHttpMethodAdapter;
8 |
9 | /**
10 | * ================================================
11 | * 作 者:ZhouZhengyi
12 | * 创建日期:2020/4/5 7:31
13 | * 描 述:
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class OkHttpClassAdapter extends ClassVisitor {
18 |
19 | private String className;
20 |
21 | public OkHttpClassAdapter(ClassVisitor cv) {
22 | super(Opcodes.ASM5, cv);
23 | }
24 |
25 | @Override
26 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
27 | super.visit(version, access, name, signature, superName, interfaces);
28 | this.className = name;
29 | }
30 |
31 | @Override
32 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
33 | MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
34 | //如果插件开关关闭,则不插入字节码
35 | if(!Config.getInstance().largeImagePluginSwitch()) {
36 | return methodVisitor;
37 | }
38 | if(className.equals("okhttp3/OkHttpClient$Builder") && name.equals("") && desc.equals("()V")){
39 | return methodVisitor == null ? null : new OkHttpMethodAdapter(methodVisitor,access,name,desc);
40 | }
41 | return methodVisitor;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/adapter/UrlConnectionClassAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.adapter;
2 |
3 | import org.objectweb.asm.ClassVisitor;
4 | import org.objectweb.asm.MethodVisitor;
5 | import org.objectweb.asm.Opcodes;
6 | import org.zzy.largeimage.Config;
7 | import org.zzy.largeimage.method.UrlConnectionMethodAdapter;
8 |
9 | /**
10 | * ================================================
11 | * 作 者:ZhouZhengyi
12 | * 创建日期:2020/4/5 16:20
13 | * 描 述:Hook UrlConnection的目的是为了将
14 | * UrlConnection代理到OKhttp上面,这样通过网络下载图片就可以
15 | * 通过okhttp统一的处理。
16 | * 修订历史:
17 | * ================================================
18 | */
19 | public class UrlConnectionClassAdapter extends ClassVisitor {
20 |
21 | /**
22 | * 类名
23 | */
24 | private String className;
25 |
26 | public UrlConnectionClassAdapter(ClassVisitor cv) {
27 | super(Opcodes.ASM5, cv);
28 | }
29 |
30 | @Override
31 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
32 | super.visit(version, access, name, signature, superName, interfaces);
33 | this.className = name;
34 | }
35 |
36 | /**
37 | * 这个方法跟其他几个methodAdapter不一样
38 | * 其他的methodAdapter是根据类名和方法名来进行hook
39 | * 也就是说当访问到某个类的某个方法时进行
40 | * 而这个方法是,所有的类和方法都有可能存在hook,
41 | * 所以这里不做类和方法的判断
42 | * 作者: ZhouZhengyi
43 | * 创建时间: 2020/4/5 17:25
44 | */
45 | @Override
46 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
47 | MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
48 | //如果插件开关关闭,则不插入字节码
49 | if (!Config.getInstance().largeImagePluginSwitch()) {
50 | return methodVisitor;
51 | }
52 | return methodVisitor == null ? null : new UrlConnectionMethodAdapter(className, methodVisitor, access, name, desc);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/FrescoMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.commons.AdviceAdapter;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:ZhouZhengyi
10 | * 创建日期:2020/4/2 22:00
11 | * 描 述:对ImageRequest类的构造方法进行字节码修改
12 | * ImageRequest构造方法中会对mPostprocessor字段赋值,
13 | * 改字段是一个后处理器,我们通过hook改字段,可以得到
14 | * bitmap对象。
15 | * 修订历史:
16 | * ================================================
17 | */
18 | public class FrescoMethodAdapter extends AdviceAdapter {
19 |
20 | /**
21 | * Creates a new {@link AdviceAdapter}.
22 | *
23 | *
24 | * @param mv the method visitor to which this adapter delegates calls.
25 | * @param access the method's access flags
26 | * @param name the method's name.
27 | * @param desc the method's descriptor
28 | */
29 | public FrescoMethodAdapter( MethodVisitor mv, int access, String name, String desc) {
30 | super(Opcodes.ASM5, mv, access, name, desc);
31 | }
32 |
33 | /**
34 | * 方法进入时
35 | * 1.调用ImageRequestBuilder的getSourceUri()
36 | * 2.调用getPostprocessor()
37 | * 3.设置进FrescoHook的process方法
38 | * 4.将返回的Postprocessor再设置进ImageRequestBuilder
39 | * builder.setPostprocessor(FrescoHook.process(builder.getSourceUri(),builder.getPostprocessor(),getResizeOptions()));
40 | * 作者: ZhouZhengyi
41 | * 创建时间: 2020/4/2 23:53
42 | */
43 | @Override
44 | protected void onMethodEnter() {
45 | super.onMethodEnter();
46 | mv.visitVarInsn(ALOAD, 1);
47 | mv.visitVarInsn(ALOAD, 1);
48 | mv.visitMethodInsn(INVOKEVIRTUAL, "com/facebook/imagepipeline/request/ImageRequestBuilder", "getSourceUri", "()Landroid/net/Uri;", false);
49 | mv.visitVarInsn(ALOAD, 1);
50 | mv.visitMethodInsn(INVOKEVIRTUAL, "com/facebook/imagepipeline/request/ImageRequestBuilder", "getPostprocessor", "()Lcom/facebook/imagepipeline/request/Postprocessor;", false);
51 | mv.visitVarInsn(ALOAD, 1);
52 | mv.visitMethodInsn(INVOKEVIRTUAL, "com/facebook/imagepipeline/request/ImageRequestBuilder", "getResizeOptions", "()Lcom/facebook/imagepipeline/common/ResizeOptions;", false);
53 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/aop/fresco/FrescoHook", "process", "(Landroid/net/Uri;Lcom/facebook/imagepipeline/request/Postprocessor;Lcom/facebook/imagepipeline/common/ResizeOptions;)Lcom/facebook/imagepipeline/request/Postprocessor;", false);
54 | mv.visitMethodInsn(INVOKEVIRTUAL, "com/facebook/imagepipeline/request/ImageRequestBuilder", "setPostprocessor", "(Lcom/facebook/imagepipeline/request/Postprocessor;)Lcom/facebook/imagepipeline/request/ImageRequestBuilder;", false);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/GlideMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.commons.AdviceAdapter;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:ZhouZhengyi
10 | * 创建日期:2020/4/1 15:43
11 | * 描 述:对SingleRequest类中的构造方法进行字节码修改
12 | * 构造方法会对SingleRequest类进行初始化,其中有一个
13 | * requestListeners参数,它是一个list类型,
14 | * 在图片准备完毕时会对该list进行遍历回调,我们只需要在
15 | * 该list中添加我们自定义的listener,遍历时就会回调我们
16 | * 的方法,从而拿到图片数据。
17 | * 修订历史:
18 | * ================================================
19 | */
20 | public class GlideMethodAdapter extends AdviceAdapter {
21 |
22 | /**
23 | * Creates a new {@link AdviceAdapter}.
24 | *
25 | * @param mv the method visitor to which this adapter delegates calls.
26 | * @param access the method's access flags (see {@link Opcodes}).
27 | * @param name the method's name.
28 | * @param desc the method's descriptor ).
29 | */
30 | public GlideMethodAdapter( MethodVisitor mv, int access, String name, String desc) {
31 | super(Opcodes.ASM5, mv, access, name, desc);
32 | }
33 |
34 | /**
35 | * 方法退出时
36 | * 1.先拿到requestListeners
37 | * 2.然后对其进行修改
38 | * 3.将修改后的requestListeners设置回去
39 | * requestListeners=GlideHook.process(requestListeners);
40 | * 作者: ZhouZhengyi
41 | * 创建时间: 2020/4/1 15:51
42 | */
43 | @Override
44 | protected void onMethodExit(int opcode) {
45 | super.onMethodExit(opcode);
46 | mv.visitVarInsn(ALOAD, 0);
47 | mv.visitFieldInsn(GETFIELD, "com/bumptech/glide/request/SingleRequest", "requestListeners", "Ljava/util/List;");
48 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/aop/glide/GlideHook", "process", "(Ljava/util/List;)Ljava/util/List;", false);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/ImageLoaderMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.commons.AdviceAdapter;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:ZhouZhengyi
10 | * 创建日期:2020/4/3 11:49
11 | * 描 述:
12 | * 修订历史:
13 | * ================================================
14 | */
15 | public class ImageLoaderMethodAdapter extends AdviceAdapter {
16 |
17 | /**
18 | * Creates a new {@link AdviceAdapter}.
19 | * @param mv the method visitor to which this adapter delegates calls.
20 | * @param access the method's access flags
21 | * @param name the method's name.
22 | * @param desc the method's descriptor
23 | */
24 | public ImageLoaderMethodAdapter(MethodVisitor mv, int access, String name, String desc) {
25 | super(Opcodes.ASM5, mv, access, name, desc);
26 | }
27 |
28 | @Override
29 | protected void onMethodEnter() {
30 | super.onMethodEnter();
31 | mv.visitVarInsn(ALOAD, 5);
32 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/aop/imageloader/ImageLoaderHook", "process", "(Lcom/nostra13/universalimageloader/core/listener/ImageLoadingListener;)Lcom/nostra13/universalimageloader/core/listener/ImageLoadingListener;", false);
33 | mv.visitVarInsn(ASTORE, 5);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/OkHttpMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import com.android.ddmlib.Log;
4 |
5 | import org.objectweb.asm.MethodVisitor;
6 | import org.objectweb.asm.Opcodes;
7 | import org.objectweb.asm.commons.AdviceAdapter;
8 | import org.zzy.largeimage.Config;
9 |
10 | /**
11 | * ================================================
12 | * 作 者:ZhouZhengyi
13 | * 创建日期:2020/4/5 7:47
14 | * 描 述:
15 | * 修订历史:
16 | * ================================================
17 | */
18 | public class OkHttpMethodAdapter extends AdviceAdapter {
19 |
20 | /**
21 | * Creates a new {@link AdviceAdapter}.
22 | *
23 | * @param mv the method visitor to which this adapter delegates calls.
24 | * @param access the method's access flags (see {@link Opcodes}).
25 | * @param name the method's name.
26 | * @param desc the method's descriptor
27 | */
28 | public OkHttpMethodAdapter(MethodVisitor mv, int access, String name, String desc) {
29 | super(Opcodes.ASM5, mv, access, name, desc);
30 | }
31 |
32 |
33 | /**
34 | * 方法退出时插入
35 | * 这里不知道为什么在onMethodEnter方法插入会报空指针
36 | * interceptors.addAll(LargeImage.getInstance().getOkHttpInterceptors());
37 | * networkInterceptors.addAll(LargeImage.getInstance().getOkHttpNetworkInterceptors());
38 | * 作者: ZhouZhengyi
39 | * 创建时间: 2020/4/5 9:39
40 | */
41 | @Override
42 | protected void onMethodExit(int opcode) {
43 | super.onMethodExit(opcode);
44 | //添加应用拦截器
45 | mv.visitVarInsn(ALOAD, 0);
46 | mv.visitFieldInsn(GETFIELD, "okhttp3/OkHttpClient$Builder", "interceptors", "Ljava/util/List;");
47 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/LargeImage", "getInstance", "()Lorg/zzy/lib/largeimage/LargeImage;", false);
48 | mv.visitMethodInsn(INVOKEVIRTUAL, "org/zzy/lib/largeimage/LargeImage", "getOkHttpInterceptors", "()Ljava/util/List;", false);
49 | mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "addAll", "(Ljava/util/Collection;)Z", true);
50 | mv.visitInsn(POP);
51 | //添加网络拦截器
52 | mv.visitVarInsn(ALOAD, 0);
53 | mv.visitFieldInsn(GETFIELD, "okhttp3/OkHttpClient$Builder", "networkInterceptors", "Ljava/util/List;");
54 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/LargeImage", "getInstance", "()Lorg/zzy/lib/largeimage/LargeImage;", false);
55 | mv.visitMethodInsn(INVOKEVIRTUAL, "org/zzy/lib/largeimage/LargeImage", "getOkHttpNetworkInterceptors", "()Ljava/util/List;", false);
56 | mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "addAll", "(Ljava/util/Collection;)Z", true);
57 | mv.visitInsn(POP);
58 | //添加DNS
59 | mv.visitVarInsn(ALOAD, 0);
60 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/LargeImage", "getInstance", "()Lorg/zzy/lib/largeimage/LargeImage;", false);
61 | mv.visitMethodInsn(INVOKEVIRTUAL, "org/zzy/lib/largeimage/LargeImage", "getDns", "()Lokhttp3/Dns;", false);
62 | mv.visitFieldInsn(PUTFIELD, "okhttp3/OkHttpClient$Builder", "dns", "Lokhttp3/Dns;");
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/PicassoMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.commons.AdviceAdapter;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:ZhouZhengyi
10 | * 创建日期:2020/4/2 10:38
11 | * 描 述:对Request类的构造方法字节码进行修改
12 | * Request类构造方法中有一个List transformations
13 | * 参数,该参数会在piaccso得到bitmap以后进行遍历,对bitmap进行
14 | * 一些变换操作,我们可以插入自己的Transformation然后在里面
15 | * 得到我们想要的数据。
16 | * 修订历史:
17 | * ================================================
18 | */
19 | public class PicassoMethodAdapter extends AdviceAdapter {
20 |
21 | /**
22 | * Creates a new {@link AdviceAdapter}.
23 | *
24 | * @param mv the method visitor to which this adapter delegates calls.
25 | * @param access the method's access flags .
26 | * @param name the method's name.
27 | * @param desc the method's descriptor.
28 | */
29 | public PicassoMethodAdapter(MethodVisitor mv, int access, String name, String desc) {
30 | super(Opcodes.ASM5, mv, access, name, desc);
31 | }
32 |
33 | /**
34 | * 方法进入时
35 | * 1.拿到方法第一个参数Uri
36 | * 2.拿到方法第四个参数 List transformations
37 | * 3.把它们传入hook方法
38 | * 4.在方法中加入我们自己的Transformation
39 | * 5.将设置好以后的 List transformations返回给第四个参数
40 | * transformations = PicassoHook.process(uri,transformations,resourceId,targetWidth,targetHeight);
41 | * 作者: ZhouZhengyi
42 | * 创建时间: 2020/4/2 11:26
43 | */
44 | @Override
45 | protected void onMethodEnter() {
46 | super.onMethodEnter();
47 | mv.visitVarInsn(ALOAD, 1);
48 | mv.visitVarInsn(ALOAD, 4);
49 | mv.visitVarInsn(ILOAD, 2);
50 | mv.visitVarInsn(ILOAD, 5);
51 | mv.visitVarInsn(ILOAD, 6);
52 | mv.visitMethodInsn(INVOKESTATIC, "org/zzy/lib/largeimage/aop/picasso/PicassoHook", "process", "(Landroid/net/Uri;Ljava/util/List;III)Ljava/util/List;", false);
53 | mv.visitVarInsn(ASTORE, 4);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/method/UrlConnectionMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.method;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.commons.AdviceAdapter;
6 |
7 | /**
8 | * ================================================
9 | * 作 者:ZhouZhengyi
10 | * 创建日期:2020/4/5 16:50
11 | * 描 述:
12 | * 修订历史:
13 | * ================================================
14 | */
15 | public class UrlConnectionMethodAdapter extends AdviceAdapter {
16 |
17 | private String className;
18 |
19 | /**
20 | * Creates a new {@link AdviceAdapter}.
21 | *
22 | * @param mv the method visitor to which this adapter delegates calls.
23 | * @param access the method's access flags).
24 | * @param name the method's name.
25 | * @param desc the method's descriptor
26 | */
27 | public UrlConnectionMethodAdapter(String className, MethodVisitor mv, int access, String name, String desc) {
28 | super(Opcodes.ASM5, mv, access, name, desc);
29 | this.className = className;
30 | }
31 |
32 | /**
33 | * 这里复写的方法与其他的methodAdapter也不同
34 | * 其他的methodAdapter是在方法进入或者退出时操作
35 | * 而这个methodAdapter是根据指令比较的
36 | * 这个方法的意思是当方法被访问时调用
37 | * @param opcode 指令
38 | * @param owner 操作的类
39 | * @param name 方法名称
40 | * @param desc 方法描述 (参数)返回值类型
41 | * 作者: ZhouZhengyi
42 | * 创建时间: 2020/4/5 17:29
43 | */
44 | @Override
45 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
46 | //所有的类和方法,只要存在调用openConnection方法的指令,就进行hook
47 | if(opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/net/URL")
48 | && name.equals("openConnection")&& desc.equals("()Ljava/net/URLConnection;")){
49 | mv.visitMethodInsn(INVOKEVIRTUAL,"java/net/URL", "openConnection", "()Ljava/net/URLConnection;", false);
50 | super.visitMethodInsn(INVOKESTATIC,"org/zzy/lib/largeimage/aop/urlconnection/UrlConnectionHook","process","(Ljava/net/URLConnection;)Ljava/net/URLConnection;",false);
51 | }else if(opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/net/URL")
52 | && name.equals("openConnection")&& desc.equals("(Ljava/net/Proxy;)Ljava/net/URLConnection;")){
53 | //public URLConnection openConnection(Proxy proxy)
54 | mv.visitMethodInsn(INVOKEVIRTUAL,"java/net/URL", "openConnection", "(Ljava/net/Proxy;)Ljava/net/URLConnection;", false);
55 | super.visitMethodInsn(INVOKESTATIC,"org/zzy/lib/largeimage/aop/urlconnection/UrlConnectionHook","process","(Ljava/net/URLConnection;)Ljava/net/URLConnection;",false);
56 | }else{
57 | super.visitMethodInsn(opcode, owner, name, desc, itf);
58 | }
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/transform/LargeImageTransform.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.transform;
2 |
3 | import com.android.build.api.transform.Context;
4 | import com.android.build.api.transform.TransformException;
5 | import com.android.build.api.transform.TransformInput;
6 | import com.android.build.api.transform.TransformInvocation;
7 | import com.android.build.api.transform.TransformOutputProvider;
8 | import com.quinn.hunter.transform.HunterTransform;
9 | import com.quinn.hunter.transform.RunVariant;
10 |
11 | import org.gradle.api.Project;
12 | import org.zzy.largeimage.weaver.LargeImageWeaver;
13 |
14 | import java.io.IOException;
15 | import java.util.Collection;
16 |
17 | /**
18 | * ================================================
19 | * 作 者:ZhouZhengyi
20 | * 创建日期:2020/3/31 21:05
21 | * 描 述:使用Hunter框架,不需用传统方式写Transform
22 | * 修订历史:
23 | * ================================================
24 | */
25 | public class LargeImageTransform extends HunterTransform {
26 |
27 | public LargeImageTransform(Project project) {
28 | super(project);
29 | this.bytecodeWeaver = new LargeImageWeaver();
30 | }
31 |
32 | @Override
33 | public void transform(Context context, Collection inputs, Collection referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
34 | super.transform(context, inputs, referencedInputs, outputProvider, isIncremental);
35 | }
36 |
37 | @Override
38 | protected RunVariant getRunVariant() {
39 | return super.getRunVariant();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/transform/OkHttpTransform.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.transform;
2 |
3 | import com.android.build.api.transform.Context;
4 | import com.android.build.api.transform.TransformException;
5 | import com.android.build.api.transform.TransformInput;
6 | import com.android.build.api.transform.TransformOutputProvider;
7 | import com.quinn.hunter.transform.HunterTransform;
8 | import com.quinn.hunter.transform.RunVariant;
9 |
10 | import org.gradle.api.Project;
11 | import org.zzy.largeimage.weaver.OkHttpWeaver;
12 |
13 | import java.io.IOException;
14 | import java.util.Collection;
15 |
16 | /**
17 | * ================================================
18 | * 作 者:ZhouZhengyi
19 | * 创建日期:2020/4/5 7:28
20 | * 描 述:
21 | * 修订历史:
22 | * ================================================
23 | */
24 | public class OkHttpTransform extends HunterTransform {
25 |
26 | public OkHttpTransform(Project project) {
27 | super(project);
28 | this.bytecodeWeaver = new OkHttpWeaver();
29 | }
30 |
31 | @Override
32 | public void transform(Context context, Collection inputs, Collection referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
33 | super.transform(context, inputs, referencedInputs, outputProvider, isIncremental);
34 | }
35 |
36 | @Override
37 | protected RunVariant getRunVariant() {
38 | return super.getRunVariant();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/transform/UrlConnectionTransform.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.transform;
2 |
3 | import com.quinn.hunter.transform.HunterTransform;
4 |
5 | import org.gradle.api.Project;
6 | import org.zzy.largeimage.weaver.UrlConnectionWeaver;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:ZhouZhengyi
11 | * 创建日期:2020/4/5 16:22
12 | * 描 述:
13 | * 修订历史:
14 | * ================================================
15 | */
16 | public class UrlConnectionTransform extends HunterTransform {
17 |
18 | public UrlConnectionTransform(Project project) {
19 | super(project);
20 | this.bytecodeWeaver = new UrlConnectionWeaver();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/weaver/LargeImageWeaver.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.weaver;
2 |
3 | import com.quinn.hunter.transform.asm.BaseWeaver;
4 |
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.ClassWriter;
7 | import org.zzy.largeimage.adapter.LargeImageClassAdapter;
8 |
9 | /**
10 | * ================================================
11 | * 作 者:ZhouZhengyi
12 | * 创建日期:2020/3/31 21:24
13 | * 描 述:
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class LargeImageWeaver extends BaseWeaver {
18 |
19 | @Override
20 | protected ClassVisitor wrapClassWriter(ClassWriter classWriter) {
21 | return new LargeImageClassAdapter(classWriter);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/weaver/OkHttpWeaver.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.weaver;
2 |
3 | import com.quinn.hunter.transform.asm.BaseWeaver;
4 |
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.ClassWriter;
7 | import org.zzy.largeimage.adapter.OkHttpClassAdapter;
8 |
9 | /**
10 | * ================================================
11 | * 作 者:ZhouZhengyi
12 | * 创建日期:2020/4/5 7:29
13 | * 描 述:
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class OkHttpWeaver extends BaseWeaver {
18 |
19 | @Override
20 | protected ClassVisitor wrapClassWriter(ClassWriter classWriter) {
21 | return new OkHttpClassAdapter(classWriter);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/groovy/org/zzy/largeimage/weaver/UrlConnectionWeaver.java:
--------------------------------------------------------------------------------
1 | package org.zzy.largeimage.weaver;
2 |
3 | import com.quinn.hunter.transform.asm.BaseWeaver;
4 |
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.ClassWriter;
7 | import org.zzy.largeimage.adapter.UrlConnectionClassAdapter;
8 |
9 | /**
10 | * ================================================
11 | * 作 者:ZhouZhengyi
12 | * 创建日期:2020/4/5 16:24
13 | * 描 述:
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class UrlConnectionWeaver extends BaseWeaver {
18 |
19 | @Override
20 | protected ClassVisitor wrapClassWriter(ClassWriter classWriter) {
21 | return new UrlConnectionClassAdapter(classWriter);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/largeimage-plugin/src/main/resources/META-INF/gradle-plugins/largeimage-monitor.properties:
--------------------------------------------------------------------------------
1 | implementation-class=org.zzy.largeimage.LargeImageMonitorPlugin
--------------------------------------------------------------------------------
/largeimage-plugin/upload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.novoda.bintray-release'
2 | //gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false
3 | publish {
4 | def groupProjectID = 'org.zzy.largeimage'
5 | def artifactProjectID = 'large-image-monitor-plugin'
6 | def publishVersionID = "${rootProject.ext.android["pluginVersionName"]}"
7 |
8 | userOrg = 'zzy'
9 | repoName = "imageMonitor"
10 | groupId = groupProjectID
11 | artifactId = artifactProjectID
12 | publishVersion = publishVersionID
13 | desc = 'Oh hi, this is a library which can be monitor large image.'
14 | website = 'https://github.com/121880399/LargeImageMonitor'
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/largeimage/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/largeimage/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: 'upload.gradle'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.android["compileSdkVersion"]
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.android["minSdkVersion"]
9 | targetSdkVersion rootProject.ext.android["targetSdkVersion"]
10 | versionCode rootProject.ext.android["versionCode"]
11 | versionName rootProject.ext.android["versionName"]
12 |
13 | }
14 | lintOptions {
15 | abortOnError false
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | implementation rootProject.ext.dependencies["okhttp"]
30 | implementation rootProject.ext.dependencies["glide"]
31 | implementation rootProject.ext.dependencies["picasso"]
32 | implementation rootProject.ext.dependencies["fresco"]
33 | implementation rootProject.ext.dependencies["image-loader"]
34 | implementation rootProject.ext.dependencies["MMKV"]
35 | implementation (rootProject.ext.dependencies["FloatWindow"]){
36 | exclude module: 'support-v4'
37 | exclude module: 'support-compat'
38 | }
39 | implementation rootProject.ext.dependencies["androidx"]
40 | implementation (rootProject.ext.dependencies["recylcerview"]){
41 | exclude module: 'support-compat'
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/largeimage/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/consumer-rules.pro
--------------------------------------------------------------------------------
/largeimage/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/largeimage/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/largeimage/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/LargeImage.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage;
2 |
3 | import android.app.Application;
4 | import android.content.Intent;
5 | import android.util.Log;
6 | import android.view.View;
7 | import android.view.animation.BounceInterpolator;
8 | import android.widget.ImageView;
9 |
10 | import androidx.core.util.Preconditions;
11 |
12 | import com.tencent.mmkv.MMKV;
13 | import com.yhao.floatwindow.FloatWindow;
14 | import com.yhao.floatwindow.MoveType;
15 | import com.yhao.floatwindow.Screen;
16 |
17 | import org.zzy.lib.largeimage.activity.LargeImageListActivity;
18 | import org.zzy.lib.largeimage.aop.okhttp.LargeImageInterceptor;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | import okhttp3.Dns;
24 | import okhttp3.Interceptor;
25 |
26 | /**
27 | * ================================================
28 | * 作 者:ZhouZhengyi
29 | * 创建日期:2020/4/4 20:58
30 | * 描 述:门面类,主要用于初始化和配置各项参数
31 | * 修订历史:2020/4/13 v1.0.0
32 | * github:https://github.com/121880399/LargeImageMonitor
33 | * ================================================
34 | */
35 | public class LargeImage {
36 | public static String TAG = "LargeImageMonitor";
37 |
38 | public static Application APPLICATION;
39 |
40 | /**
41 | * 文件大小阈值 kb为单位
42 | */
43 | private double fileSizeThreshold = 500.0;
44 | /**
45 | * 内存大小阈值 kb为单位
46 | */
47 | private double memorySizeThreshold = 800.0;
48 |
49 | /**
50 | * 大图监控开关,这里只是存储数据的开关
51 | * 是否进行字节码修改需要在gradle文件中对插件进行设置
52 | */
53 | private volatile boolean largeImageOpen = true;
54 |
55 | /**
56 | * Okhttp应用拦截器
57 | */
58 | private List okHttpInterceptors = new ArrayList<>();
59 | /**
60 | * Okhttp网络拦截器
61 | */
62 | private List okHttpNetworkInterceptors = new ArrayList<>();
63 |
64 | /**
65 | * 自定义DNS,实现全局HttpDNS
66 | */
67 | private Dns mDns = Dns.SYSTEM;
68 |
69 | /**
70 | * 用来记录当前启动次数
71 | */
72 | private MMKV mmkv;
73 |
74 | /**
75 | * 最大删除值,表示启动多少次以后开始清理mmkv记录的大图信息
76 | */
77 | private int maxRemoveValue = 20;
78 |
79 | /**
80 | * 是否已经调用了install方法
81 | */
82 | private boolean isCalled = false;
83 |
84 | /**
85 | * 当前删除值
86 | */
87 | private int currentRemoveValue = 1;
88 |
89 | private LargeImage() {
90 |
91 | }
92 |
93 | private static class Holder {
94 | private static LargeImage INSTANCE = new LargeImage();
95 | }
96 |
97 | public static LargeImage getInstance() {
98 | return Holder.INSTANCE;
99 | }
100 |
101 | public LargeImage install(Application app) {
102 | if(null == app){
103 | throw new NullPointerException("You must set a applicatiion!");
104 | }
105 | if (isCalled) {
106 | Log.e(TAG, "Don't call this method repeatedly!");
107 | return this;
108 | }
109 | isCalled = true;
110 | APPLICATION = app;
111 | //默认添加拦截大图
112 | okHttpInterceptors.add(new LargeImageInterceptor());
113 | //初始化MMKV
114 | MMKV.initialize(app);
115 | isRemoveMmkv();
116 | ImageView ivIcon = new ImageView(app);
117 | ivIcon.setImageResource(R.drawable.ic_logo);
118 | FloatWindow.with(app)
119 | .setView(ivIcon)
120 | .setWidth(Screen.width, 0.2f) //设置悬浮控件宽高
121 | .setHeight(Screen.width, 0.2f)
122 | .setX(Screen.width, 0.8f)
123 | .setY(Screen.height, 0.3f)
124 | .setMoveType(MoveType.slide, 0, 0)
125 | .setMoveStyle(500, new BounceInterpolator())
126 | .setDesktopShow(false)
127 | .build();
128 | ivIcon.setOnClickListener(new View.OnClickListener() {
129 | @Override
130 | public void onClick(View v) {
131 | Intent intent = new Intent();
132 | intent.setClass(APPLICATION, LargeImageListActivity.class);
133 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
134 | APPLICATION.startActivity(intent);
135 | }
136 | });
137 | return this;
138 | }
139 |
140 | /**
141 | * 是否清理mmkv中的值
142 | * 作者: ZhouZhengyi
143 | * 创建时间: 2020/4/11 21:20
144 | */
145 | private void isRemoveMmkv() {
146 | mmkv = MMKV.mmkvWithID("LargeImage");
147 | if (!mmkv.containsKey("maxRemoveValue")) {
148 | mmkv.encode("maxRemoveValue", maxRemoveValue);
149 | } else {
150 | maxRemoveValue = mmkv.decodeInt("maxRemoveValue");
151 | }
152 | if (!mmkv.containsKey("currentRemoveValue")) {
153 | mmkv.encode("currentRemoveValue", 1);
154 | } else {
155 | currentRemoveValue = mmkv.decodeInt("currentRemoveValue");
156 | }
157 | //开启一个线程,给保存大图信息的mmkv中的每个entry的unUseCount加1
158 | // 当前启动次数已经达到了该清理mmkv的最大值,那么开启一个线程清理存放大图信息的mmkv
159 | Thread thread = new Thread(runnable);
160 | thread.start();
161 | }
162 |
163 | private Runnable runnable = new Runnable() {
164 | @Override
165 | public void run() {
166 | try {
167 | MMKV largeImageMmkv = LargeImageManager.getInstance().getMmkv();
168 | for (String key : largeImageMmkv.allKeys()) {
169 | LargeImageInfo largeImageInfo = largeImageMmkv.decodeParcelable(key, LargeImageInfo.class);
170 | //所有保存的信息未使用次数加一
171 | largeImageInfo.getUnUseCount().incrementAndGet();
172 | largeImageMmkv.encode(key, largeImageInfo);
173 | }
174 | if (currentRemoveValue >= maxRemoveValue) {
175 | for (String key : largeImageMmkv.allKeys()) {
176 | LargeImageInfo largeImageInfo = largeImageMmkv.decodeParcelable(key, LargeImageInfo.class);
177 | //如果该大图信息未使用次数大于最大删除值,那么说明该信息已经很久不用了,直接删除
178 | if (largeImageInfo.getUnUseCount().get() >= maxRemoveValue) {
179 | largeImageMmkv.remove(key);
180 | }
181 | }
182 | //清理完后,当前启动次数清零
183 | currentRemoveValue = 0;
184 | }
185 | currentRemoveValue++;
186 | mmkv.encode("currentRemoveValue", currentRemoveValue);
187 | }catch (Exception e){
188 | e.printStackTrace();
189 | }
190 | }
191 | };
192 |
193 | /**
194 | * 设置文件阈值 单位为kb
195 | *
196 | * @param fileSizeThreshold 文件阈值 单位kb
197 | * @return
198 | */
199 | public LargeImage setFileSizeThreshold(double fileSizeThreshold) {
200 | this.fileSizeThreshold = fileSizeThreshold;
201 | return this;
202 | }
203 |
204 | /**
205 | * 设置内存阈值 单位为kb
206 | *
207 | * @param memorySizeThreshold 内存阈值 单位为kb
208 | * @return
209 | */
210 | public LargeImage setMemorySizeThreshold(double memorySizeThreshold) {
211 | this.memorySizeThreshold = memorySizeThreshold;
212 | return this;
213 | }
214 |
215 | /**
216 | * 设置大图监控开关 true为开 false为关
217 | */
218 | public LargeImage setLargeImageOpen(boolean largeImageOpen) {
219 | this.largeImageOpen = largeImageOpen;
220 | return this;
221 | }
222 |
223 | /**
224 | * 因为实现了Okhttp的全局插桩,所以提供一个可以添加拦截器的方法
225 | * 让用户可以自定义拦截器实现自己项目和三方库的OKhttp全局监听
226 | *
227 | * @param interceptor 应用拦截器
228 | */
229 | public LargeImage addOkHttpInterceptor(Interceptor interceptor) {
230 | if (null != okHttpInterceptors) {
231 | okHttpInterceptors.add(interceptor);
232 | }
233 | return this;
234 | }
235 |
236 | /**
237 | * 添加Okhttp网络拦截器
238 | *
239 | * @param networkInterceptor 网络拦截器
240 | */
241 | public LargeImage addOkHttpNetworkInterceptor(Interceptor networkInterceptor) {
242 | if (null != okHttpNetworkInterceptors) {
243 | okHttpNetworkInterceptors.add(networkInterceptor);
244 | }
245 | return this;
246 | }
247 |
248 | /**
249 | * 可以指定自己定义的HTTPDNS
250 | *
251 | * @param dns 自定义DNS
252 | * @return
253 | */
254 | public LargeImage setDns(Dns dns) {
255 | this.mDns = dns;
256 | return this;
257 | }
258 |
259 | /**
260 | * 设置启动多少次,开始清除mmkv中的大图信息
261 | * 项目越大,该值可以适当调大
262 | */
263 | public LargeImage setMaxRemoveValue(int value) {
264 | //不建议少于20次
265 | if(value <= 20){
266 | value = 20;
267 | }
268 | //这里不设置this.maxRemoveValue的值是因为不想影响当前
269 | //的值,因为是否进行清理是在子线程中执行,只存放mmkv
270 | //那么只影响下次启动
271 | mmkv.encode("maxRemoveValue",value);
272 | return this;
273 | }
274 |
275 |
276 | public Dns getDns() {
277 | return mDns;
278 | }
279 |
280 | public List getOkHttpInterceptors() {
281 | return okHttpInterceptors;
282 | }
283 |
284 | public List getOkHttpNetworkInterceptors() {
285 | return okHttpNetworkInterceptors;
286 | }
287 |
288 | public double getFileSizeThreshold() {
289 | return fileSizeThreshold;
290 | }
291 |
292 | public double getMemorySizeThreshold() {
293 | return memorySizeThreshold;
294 | }
295 |
296 | public boolean isLargeImageOpen() {
297 | return largeImageOpen;
298 | }
299 |
300 | public int getMaxRemoveValue() {
301 | return maxRemoveValue;
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/LargeImageInfo.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.util.concurrent.atomic.AtomicInteger;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:ZhouZhengyi
11 | * 创建日期:2020/4/4 8:09
12 | * 描 述:大图的信息
13 | * 修订历史:
14 | * ================================================
15 | */
16 | public class LargeImageInfo implements Parcelable {
17 |
18 | /**
19 | * 图片地址
20 | */
21 | private String url;
22 |
23 | /**
24 | * 图片文件大小
25 | */
26 | private double fileSize;
27 |
28 | /**
29 | * 图片所占内存大小
30 | */
31 | private double memorySize;
32 |
33 | /**
34 | * 图片宽
35 | */
36 | private int width;
37 |
38 | /**
39 | * 图片高
40 | */
41 | private int height;
42 |
43 | /**
44 | * 加载图片所使用的框架
45 | */
46 | private String framework;
47 |
48 | /**
49 | * View的宽
50 | */
51 | private int targetWidth;
52 | /**
53 | * View的高
54 | */
55 | private int targetHeight;
56 |
57 | /**
58 | * 标识该记录未使用次数
59 | * 该值只要使用一次,就为0.如果一直不使用就会持续增加,
60 | * 增加到最大清理值还未使用,就说明该信息很可能已经不用了
61 | * 那么就删除掉。
62 | * 不要拿这个值当做依据,该值只用于评判那些很久未使用的数据
63 | * 对于使用过的数据,不要在意他的值是否准确,只要使用过肯定会被设置
64 | * 为0
65 | */
66 | private AtomicInteger unUseCount = new AtomicInteger();
67 |
68 | public AtomicInteger getUnUseCount() {
69 | return unUseCount;
70 | }
71 |
72 | public int getTargetWidth() {
73 | return targetWidth;
74 | }
75 |
76 | public void setTargetWidth(int targetWidth) {
77 | this.targetWidth = targetWidth;
78 | }
79 |
80 | public int getTargetHeight() {
81 | return targetHeight;
82 | }
83 |
84 | public void setTargetHeight(int targetHeight) {
85 | this.targetHeight = targetHeight;
86 | }
87 |
88 | public String getUrl() {
89 | return url;
90 | }
91 |
92 | public void setUrl(String url) {
93 | this.url = url;
94 | }
95 |
96 | public double getFileSize() {
97 | return fileSize;
98 | }
99 |
100 | public void setFileSize(double fileSize) {
101 | this.fileSize = fileSize;
102 | }
103 |
104 | public double getMemorySize() {
105 | return memorySize;
106 | }
107 |
108 | public void setMemorySize(double memorySize) {
109 | this.memorySize = memorySize;
110 | }
111 |
112 | public int getWidth() {
113 | return width;
114 | }
115 |
116 | public void setWidth(int width) {
117 | this.width = width;
118 | }
119 |
120 | public int getHeight() {
121 | return height;
122 | }
123 |
124 | public void setHeight(int height) {
125 | this.height = height;
126 | }
127 |
128 | public String getFramework() {
129 | return framework;
130 | }
131 |
132 | public void setFramework(String framework) {
133 | this.framework = framework;
134 | }
135 |
136 | public LargeImageInfo() {
137 | }
138 |
139 | @Override
140 | public int describeContents() {
141 | return 0;
142 | }
143 |
144 | @Override
145 | public void writeToParcel(Parcel dest, int flags) {
146 | dest.writeString(this.url);
147 | dest.writeDouble(this.fileSize);
148 | dest.writeDouble(this.memorySize);
149 | dest.writeInt(this.width);
150 | dest.writeInt(this.height);
151 | dest.writeString(this.framework);
152 | dest.writeInt(this.targetWidth);
153 | dest.writeInt(this.targetHeight);
154 | dest.writeSerializable(this.unUseCount);
155 | }
156 |
157 | protected LargeImageInfo(Parcel in) {
158 | this.url = in.readString();
159 | this.fileSize = in.readDouble();
160 | this.memorySize = in.readDouble();
161 | this.width = in.readInt();
162 | this.height = in.readInt();
163 | this.framework = in.readString();
164 | this.targetWidth = in.readInt();
165 | this.targetHeight = in.readInt();
166 | this.unUseCount = (AtomicInteger) in.readSerializable();
167 | }
168 |
169 | public static final Creator CREATOR = new Creator() {
170 | @Override
171 | public LargeImageInfo createFromParcel(Parcel source) {
172 | return new LargeImageInfo(source);
173 | }
174 |
175 | @Override
176 | public LargeImageInfo[] newArray(int size) {
177 | return new LargeImageInfo[size];
178 | }
179 | };
180 | }
181 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/Test.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage;
2 |
3 |
4 | import android.net.Uri;
5 |
6 | import com.bumptech.glide.request.RequestListener;
7 | import com.squareup.picasso.Transformation;
8 |
9 | import org.zzy.lib.largeimage.aop.glide.GlideHook;
10 | import org.zzy.lib.largeimage.aop.picasso.PicassoHook;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * ================================================
16 | * 作 者:ZhouZhengyi
17 | * 创建日期:2020/4/1 19:14
18 | * 描 述:用来测试生成ASM码
19 | * 修订历史:
20 | * ================================================
21 | */
22 | public class Test {
23 | // private List requestListeners;
24 | //模拟glide
25 | // private void init(){
26 | // GlideHook.process(requestListeners);
27 | // }
28 |
29 | //模拟picasso
30 | // private void init(Uri uri, List transformations, int resourceId, int targetWidth, int targetHeight){
31 | // transformations = PicassoHook.process(uri,transformations,resourceId,targetWidth,targetHeight);
32 | // }
33 |
34 | //模拟fresco
35 | // private void init(ImageRequestBuilder builder){
36 | // builder.setPostprocessor(FrescoHook.process(builder.getSourceUri(),builder.getPostprocessor(),builder.getResizeOptions()));
37 | // }
38 | //
39 | // public static class Builder {
40 | // private int a;
41 | // private Set mRequestListeners;
42 | // }
43 |
44 | //模拟imageloader
45 | // public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
46 | // ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
47 | // listener = ImageLoaderHook.process(listener);
48 | // }
49 | // final List interceptors = new ArrayList<>();
50 | // final List networkInterceptors = new ArrayList<>();
51 | //
52 | // private void init(){
53 | // interceptors.addAll(LargeImage.getInstance().getOkHttpInterceptors());
54 | // networkInterceptors.addAll(LargeImage.getInstance().getOkHttpNetworkInterceptors());
55 | // }
56 | // Dns dns;
57 | // public void openConnection() {
58 | // dns = LargeImage.getInstance().getDns();
59 | // }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/activity/LargeImageListActivity.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.activity;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.MenuItem;
6 | import android.view.View;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.appcompat.widget.Toolbar;
11 | import androidx.recyclerview.widget.DividerItemDecoration;
12 | import androidx.recyclerview.widget.LinearLayoutManager;
13 | import androidx.recyclerview.widget.RecyclerView;
14 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
15 |
16 | import org.zzy.lib.largeimage.LargeImageInfo;
17 | import org.zzy.lib.largeimage.LargeImageManager;
18 | import org.zzy.lib.largeimage.R;
19 | import org.zzy.lib.largeimage.adapter.LargeImageListAdapter;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Map;
24 |
25 | /**
26 | * ================================================
27 | * 作 者:ZhouZhengyi
28 | * 创建日期:2020/4/10 21:33
29 | * 描 述:用列表的形式显示超标图片,只显示本次APP启动以
30 | * 来超标图片,不会显示历史的。
31 | * 修订历史:
32 | * ================================================
33 | */
34 | public class LargeImageListActivity extends AppCompatActivity {
35 | private Toolbar mToolBar;
36 | private RecyclerView mRecyclerView;
37 | private LargeImageListAdapter mLargeImageAdapter;
38 | private List mLargeImageList;
39 | private SwipeRefreshLayout mRefresh;
40 | @Override
41 | protected void onCreate(@Nullable Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_largeimage_list);
44 | initView();
45 | initData();
46 | }
47 |
48 | private void initView(){
49 | mToolBar = findViewById(R.id.toolbar);
50 | mRecyclerView = findViewById(R.id.rv_largeImage);
51 | mRefresh = findViewById(R.id.refresh);
52 | mToolBar.inflateMenu(R.menu.toolbar);
53 | mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | finish();
57 | }
58 | });
59 | mToolBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
60 | @Override
61 | public boolean onMenuItemClick(MenuItem item) {
62 | if (item.getItemId() == R.id.action_setting) {
63 | Intent intent = new Intent(LargeImageListActivity.this,SettingActivity.class);
64 | startActivity(intent);
65 | }
66 | return true;
67 | }
68 | });
69 | mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
70 | @Override
71 | public void onRefresh() {
72 | Map stringLargeImageInfoMap = LargeImageManager.getInstance().getmInfoCache();
73 | if(mLargeImageList != null && mLargeImageList.size() > 0){
74 | mLargeImageList.clear();
75 | }
76 | for (Map.Entry entry : stringLargeImageInfoMap.entrySet()) {
77 | mLargeImageList.add(entry.getValue());
78 | }
79 | mLargeImageAdapter.notifyDataSetChanged();
80 | mRefresh.setRefreshing(false);
81 | }
82 | });
83 | }
84 |
85 | private void initData(){
86 | mLargeImageList = new ArrayList<>();
87 | Map stringLargeImageInfoMap = LargeImageManager.getInstance().getmInfoCache();
88 | for (Map.Entry entry : stringLargeImageInfoMap.entrySet()) {
89 | mLargeImageList.add(entry.getValue());
90 | }
91 | mLargeImageAdapter = new LargeImageListAdapter(this,mLargeImageList);
92 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
93 | mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
94 | mRecyclerView.setAdapter(mLargeImageAdapter);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/activity/SettingActivity.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.activity;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 | import android.widget.CheckBox;
6 | import android.widget.CompoundButton;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.appcompat.widget.Toolbar;
11 |
12 | import org.zzy.lib.largeimage.LargeImageManager;
13 | import org.zzy.lib.largeimage.R;
14 |
15 | /**
16 | * ================================================
17 | * 作 者:ZhouZhengyi
18 | * 创建日期:2020/4/11 20:04
19 | * 描 述:设置界面
20 | * 修订历史:
21 | * ================================================
22 | */
23 | public class SettingActivity extends AppCompatActivity {
24 | private Toolbar mToolBar;
25 | private CheckBox mMenuSwitch;
26 | @Override
27 | protected void onCreate(@Nullable Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_setting);
30 | initView();
31 | }
32 |
33 | private void initView(){
34 | mToolBar = findViewById(R.id.toolbar);
35 | mMenuSwitch = findViewById(R.id.menu_switch);
36 | mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | finish();
40 | }
41 | });
42 | mMenuSwitch.setChecked(LargeImageManager.getInstance().isOpenDialog());
43 | mMenuSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
44 | @Override
45 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
46 | LargeImageManager.getInstance().setOpenDialog(!LargeImageManager.getInstance().isOpenDialog());
47 | }
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/adapter/LargeImageListAdapter.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.adapter;
2 |
3 | import android.content.ClipData;
4 | import android.content.ClipboardManager;
5 | import android.content.Context;
6 | import android.graphics.Bitmap;
7 | import android.text.TextUtils;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 |
17 | import androidx.annotation.Nullable;
18 | import androidx.recyclerview.widget.RecyclerView;
19 |
20 | import org.zzy.lib.largeimage.LargeImage;
21 | import org.zzy.lib.largeimage.LargeImageInfo;
22 | import org.zzy.lib.largeimage.LargeImageManager;
23 | import org.zzy.lib.largeimage.R;
24 | import org.zzy.lib.largeimage.util.ResHelper;
25 |
26 | import java.text.DecimalFormat;
27 | import java.util.List;
28 |
29 | /**
30 | * ================================================
31 | * 作 者:ZhouZhengyi
32 | * 创建日期:2020/4/11 9:39
33 | * 描 述:
34 | * 修订历史:
35 | * ================================================
36 | */
37 | public class LargeImageListAdapter extends RecyclerView.Adapter {
38 |
39 | private DecimalFormat mDecimalFormat = new DecimalFormat("0.00");
40 | private List mData;
41 | private Context mContext;
42 | public LargeImageListAdapter(Context context,@Nullable List data) {
43 | this.mData = data;
44 | this.mContext = context;
45 | }
46 |
47 | @androidx.annotation.NonNull
48 | @Override
49 | public MyHolder onCreateViewHolder(@androidx.annotation.NonNull ViewGroup parent, int viewType) {
50 | View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_custom,parent,false);
51 | MyHolder holder = new MyHolder(view);
52 | return holder;
53 | }
54 |
55 | @Override
56 | public void onBindViewHolder(@androidx.annotation.NonNull MyHolder holder, int position) {
57 | LargeImageInfo largeImageInfo = mData.get(position);
58 | //设置文件大小
59 | setFileSize(largeImageInfo.getFileSize(), holder.llFileSize,holder.tvFileSize, holder.ivFileSize);
60 | //设置内存大小
61 | setMemorySize(largeImageInfo.getMemorySize(), holder.llMemorySize,
62 | holder.tvMemorySize, holder.ivMemorySize);
63 | //设置图片尺寸
64 | setImageSize(largeImageInfo.getWidth(), largeImageInfo.getHeight(), holder.tvSize);
65 | //设置View尺寸
66 | setViewSize(largeImageInfo.getTargetWidth(), largeImageInfo.getTargetHeight(), holder.tvViewSize);
67 | //设置图片地址
68 | setImageUrl(largeImageInfo.getUrl(), holder.tvImageUrl);
69 | Bitmap bitmap = LargeImageManager.getInstance().getmBitmapCache().get(largeImageInfo.getUrl());
70 | //设置图片
71 | holder.ivThumb.setImageBitmap(bitmap);
72 | }
73 |
74 | @Override
75 | public int getItemCount() {
76 | return mData == null ? 0 : mData.size();
77 | }
78 |
79 |
80 | private void setImageUrl(final String url, TextView tvImageUrl) {
81 | if (TextUtils.isEmpty(url)) {
82 | tvImageUrl.setVisibility(View.GONE);
83 | } else {
84 | tvImageUrl.setVisibility(View.VISIBLE);
85 | if(!url.startsWith("http") && !url.startsWith("https")){
86 | String tempUrl = url;
87 | if(url.contains("/")){
88 | int index = url.lastIndexOf("/");
89 | tempUrl =url.substring(index+1,url.length());
90 | }
91 | try {
92 | final String resourceName = LargeImage.APPLICATION.getApplicationContext().getResources().getResourceName(Integer.parseInt(tempUrl));
93 | if(TextUtils.isEmpty(resourceName)){
94 | tvImageUrl.setText(ResHelper.getString(R.string.large_image_url, "本地图片"));
95 | }else {
96 | tvImageUrl.setText(ResHelper.getString(R.string.large_image_url, resourceName));
97 | }
98 | tvImageUrl.setOnClickListener(new View.OnClickListener() {
99 | @Override
100 | public void onClick(View v) {
101 | copyToClipboard(resourceName);
102 | }
103 | });
104 | } catch (NumberFormatException e){
105 | //不是请求网络,也没用resId,统一显示为本地图片
106 | e.printStackTrace();
107 | tvImageUrl.setText(ResHelper.getString(R.string.large_image_url, "本地图片"));
108 | }
109 | }else{
110 | tvImageUrl.setText(ResHelper.getString(R.string.large_image_url, url));
111 | tvImageUrl.setOnClickListener(new View.OnClickListener() {
112 | @Override
113 | public void onClick(View v) {
114 | copyToClipboard(url);
115 | }
116 | });
117 | }
118 | }
119 | }
120 |
121 | private void copyToClipboard(String resourceName) {
122 | try {
123 | //获取剪贴板管理器
124 | ClipboardManager cm =
125 | (ClipboardManager) LargeImage.APPLICATION.getSystemService(Context.CLIPBOARD_SERVICE);
126 | //创建普通字符型ClipData
127 | ClipData clipData = ClipData.newPlainText("Label", resourceName);
128 | cm.setPrimaryClip(clipData);
129 | Toast.makeText(LargeImage.APPLICATION.getApplicationContext(), "复制成功!", Toast.LENGTH_SHORT).show();
130 | } catch (Exception e) {
131 | Toast.makeText(LargeImage.APPLICATION.getApplicationContext(), "复制失败!", Toast.LENGTH_SHORT).show();
132 | e.printStackTrace();
133 | }
134 | }
135 |
136 | private void setViewSize(int targetWidth, int targetHeigh, TextView tvViewSize) {
137 | if (targetWidth <= 0 || targetHeigh <= 0) {
138 | tvViewSize.setVisibility(View.GONE);
139 | } else {
140 | tvViewSize.setVisibility(View.VISIBLE);
141 | StringBuilder sb = new StringBuilder();
142 | sb.append(targetWidth).append("*").append(targetHeigh);
143 | tvViewSize.setText(ResHelper.getString(R.string.large_view_size, sb.toString()));
144 | }
145 | }
146 |
147 | private void setImageSize(int width, int height, TextView tvSize) {
148 | if (width <= 0 && height <= 0) {
149 | tvSize.setVisibility(View.GONE);
150 | } else {
151 | tvSize.setVisibility(View.VISIBLE);
152 | StringBuilder sb = new StringBuilder();
153 | sb.append(width).append("*").append(height);
154 | tvSize.setText(ResHelper.getString(R.string.large_image_size, sb.toString()));
155 | }
156 | }
157 |
158 | private void setMemorySize(double memorySize, LinearLayout llMemorySize, TextView tvMemorySize, ImageView ivMemorySize) {
159 | if (memorySize <= 0) {
160 | llMemorySize.setVisibility(View.GONE);
161 | } else {
162 | llMemorySize.setVisibility(View.VISIBLE);
163 | if (memorySize > LargeImage.getInstance().getMemorySizeThreshold()) {
164 | ivMemorySize.setVisibility(View.VISIBLE);
165 | } else {
166 | ivMemorySize.setVisibility(View.GONE);
167 | }
168 | double size = memorySize / 1024;
169 | tvMemorySize.setText(ResHelper.getString(R.string.large_image_memory_size, mDecimalFormat.format(size)));
170 | }
171 | }
172 |
173 | private void setFileSize(double fileSize, LinearLayout llFileSize, TextView tvFileSize, ImageView ivFileSize) {
174 | if (fileSize <= 0) {
175 | llFileSize.setVisibility(View.GONE);
176 | } else {
177 | llFileSize.setVisibility(View.VISIBLE);
178 | if (fileSize > LargeImage.getInstance().getFileSizeThreshold()) {
179 | ivFileSize.setVisibility(View.VISIBLE);
180 | } else {
181 | ivFileSize.setVisibility(View.GONE);
182 | }
183 | tvFileSize.setText(ResHelper.getString(R.string.large_image_file_size, mDecimalFormat.format(fileSize)));
184 | }
185 | }
186 |
187 |
188 | class MyHolder extends RecyclerView.ViewHolder{
189 | LinearLayout llMemorySize;
190 | TextView tvMemorySize;
191 | ImageView ivMemorySize;
192 | LinearLayout llFileSize;
193 | TextView tvFileSize;
194 | ImageView ivFileSize;
195 | TextView tvSize;
196 | TextView tvViewSize;
197 | TextView tvImageUrl;
198 | ImageView ivThumb;
199 |
200 | public MyHolder(@androidx.annotation.NonNull View itemView) {
201 | super(itemView);
202 | llMemorySize = itemView.findViewById(R.id.ll_memory_size);
203 | tvMemorySize = itemView.findViewById(R.id.tv_memory_size);
204 | ivMemorySize = itemView.findViewById(R.id.iv_memory_size);
205 | llFileSize = itemView.findViewById(R.id.ll_file_size);
206 | tvFileSize = itemView.findViewById(R.id.tv_file_size);
207 | ivFileSize = itemView.findViewById(R.id.iv_file_size);
208 | tvSize = itemView.findViewById(R.id.tv_size);
209 | tvViewSize = itemView.findViewById(R.id.tv_view_size);
210 | tvImageUrl = itemView.findViewById(R.id.tv_image_url);
211 | ivThumb = itemView.findViewById(R.id.iv_thumb);
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/fresco/FrescoHook.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.fresco;
2 |
3 | import android.net.Uri;
4 |
5 | import com.facebook.imagepipeline.common.ResizeOptions;
6 | import com.facebook.imagepipeline.core.ImagePipelineConfig;
7 | import com.facebook.imagepipeline.listener.RequestListener;
8 | import com.facebook.imagepipeline.request.Postprocessor;
9 |
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | /**
14 | * ================================================
15 | * 作 者:ZhouZhengyi
16 | * 创建日期:2020/4/2 22:08
17 | * 描 述:
18 | * 修订历史:
19 | * ================================================
20 | */
21 | public class FrescoHook {
22 |
23 | public static Postprocessor process(Uri uri, Postprocessor postprocessor,ResizeOptions resizeOptions){
24 | return new FrescoLargeImageProcessor(postprocessor,uri,resizeOptions);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/fresco/FrescoLargeImageProcessor.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.fresco;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.net.Uri;
6 |
7 | import com.facebook.cache.common.CacheKey;
8 | import com.facebook.common.references.CloseableReference;
9 | import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
10 | import com.facebook.imagepipeline.common.ResizeOptions;
11 | import com.facebook.imagepipeline.nativecode.Bitmaps;
12 | import com.facebook.imagepipeline.request.Postprocessor;
13 |
14 | import org.zzy.lib.largeimage.LargeImageManager;
15 |
16 | import static com.facebook.imagepipeline.request.BasePostprocessor.FALLBACK_BITMAP_CONFIGURATION;
17 |
18 | /**
19 | * ================================================
20 | * 作 者:ZhouZhengyi
21 | * 创建日期:2020/4/4 10:35
22 | * 描 述:
23 | * 修订历史:
24 | * ================================================
25 | */
26 | public class FrescoLargeImageProcessor implements Postprocessor {
27 |
28 | private Postprocessor mOriginProcessor;
29 | private Uri mUri;
30 | private ResizeOptions mResizeOptions;
31 | public FrescoLargeImageProcessor(Postprocessor mOriginProcessor, Uri mUri, ResizeOptions resizeOptions) {
32 | this.mOriginProcessor = mOriginProcessor;
33 | this.mUri = mUri;
34 | this.mResizeOptions = resizeOptions;
35 | }
36 |
37 | @Override
38 | public CloseableReference process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) {
39 | int width = 0;
40 | int height = 0;
41 | if(null != mResizeOptions){
42 | width = mResizeOptions.width;
43 | height = mResizeOptions.height;
44 | }
45 | sourceBitmap = LargeImageManager.getInstance().transform(mUri.toString(),sourceBitmap,"Fresco",width,height);
46 | if(null != mOriginProcessor){
47 | return mOriginProcessor.process(sourceBitmap,bitmapFactory);
48 | }
49 | final Bitmap.Config sourceBitmapConfig = sourceBitmap.getConfig();
50 | CloseableReference destBitmapRef =
51 | bitmapFactory.createBitmapInternal(
52 | sourceBitmap.getWidth(),
53 | sourceBitmap.getHeight(),
54 | sourceBitmapConfig != null ? sourceBitmapConfig : FALLBACK_BITMAP_CONFIGURATION);
55 | try {
56 | process(destBitmapRef.get(),sourceBitmap);
57 | return CloseableReference.cloneOrNull(destBitmapRef);
58 | }finally {
59 | CloseableReference.closeSafely(destBitmapRef);
60 | }
61 | }
62 |
63 | public void process(Bitmap destBitmap, Bitmap sourceBitmap) {
64 | internalCopyBitmap(destBitmap, sourceBitmap);
65 | process(destBitmap);
66 | }
67 |
68 | public void process(Bitmap bitmap) {
69 | }
70 |
71 | private static void internalCopyBitmap(Bitmap destBitmap,Bitmap sourceBitmap){
72 | if(destBitmap.getConfig() == sourceBitmap.getConfig()){
73 | Bitmaps.copyBitmap(destBitmap, sourceBitmap);
74 | }else{
75 | Canvas canvas = new Canvas(destBitmap);
76 | canvas.drawBitmap(sourceBitmap,0,0,null);
77 | }
78 | }
79 |
80 | @Override
81 | public String getName() {
82 | if(null != mOriginProcessor){
83 | return mOriginProcessor.getName();
84 | }
85 | return "LargeImage&Fresco&FrescoLargeImageProcessor";
86 | }
87 |
88 | @Override
89 | public CacheKey getPostprocessorCacheKey() {
90 | if(null != mOriginProcessor){
91 | return mOriginProcessor.getPostprocessorCacheKey();
92 | }
93 | return null;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/glide/GlideHook.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.glide;
2 |
3 | import com.bumptech.glide.request.RequestListener;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * ================================================
10 | * 作 者:ZhouZhengyi
11 | * 创建日期:2020/4/1 16:30
12 | * 描 述:将该类的process方法注入到
13 | * com.bumptech.glide.request.SingleRequest的构造方法中
14 | * 修订历史:
15 | * ================================================
16 | */
17 | public class GlideHook {
18 |
19 | public static List process(List requestListener){
20 | if(requestListener == null ){
21 | requestListener = new ArrayList<>();
22 | }
23 | requestListener.add(new GlideLargeImageListener());
24 | return requestListener;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/glide/GlideLargeImageListener.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.glide;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.drawable.BitmapDrawable;
5 | import android.view.View;
6 |
7 | import androidx.annotation.Nullable;
8 |
9 | import com.bumptech.glide.load.DataSource;
10 | import com.bumptech.glide.load.engine.GlideException;
11 | import com.bumptech.glide.request.Request;
12 | import com.bumptech.glide.request.RequestListener;
13 | import com.bumptech.glide.request.target.BitmapImageViewTarget;
14 | import com.bumptech.glide.request.target.Target;
15 | import com.bumptech.glide.request.target.ViewTarget;
16 |
17 | import org.zzy.lib.largeimage.LargeImageManager;
18 |
19 | /**
20 | * ================================================
21 | * 作 者:ZhouZhengyi
22 | * 创建日期:2020/4/1 19:55
23 | * 描 述:当资源加载完成后,会回调这个类里面的onResourceReady方法
24 | * 在里面编写自己的逻辑
25 | * 修订历史:
26 | * ================================================
27 | */
28 | public class GlideLargeImageListener implements RequestListener {
29 |
30 |
31 | @Override
32 | public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
33 | return false;
34 | }
35 |
36 | @Override
37 | public boolean onResourceReady(R resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
38 | int width =0;
39 | int heigh =0;
40 | if(target instanceof ViewTarget){
41 | View view = ((ViewTarget) target).getView();
42 | width = view.getWidth();
43 | heigh = view.getHeight();
44 | }
45 | if(resource instanceof Bitmap){
46 | LargeImageManager.getInstance().transform(model.toString(),(Bitmap)resource,"Glide",width,heigh);
47 | }else if(resource instanceof BitmapDrawable){
48 | LargeImageManager.getInstance().transform(model.toString(),(BitmapDrawable) resource,"Glide",width,heigh);
49 | }
50 | return false;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/imageloader/ImageLoaderHook.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.imageloader;
2 |
3 | import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
4 |
5 | /**
6 | * ================================================
7 | * 作 者:ZhouZhengyi
8 | * 创建日期:2020/4/3 16:27
9 | * 描 述:
10 | * 修订历史:
11 | * ================================================
12 | */
13 | public class ImageLoaderHook {
14 |
15 | public static ImageLoadingListener process(ImageLoadingListener listener){
16 | return new ImageLoaderLargeImageListener(listener);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/imageloader/ImageLoaderLargeImageListener.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.imageloader;
2 |
3 | import android.graphics.Bitmap;
4 | import android.view.View;
5 |
6 | import com.nostra13.universalimageloader.core.assist.FailReason;
7 | import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
8 | import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
9 |
10 | import org.zzy.lib.largeimage.LargeImageManager;
11 |
12 | /**
13 | * ================================================
14 | * 作 者:ZhouZhengyi
15 | * 创建日期:2020/4/3 16:37
16 | * 描 述:
17 | * 修订历史:
18 | * ================================================
19 | */
20 | public class ImageLoaderLargeImageListener implements ImageLoadingListener {
21 |
22 | /**
23 | * 原始Listener
24 | */
25 | private ImageLoadingListener mOriginListener;
26 |
27 | public ImageLoaderLargeImageListener(ImageLoadingListener listener){
28 | if(null == listener){
29 | mOriginListener = new SimpleImageLoadingListener();
30 | }else {
31 | mOriginListener = listener;
32 | }
33 | }
34 |
35 | @Override
36 | public void onLoadingStarted(String imageUri, View view) {
37 | mOriginListener.onLoadingStarted(imageUri,view);
38 | }
39 |
40 | @Override
41 | public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
42 | mOriginListener.onLoadingFailed(imageUri,view,failReason);
43 | }
44 |
45 | @Override
46 | public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
47 | LargeImageManager.getInstance().transform(imageUri,loadedImage,"ImageLoader",view.getWidth(),view.getHeight());
48 | mOriginListener.onLoadingComplete(imageUri, view, loadedImage);
49 | }
50 |
51 | @Override
52 | public void onLoadingCancelled(String imageUri, View view) {
53 | mOriginListener.onLoadingCancelled(imageUri, view);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/okhttp/LargeImageInterceptor.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.okhttp;
2 |
3 | import android.text.TextUtils;
4 |
5 | import org.zzy.lib.largeimage.LargeImageManager;
6 |
7 | import java.io.IOException;
8 |
9 | import okhttp3.Interceptor;
10 | import okhttp3.Request;
11 | import okhttp3.Response;
12 |
13 | /**
14 | * ================================================
15 | * 作 者:ZhouZhengyi
16 | * 创建日期:2020/4/5 8:43
17 | * 描 述:
18 | * 修订历史:
19 | * ================================================
20 | */
21 | public class LargeImageInterceptor implements Interceptor {
22 |
23 |
24 | @Override
25 | public Response intercept(Chain chain) throws IOException {
26 | //发出请求时不拦截
27 | Request request = chain.request();
28 | Response response = chain.proceed(request);
29 | //拦截响应
30 | String header = response.header("Content-Type");
31 | //如果是图片类型则拦截
32 | if(isImage(header)){
33 | process(response);
34 | }
35 | return response;
36 | }
37 |
38 | private void process(Response response){
39 | String header = response.header("Content-Length");
40 | //判断是否有数据
41 | if(!TextUtils.isEmpty(header)){
42 | try {
43 | //parseInt有可能抛出异常
44 | LargeImageManager.getInstance().saveImageInfo(response.request().url().toString(), Integer.parseInt(header));
45 | }catch (Exception e){
46 | e.printStackTrace();
47 | }
48 | }
49 | }
50 |
51 | /**
52 | * 判断是否是图片
53 | * 作者: ZhouZhengyi
54 | * 创建时间: 2020/4/5 9:45
55 | */
56 | private boolean isImage(String contentType){
57 | String mimeType = stripContentExtras(contentType);
58 | if(mimeType.startsWith("image")){
59 | return true;
60 | }else{
61 | return false;
62 | }
63 | }
64 |
65 | private String stripContentExtras(String contentType){
66 | int index = contentType.indexOf(';');
67 | return (index >= 0) ? contentType.substring(0, index) : contentType;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/picasso/PicassoHook.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.picasso;
2 |
3 | import android.net.Uri;
4 |
5 | import com.squareup.picasso.Transformation;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * ================================================
12 | * 作 者:ZhouZhengyi
13 | * 创建日期:2020/4/2 10:47
14 | * 描 述:将process方法注入到
15 | * com.squareup.picasso.Request的构造方法中
16 | * 修订历史:
17 | * ================================================
18 | */
19 | public class PicassoHook {
20 |
21 | public static List process(Uri uri, List transformations,int resourceId,int targetWidth, int targetHeight){
22 | if(null == transformations){
23 | transformations = new ArrayList<>();
24 | }
25 | transformations.add(new PicassoLargeImageTransformation(uri,resourceId,targetWidth,targetHeight));
26 | return transformations;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/picasso/PicassoLargeImageTransformation.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.picasso;
2 |
3 | import android.graphics.Bitmap;
4 | import android.net.Uri;
5 |
6 | import com.squareup.picasso.Transformation;
7 |
8 | import org.zzy.lib.largeimage.LargeImageManager;
9 |
10 | /**
11 | * ================================================
12 | * 作 者:ZhouZhengyi
13 | * 创建日期:2020/4/2 11:33
14 | * 描 述:
15 | * 修订历史:
16 | * ================================================
17 | */
18 | public class PicassoLargeImageTransformation implements Transformation {
19 |
20 | private String mUri;
21 | private int targetWidth;
22 | private int targetHeight;
23 |
24 | public PicassoLargeImageTransformation(Uri uri,int resourceId,int targetWidth, int targetHeight){
25 | if(uri == null){
26 | mUri = String.valueOf(resourceId);
27 | }else{
28 | mUri = uri.toString();
29 | }
30 | this.targetWidth=targetWidth;
31 | this.targetHeight=targetHeight;
32 | }
33 |
34 | @Override
35 | public Bitmap transform(Bitmap source) {
36 | return LargeImageManager.getInstance().transform(mUri,source,"Picasso",targetWidth,targetHeight);
37 | }
38 |
39 | @Override
40 | public String key() {
41 | return "LargeImage&Picasso&PicassoLargeImageTransformation";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/aop/urlconnection/UrlConnectionHook.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.aop.urlconnection;
2 |
3 | import org.zzy.lib.largeimage.aop.okhttp.LargeImageInterceptor;
4 |
5 | import java.net.MalformedURLException;
6 | import java.net.URL;
7 | import java.net.URLConnection;
8 |
9 | import okhttp3.HttpUrl;
10 | import okhttp3.Interceptor;
11 | import okhttp3.OkHttpClient;
12 |
13 | /**
14 | * ================================================
15 | * 作 者:ZhouZhengyi
16 | * 创建日期:2020/4/5 16:36
17 | * 描 述:
18 | * 修订历史:
19 | * ================================================
20 | */
21 | public class UrlConnectionHook {
22 |
23 | public static URLConnection process (URLConnection urlConnection){
24 | try {
25 | String host = HttpUrl.parse(urlConnection.getURL().toString()).host();
26 | return createOkHttpUrlConnection(urlConnection);
27 | }catch (Exception e){
28 | e.printStackTrace();
29 | }
30 | return urlConnection;
31 | }
32 |
33 | /**
34 | * 构建一个OkhttpClient,并且判断当前是http还是https,返回相应的OkhttpUrlConnection
35 | * ObsoleteUrlFactory类在OKhttp3.14版本开始就被删掉了,不是因为有什么问题,只是不推荐使用了
36 | * 作者: ZhouZhengyi
37 | * 创建时间: 2020/4/5 20:47
38 | */
39 | private static URLConnection createOkHttpUrlConnection(URLConnection urlConnection) throws MalformedURLException {
40 | OkHttpClient.Builder builder = new OkHttpClient.Builder();
41 | addInterceptor(builder);
42 | OkHttpClient client = builder.build();
43 |
44 | String strUrl = urlConnection.getURL().toString();
45 | URL url = new URL(strUrl);
46 | String protocol = url.getProtocol().toLowerCase();
47 | if(protocol.equalsIgnoreCase("http")){
48 | return new ObsoleteUrlFactory.OkHttpURLConnection(url,client);
49 | }
50 | if (protocol.equalsIgnoreCase("https")){
51 | return new ObsoleteUrlFactory.OkHttpsURLConnection(url,client);
52 | }
53 | return urlConnection;
54 | }
55 |
56 | private static void addInterceptor(OkHttpClient.Builder builder) {
57 | //判断当前是否已经添加过全局的Okhttp拦截器,如果添加了就返回
58 | for (Interceptor interceptor : builder.interceptors()) {
59 | if(interceptor instanceof LargeImageInterceptor){
60 | return;
61 | }
62 | }
63 | builder.addInterceptor(new LargeImageInterceptor());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/util/ConvertUtils.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.util;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.graphics.PixelFormat;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.graphics.drawable.Drawable;
8 |
9 | import androidx.annotation.IntDef;
10 |
11 | import java.lang.annotation.Retention;
12 | import java.lang.annotation.RetentionPolicy;
13 |
14 | /**
15 | * ================================================
16 | * 作 者:ZhouZhengyi
17 | * 创建日期:2020/4/4 8:58
18 | * 描 述:该工具类用于转换,里面的方法裁剪与AndroidUtilCode
19 | * 框架。
20 | * 修订历史:
21 | * ================================================
22 | */
23 | public class ConvertUtils {
24 |
25 | public static final int BYTE = 1;
26 | public static final int KB = 1024;
27 | public static final int MB = 1048576;
28 | public static final int GB = 1073741824;
29 |
30 | @IntDef({BYTE, KB, MB, GB})
31 | @Retention(RetentionPolicy.SOURCE)
32 | public @interface Unit {
33 | }
34 |
35 | /**
36 | * Size of byte to size of memory in unit.
37 | *
38 | * @param byteSize Size of byte.
39 | * @param unit The unit of memory size.
40 | * @return size of memory in unit
41 | */
42 | public static double byte2MemorySize(final long byteSize,
43 | @Unit final int unit) {
44 | if (byteSize < 0) return -1;
45 | return (double) byteSize / unit;
46 | }
47 |
48 | /**
49 | * Drawable to bitmap.
50 | *
51 | * @param drawable The drawable.
52 | * @return bitmap
53 | */
54 | public static Bitmap drawable2Bitmap(final Drawable drawable) {
55 | if (drawable instanceof BitmapDrawable) {
56 | BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
57 | if (bitmapDrawable.getBitmap() != null) {
58 | return bitmapDrawable.getBitmap();
59 | }
60 | }
61 | Bitmap bitmap;
62 | if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
63 | bitmap = Bitmap.createBitmap(1, 1,
64 | drawable.getOpacity() != PixelFormat.OPAQUE
65 | ? Bitmap.Config.ARGB_8888
66 | : Bitmap.Config.RGB_565);
67 | } else {
68 | bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
69 | drawable.getIntrinsicHeight(),
70 | drawable.getOpacity() != PixelFormat.OPAQUE
71 | ? Bitmap.Config.ARGB_8888
72 | : Bitmap.Config.RGB_565);
73 | }
74 | Canvas canvas = new Canvas(bitmap);
75 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
76 | drawable.draw(canvas);
77 | return bitmap;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/util/ImageUtil.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.util;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 | import android.os.Build;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.view.ViewTreeObserver;
9 | import android.widget.ImageView;
10 |
11 | import org.zzy.lib.largeimage.LargeImage;
12 | import org.zzy.lib.largeimage.R;
13 |
14 | import java.io.ByteArrayInputStream;
15 | import java.io.ByteArrayOutputStream;
16 | import java.io.File;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 | import java.io.InputStream;
20 |
21 | import okhttp3.Call;
22 | import okhttp3.Callback;
23 | import okhttp3.OkHttpClient;
24 | import okhttp3.Request;
25 | import okhttp3.Response;
26 |
27 | /**
28 | * ================================================
29 | * 作 者:ZhouZhengyi
30 | * 创建日期:2020/4/7 16:52
31 | * 描 述: 用来加载弹窗小图
32 | * 修订历史:1.为了防止二次hook,自定义该工具类加载图片
33 | * 2.目前已经不再使用,hook图片框架时能得到相应的bitmap对象
34 | * 可以直接使用ImageView加载。
35 | * ================================================
36 | */
37 | public class ImageUtil {
38 |
39 | /**
40 | * 从输入流中得到Bitmap
41 | * 作者: ZhouZhengyi
42 | * 创建时间: 2020/4/7 17:05
43 | */
44 | private static Bitmap decodeBitmapFromStream(String filePath, int targetWidth, int targetHeight) {
45 | Log.d(LargeImage.TAG, "decodeBitmapFromStream Thread id:" + Thread.currentThread().getId());
46 | BitmapFactory.Options options = new BitmapFactory.Options();
47 | //只获取Bitmap原始宽高,不分配内存
48 | options.inJustDecodeBounds = true;
49 | BitmapFactory.decodeFile(filePath, options);
50 | //计算inSampleSize值
51 | options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
52 | options.inJustDecodeBounds = false;
53 | return BitmapFactory.decodeFile(filePath, options);
54 | }
55 |
56 | /**
57 | * 只要bitmap的宽或者高 大于ImageView的宽高
58 | * 那么就计算inSampleSize的值
59 | * 作者: ZhouZhengyi
60 | * 创建时间: 2020/4/7 17:14
61 | */
62 | private static int calculateInSampleSize(BitmapFactory.Options options, int targetWidth, int targetHeight) {
63 | if (targetHeight == 0 || targetWidth == 0) {
64 | return 1;
65 | }
66 | Log.d(LargeImage.TAG, "calculateInSampleSize thread id:" + Thread.currentThread().getId());
67 | int height = options.outHeight;
68 | int width = options.outWidth;
69 | int inSampleSize = 1;
70 | if (width > targetWidth || height > targetHeight) {
71 | int halfHeight = height / 2;
72 | int halfWidth = width / 2;
73 | while ((halfHeight / inSampleSize) >= targetHeight &&
74 | (halfWidth / inSampleSize) >= targetWidth) {
75 | Log.d(LargeImage.TAG, "calculateInSampleSize thread id:" + Thread.currentThread().getId() + " inSampleSize:" + inSampleSize + " H");
76 | inSampleSize *= 2;
77 | }
78 |
79 | }
80 | return inSampleSize;
81 | }
82 |
83 | /**
84 | * 如果使用四大图片框架,则会有循环引用的问题,所以只能利用OkHttp自己实现图片下载
85 | * 作者: ZhouZhengyi
86 | * 创建时间: 2020/4/7 17:17
87 | */
88 | public static void downloadImage(final String url, final ImageView targetView) {
89 | OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
90 | final Request request = new Request.Builder().url(url).build();
91 | okHttpClient.newCall(request).enqueue(new Callback() {
92 | @Override
93 | public void onFailure(Call call, IOException e) {
94 | targetView.setImageResource(R.drawable.ic_failed);
95 | }
96 |
97 | @Override
98 | public void onResponse(Call call, Response response) throws IOException {
99 | String root = LargeImage.APPLICATION.getFilesDir().getAbsolutePath() + "/largeimage";
100 | InputStream is = null;
101 | FileOutputStream fileOutputStream = null;
102 | File dir = new File(root);
103 | if(!dir.exists()){
104 | dir.mkdirs();
105 | }
106 | String imageUrl = url;
107 | int index = imageUrl.lastIndexOf("/");
108 | String fileName = imageUrl.substring(index,imageUrl.length());
109 | File file = new File(dir,fileName);
110 | try {
111 | Log.d(LargeImage.TAG, "onResponse thread id:" + Thread.currentThread().getId());
112 | is = response.body().byteStream();
113 | fileOutputStream = new FileOutputStream(file);
114 | byte [] bytes = new byte[2048];
115 | int len = -1;
116 | while((len=is.read(bytes)) != -1){
117 | fileOutputStream.write(bytes,0,len);
118 | }
119 | fileOutputStream.flush();
120 | final Bitmap bitmap = decodeBitmapFromStream(file.getAbsolutePath(), targetView.getWidth(), targetView.getHeight());
121 | targetView.post(new Runnable() {
122 | @Override
123 | public void run() {
124 | Log.d(LargeImage.TAG, "onResponse thread id:" + Thread.currentThread().getId());
125 | targetView.setImageBitmap(bitmap);
126 | }
127 | });
128 | } catch (Exception e) {
129 | e.printStackTrace();
130 | } finally {
131 | if (is != null) {
132 | is.close();
133 | }
134 | if(fileOutputStream != null){
135 | fileOutputStream.close();
136 | }
137 | }
138 | }
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/util/Reflector.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.util;
2 |
3 |
4 | import androidx.annotation.NonNull;
5 | import androidx.annotation.Nullable;
6 |
7 | import java.lang.reflect.Constructor;
8 | import java.lang.reflect.Field;
9 | import java.lang.reflect.InvocationTargetException;
10 | import java.lang.reflect.Member;
11 | import java.lang.reflect.Method;
12 | import java.lang.reflect.Modifier;
13 |
14 | /**
15 | *
16 | * 使用方法:
17 | * 1.反射类中某个方法并调用:
18 | * Reflector.on(factoryClass).method("create", Context.class).call(context);
19 | * 2.反射类中某个字段并取得值
20 | * Reflector.on(ActivityManagerNative.class).field("gDefault").get();
21 | * 3.反射对象中某个字段并设置值
22 | * Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
23 | * 4.反射某个类并创建对象
24 | * Reflector.on("android.databinding.DataBinderMapperProxy").constructor().newInstance();
25 | * 5.反射某个方法,并且为方法绑定调用对象
26 | * Reflector.on(AssetManager.class).method("addAssetPath", String.class);
27 | * assetManager = AssetManager.class.newInstance();
28 | * reflector.bind(assetManager);
29 | * reflector.call(apk);
30 | *
31 | */
32 | public class Reflector {
33 |
34 | public static final String LOG_TAG ="Reflector";
35 |
36 | protected Class> mType;
37 | protected Object mCaller;
38 | protected Constructor mConstructor;
39 | protected Field mField;
40 | protected Method mMethod;
41 |
42 | public static class ReflectedException extends Exception {
43 |
44 | public ReflectedException(String message) {
45 | super(message);
46 | }
47 | public ReflectedException(String message, Throwable cause) {
48 | super(message, cause);
49 | }
50 |
51 | }
52 | public static Reflector on(@NonNull String name) throws ReflectedException {
53 | return on(name, true, Reflector.class.getClassLoader());
54 | }
55 |
56 | public static Reflector on(@NonNull String name, boolean initialize) throws ReflectedException {
57 | return on(name, initialize, Reflector.class.getClassLoader());
58 | }
59 |
60 | public static Reflector on(@NonNull String name, boolean initialize, @Nullable ClassLoader loader) throws ReflectedException {
61 | try {
62 | return on(Class.forName(name, initialize, loader));
63 | } catch (Throwable e) {
64 | throw new ReflectedException("Oops!", e);
65 | }
66 | }
67 |
68 | public static Reflector on(@NonNull Class> type) {
69 | Reflector reflector = new Reflector();
70 | reflector.mType = type;
71 | return reflector;
72 | }
73 |
74 | public static Reflector with(@NonNull Object caller) throws ReflectedException {
75 | return on(caller.getClass()).bind(caller);
76 | }
77 |
78 | protected Reflector() {
79 |
80 | }
81 |
82 | public Reflector constructor(@Nullable Class>... parameterTypes) throws ReflectedException {
83 | try {
84 | mConstructor = mType.getDeclaredConstructor(parameterTypes);
85 | mConstructor.setAccessible(true);
86 | mField = null;
87 | mMethod = null;
88 | return this;
89 | } catch (Throwable e) {
90 | throw new ReflectedException("Oops!", e);
91 | }
92 | }
93 |
94 | @SuppressWarnings("unchecked")
95 | public R newInstance(@Nullable Object... initargs) throws ReflectedException {
96 | if (mConstructor == null) {
97 | throw new ReflectedException("Constructor was null!");
98 | }
99 | try {
100 | return (R) mConstructor.newInstance(initargs);
101 | } catch (InvocationTargetException e) {
102 | throw new ReflectedException("Oops!", e.getTargetException());
103 | } catch (Throwable e) {
104 | throw new ReflectedException("Oops!", e);
105 | }
106 | }
107 |
108 | protected Object checked(@Nullable Object caller) throws ReflectedException {
109 | if (caller == null || mType.isInstance(caller)) {
110 | return caller;
111 | }
112 | throw new ReflectedException("Caller [" + caller + "] is not a instance of type [" + mType + "]!");
113 | }
114 |
115 | protected void check(@Nullable Object caller, @Nullable Member member, @NonNull String name) throws ReflectedException {
116 | if (member == null) {
117 | throw new ReflectedException(name + " was null!");
118 | }
119 | if (caller == null && !Modifier.isStatic(member.getModifiers())) {
120 | throw new ReflectedException("Need a caller!");
121 | }
122 | checked(caller);
123 | }
124 |
125 | public Reflector bind(@Nullable Object caller) throws ReflectedException {
126 | mCaller = checked(caller);
127 | return this;
128 | }
129 |
130 | public Reflector unbind() {
131 | mCaller = null;
132 | return this;
133 | }
134 |
135 | public Reflector field(@NonNull String name) throws ReflectedException {
136 | try {
137 | mField = findField(name);
138 | mField.setAccessible(true);
139 | mConstructor = null;
140 | mMethod = null;
141 | return this;
142 | } catch (Throwable e) {
143 | throw new ReflectedException("Oops!", e);
144 | }
145 | }
146 |
147 | protected Field findField(@NonNull String name) throws NoSuchFieldException {
148 | try {
149 | return mType.getField(name);
150 | } catch (NoSuchFieldException e) {
151 | for (Class> cls = mType; cls != null; cls = cls.getSuperclass()) {
152 | try {
153 | return cls.getDeclaredField(name);
154 | } catch (NoSuchFieldException ex) {
155 | // Ignored
156 | }
157 | }
158 | throw e;
159 | }
160 | }
161 |
162 | @SuppressWarnings("unchecked")
163 | public R get() throws ReflectedException {
164 | return get(mCaller);
165 | }
166 |
167 | @SuppressWarnings("unchecked")
168 | public R get(@Nullable Object caller) throws ReflectedException {
169 | check(caller, mField, "Field");
170 | try {
171 | return (R) mField.get(caller);
172 | } catch (Throwable e) {
173 | throw new ReflectedException("Oops!", e);
174 | }
175 | }
176 |
177 | public Reflector set(@Nullable Object value) throws ReflectedException {
178 | return set(mCaller, value);
179 | }
180 |
181 | public Reflector set(@Nullable Object caller, @Nullable Object value) throws ReflectedException {
182 | check(caller, mField, "Field");
183 | try {
184 | mField.set(caller, value);
185 | return this;
186 | } catch (Throwable e) {
187 | throw new ReflectedException("Oops!", e);
188 | }
189 | }
190 |
191 | public Reflector method(@NonNull String name, @Nullable Class>... parameterTypes) throws ReflectedException {
192 | try {
193 | mMethod = findMethod(name, parameterTypes);
194 | mMethod.setAccessible(true);
195 | mConstructor = null;
196 | mField = null;
197 | return this;
198 | } catch (NoSuchMethodException e) {
199 | throw new ReflectedException("Oops!", e);
200 | }
201 | }
202 |
203 | protected Method findMethod(@NonNull String name, @Nullable Class>... parameterTypes) throws NoSuchMethodException {
204 | try {
205 | return mType.getMethod(name, parameterTypes);
206 | } catch (NoSuchMethodException e) {
207 | for (Class> cls = mType; cls != null; cls = cls.getSuperclass()) {
208 | try {
209 | return cls.getDeclaredMethod(name, parameterTypes);
210 | } catch (NoSuchMethodException ex) {
211 | // Ignored
212 | }
213 | }
214 | throw e;
215 | }
216 | }
217 |
218 | public R call(@Nullable Object... args) throws ReflectedException {
219 | return callByCaller(mCaller, args);
220 | }
221 |
222 | @SuppressWarnings("unchecked")
223 | public R callByCaller(@Nullable Object caller, @Nullable Object... args) throws ReflectedException {
224 | check(caller, mMethod, "Method");
225 | try {
226 | return (R) mMethod.invoke(caller, args);
227 | } catch (InvocationTargetException e) {
228 | throw new ReflectedException("Oops!", e.getTargetException());
229 | } catch (Throwable e) {
230 | throw new ReflectedException("Oops!", e);
231 | }
232 | }
233 |
234 | public static class QuietReflector extends Reflector {
235 |
236 | protected Throwable mIgnored;
237 |
238 | public static QuietReflector on(@NonNull String name) {
239 | return on(name, true, QuietReflector.class.getClassLoader());
240 | }
241 |
242 | public static QuietReflector on(@NonNull String name, boolean initialize) {
243 | return on(name, initialize, QuietReflector.class.getClassLoader());
244 | }
245 |
246 | public static QuietReflector on(@NonNull String name, boolean initialize, @Nullable ClassLoader loader) {
247 | Class> cls = null;
248 | try {
249 | cls = Class.forName(name, initialize, loader);
250 | return on(cls, null);
251 | } catch (Throwable e) {
252 | // Log.w(LOG_TAG, "Oops!", e);
253 | return on(cls, e);
254 | }
255 | }
256 |
257 | public static QuietReflector on(@Nullable Class> type) {
258 | return on(type, (type == null) ? new ReflectedException("Type was null!") : null);
259 | }
260 |
261 | private static QuietReflector on(@Nullable Class> type, @Nullable Throwable ignored) {
262 | QuietReflector reflector = new QuietReflector();
263 | reflector.mType = type;
264 | reflector.mIgnored = ignored;
265 | return reflector;
266 | }
267 |
268 | public static QuietReflector with(@Nullable Object caller) {
269 | if (caller == null) {
270 | return on((Class>) null);
271 | }
272 | return on(caller.getClass()).bind(caller);
273 | }
274 |
275 | protected QuietReflector() {
276 |
277 | }
278 |
279 | public Throwable getIgnored() {
280 | return mIgnored;
281 | }
282 |
283 | protected boolean skip() {
284 | return skipAlways() || mIgnored != null;
285 | }
286 |
287 | protected boolean skipAlways() {
288 | return mType == null;
289 | }
290 |
291 | @Override
292 | public QuietReflector constructor(@Nullable Class>... parameterTypes) {
293 | if (skipAlways()) {
294 | return this;
295 | }
296 | try {
297 | mIgnored = null;
298 | super.constructor(parameterTypes);
299 | } catch (Throwable e) {
300 | mIgnored = e;
301 | // Log.w(LOG_TAG, "Oops!", e);
302 | }
303 | return this;
304 | }
305 |
306 | @Override
307 | public R newInstance(@Nullable Object... initargs) {
308 | if (skip()) {
309 | return null;
310 | }
311 | try {
312 | mIgnored = null;
313 | return super.newInstance(initargs);
314 | } catch (Throwable e) {
315 | mIgnored = e;
316 | // Log.w(LOG_TAG, "Oops!", e);
317 | }
318 | return null;
319 | }
320 |
321 | @Override
322 | public QuietReflector bind(@Nullable Object obj) {
323 | if (skipAlways()) {
324 | return this;
325 | }
326 | try {
327 | mIgnored = null;
328 | super.bind(obj);
329 | } catch (Throwable e) {
330 | mIgnored = e;
331 | // Log.w(LOG_TAG, "Oops!", e);
332 | }
333 | return this;
334 | }
335 |
336 | @Override
337 | public QuietReflector unbind() {
338 | super.unbind();
339 | return this;
340 | }
341 |
342 | @Override
343 | public QuietReflector field(@NonNull String name) {
344 | if (skipAlways()) {
345 | return this;
346 | }
347 | try {
348 | mIgnored = null;
349 | super.field(name);
350 | } catch (Throwable e) {
351 | mIgnored = e;
352 | // Log.w(LOG_TAG, "Oops!", e);
353 | }
354 | return this;
355 | }
356 |
357 | @Override
358 | public R get() {
359 | if (skip()) {
360 | return null;
361 | }
362 | try {
363 | mIgnored = null;
364 | return super.get();
365 | } catch (Throwable e) {
366 | mIgnored = e;
367 | // Log.w(LOG_TAG, "Oops!", e);
368 | }
369 | return null;
370 | }
371 |
372 | @Override
373 | public R get(@Nullable Object caller) {
374 | if (skip()) {
375 | return null;
376 | }
377 | try {
378 | mIgnored = null;
379 | return super.get(caller);
380 | } catch (Throwable e) {
381 | mIgnored = e;
382 | // Log.w(LOG_TAG, "Oops!", e);
383 | }
384 | return null;
385 | }
386 |
387 | @Override
388 | public QuietReflector set(@Nullable Object value) {
389 | if (skip()) {
390 | return this;
391 | }
392 | try {
393 | mIgnored = null;
394 | super.set(value);
395 | } catch (Throwable e) {
396 | mIgnored = e;
397 | // Log.w(LOG_TAG, "Oops!", e);
398 | }
399 | return this;
400 | }
401 |
402 | @Override
403 | public QuietReflector set(@Nullable Object caller, @Nullable Object value) {
404 | if (skip()) {
405 | return this;
406 | }
407 | try {
408 | mIgnored = null;
409 | super.set(caller, value);
410 | } catch (Throwable e) {
411 | mIgnored = e;
412 | // Log.w(LOG_TAG, "Oops!", e);
413 | }
414 | return this;
415 | }
416 |
417 | @Override
418 | public QuietReflector method(@NonNull String name, @Nullable Class>... parameterTypes) {
419 | if (skipAlways()) {
420 | return this;
421 | }
422 | try {
423 | mIgnored = null;
424 | super.method(name, parameterTypes);
425 | } catch (Throwable e) {
426 | mIgnored = e;
427 | // Log.w(LOG_TAG, "Oops!", e);
428 | }
429 | return this;
430 | }
431 |
432 | @Override
433 | public R call(@Nullable Object... args) {
434 | if (skip()) {
435 | return null;
436 | }
437 | try {
438 | mIgnored = null;
439 | return super.call(args);
440 | } catch (Throwable e) {
441 | mIgnored = e;
442 | // Log.w(LOG_TAG, "Oops!", e);
443 | }
444 | return null;
445 | }
446 |
447 | @Override
448 | public R callByCaller(@Nullable Object caller, @Nullable Object... args) {
449 | if (skip()) {
450 | return null;
451 | }
452 | try {
453 | mIgnored = null;
454 | return super.callByCaller(caller, args);
455 | } catch (Throwable e) {
456 | mIgnored = e;
457 | // Log.w(LOG_TAG, "Oops!", e);
458 | }
459 | return null;
460 | }
461 | }
462 | }
463 |
--------------------------------------------------------------------------------
/largeimage/src/main/java/org/zzy/lib/largeimage/util/ResHelper.java:
--------------------------------------------------------------------------------
1 | package org.zzy.lib.largeimage.util;
2 |
3 | import android.content.Context;
4 | import android.content.res.ColorStateList;
5 | import android.content.res.Resources;
6 | import android.graphics.drawable.Drawable;
7 |
8 | import android.text.Html;
9 | import android.text.TextUtils;
10 |
11 |
12 | import androidx.annotation.ArrayRes;
13 | import androidx.annotation.ColorRes;
14 | import androidx.annotation.DimenRes;
15 | import androidx.annotation.DrawableRes;
16 | import androidx.annotation.RawRes;
17 | import androidx.annotation.StringRes;
18 |
19 | import org.zzy.lib.largeimage.LargeImage;
20 | import org.zzy.lib.largeimage.R;
21 |
22 | import java.io.BufferedOutputStream;
23 | import java.io.ByteArrayOutputStream;
24 | import java.io.File;
25 | import java.io.FileOutputStream;
26 | import java.io.IOException;
27 | import java.io.InputStream;
28 | import java.io.OutputStream;
29 |
30 |
31 | /**
32 | * @author : Zhouzhengyi
33 | */
34 |
35 | public class ResHelper {
36 | /**
37 | * 缓存区大小
38 | */
39 | private static final int BUFFER_SIZE = 8192;
40 |
41 | /**
42 | * 获取全局的Context
43 | *
44 | * @return Context
45 | */
46 | public static Context context() {
47 | return LargeImage.APPLICATION.getApplicationContext();
48 | }
49 |
50 | /**
51 | * 获取字符串资源
52 | *
53 | * @param resId 字符串资源ID
54 | * @return 字符串
55 | */
56 | public static String getString(@StringRes int resId) {
57 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
58 | if (null == resources || 0 == resId) {
59 | return "";
60 | }
61 | return resources.getString(resId);
62 | }
63 |
64 | /**
65 | * 获取字符串资源
66 | *
67 | * @param resId 字符串资源ID
68 | * @param formatArgs 格式化
69 | * @return 字符串
70 | */
71 | public static String getString(@StringRes int resId, Object... formatArgs) {
72 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
73 | if (null == resources || 0 == resId || null == formatArgs) {
74 | return "";
75 | }
76 | return resources.getString(resId, formatArgs);
77 | }
78 |
79 | /**
80 | * 获取颜色资源
81 | *
82 | * @param resId 字颜色资源ID
83 | * @return 颜色值
84 | */
85 | public static int getColor(@ColorRes int resId) {
86 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
87 | if (null == resources || 0 == resId) {
88 | resId = R.color.c999999;
89 | }
90 | return resources.getColor(resId);
91 | }
92 |
93 | /**
94 | * 获取颜色状态集合
95 | *
96 | * @param resId 颜色集合资源ID
97 | * @return 颜色集合
98 | */
99 | public static ColorStateList getColorStateList(@ColorRes int resId) {
100 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
101 | if (null == resources || 0 == resId) {
102 | resId = R.color.c999999;
103 | }
104 | return resources.getColorStateList(resId);
105 | }
106 |
107 | /**
108 | * 获取Dimension
109 | *
110 | * @param resId Dimen资源ID
111 | * @return Dimen
112 | */
113 | public static int getDimensionPixelOffset(@DimenRes int resId) {
114 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
115 | if (null == resources || 0 == resId) {
116 | return 0;
117 | }
118 | return resources.getDimensionPixelOffset(resId);
119 | }
120 |
121 | /**
122 | * 获取drawable资源
123 | *
124 | * @param resId drawable资源ID
125 | * @return Drawable
126 | */
127 | public static Drawable getDrawable(@DrawableRes int resId) {
128 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
129 | if (null == resources || 0 == resId) {
130 | return null;
131 | }
132 | return resources.getDrawable(resId);
133 | }
134 |
135 | /**
136 | * 获取字符串数组资源
137 | *
138 | * @param resId 字符串数组资源ID
139 | * @return 字符串数组
140 | */
141 | public static String[] getStringArray(@ArrayRes int resId) {
142 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
143 | if (null == resources || 0 == resId) {
144 | return new String[]{};
145 | }
146 | return resources.getStringArray(resId);
147 | }
148 |
149 |
150 | /**
151 | * 从assets 中读取字符串
152 | *
153 | * @param assetsFilePath assets 文件路径
154 | * @return 内容
155 | */
156 | public static String readAssetsString(final String assetsFilePath) {
157 | InputStream is;
158 | try {
159 | is = context().getAssets().open(assetsFilePath);
160 | } catch (IOException e) {
161 | e.printStackTrace();
162 | return null;
163 | }
164 | byte[] bytes = is2Bytes(is);
165 | if (bytes == null) { return null; }
166 | return new String(bytes);
167 | }
168 |
169 |
170 | /**
171 | * 拷贝 raw 下的文件
172 | *
173 | * @param resId 资源ID
174 | * @param destFilePath 目标文件路径
175 | * @return {@code true}: 成功 {@code false}: 失败
176 | */
177 | public static boolean copyFileFromRaw(@RawRes final int resId, final String destFilePath) {
178 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
179 | return writeFileFromIS(destFilePath, resources.openRawResource(resId), false
180 | );
181 | }
182 |
183 | /**
184 | * 读取 raw 中的字符串
185 | *
186 | * @param resId 资源ID
187 | * @return 字符串内容
188 | */
189 | public static String readRawString(@RawRes final int resId) {
190 | Resources resources = LargeImage.APPLICATION.getApplicationContext().getResources();
191 | InputStream is = resources.openRawResource(resId);
192 | byte[] bytes = is2Bytes(is);
193 | if (bytes == null) { return null; }
194 | return new String(bytes);
195 | }
196 |
197 | /**
198 | * 从 InputStream 写入文件
199 | *
200 | * @param filePath 文件路径
201 | * @param is InputStream 输入流
202 | * @param append 是否追加写入
203 | * @return 写文件结果
204 | */
205 | private static boolean writeFileFromIS(final String filePath, InputStream is, boolean append) {
206 | return writeFileFromIS(getFileByPath(filePath), is, append);
207 | }
208 |
209 | /**
210 | * 从 InputStream 写入文件
211 | *
212 | * @param file 文件
213 | * @param is InputStream 输入流
214 | * @param append 是否追加写入
215 | * @return 写文件结果
216 | */
217 | private static boolean writeFileFromIS(final File file, final InputStream is, final boolean append) {
218 | if (!createOrExistsFile(file) || is == null) { return false; }
219 | OutputStream os = null;
220 | try {
221 | os = new BufferedOutputStream(new FileOutputStream(file, append));
222 | byte[] data = new byte[BUFFER_SIZE];
223 | int len;
224 | while ((len = is.read(data, 0, BUFFER_SIZE)) != -1) {
225 | os.write(data, 0, len);
226 | }
227 | return true;
228 | } catch (IOException e) {
229 | e.printStackTrace();
230 | return false;
231 | } finally {
232 | try {
233 | is.close();
234 | } catch (IOException e) {
235 | e.printStackTrace();
236 | }
237 | try {
238 | if (os != null) {
239 | os.close();
240 | }
241 | } catch (IOException e) {
242 | e.printStackTrace();
243 | }
244 | }
245 | }
246 |
247 | /**
248 | * 创建或者已存在的文件
249 | *
250 | * @param file 文件
251 | * @return true 创建成功或者是文件已存在
252 | */
253 | private static boolean createOrExistsFile(File file) {
254 | if (file == null) { return false; }
255 | if (file.exists()) { return file.isFile(); }
256 | if (!createOrExistsDir(file.getParentFile())) { return false; }
257 | try {
258 | return file.createNewFile();
259 | } catch (IOException e) {
260 | e.printStackTrace();
261 | return false;
262 | }
263 | }
264 |
265 | /**
266 | * 创建或者已存在的文件目录
267 | *
268 | * @param file 文件
269 | * @return true 创建成功或者是文件已存在
270 | */
271 | private static boolean createOrExistsDir(File file) {
272 | return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
273 | }
274 |
275 | /**
276 | * 通过路径获取文件
277 | *
278 | * @param filePath 文件路径
279 | * @return 文件
280 | */
281 | private static File getFileByPath(String filePath) {
282 | return isSpace(filePath) ? null : new File(filePath);
283 | }
284 |
285 | /**
286 | * 是否是空
287 | *
288 | * @param s 字符串
289 | * @return true 空,false 非空
290 | */
291 | private static boolean isSpace(String s) {
292 | if (s == null) { return true; }
293 | for (int i = 0, len = s.length(); i < len; ++i) {
294 | if (!Character.isWhitespace(s.charAt(i))) {
295 | return false;
296 | }
297 | }
298 | return true;
299 | }
300 |
301 | /**
302 | * 是否是字节数组
303 | *
304 | * @param is InputStream 输入流
305 | * @return 字节数组
306 | */
307 | private static byte[] is2Bytes(final InputStream is) {
308 | if (is == null) { return null; }
309 | ByteArrayOutputStream os = null;
310 | try {
311 | os = new ByteArrayOutputStream();
312 | byte[] b = new byte[BUFFER_SIZE];
313 | int len;
314 | while ((len = is.read(b, 0, BUFFER_SIZE)) != -1) {
315 | os.write(b, 0, len);
316 | }
317 | return os.toByteArray();
318 | } catch (IOException e) {
319 | e.printStackTrace();
320 | return null;
321 | } finally {
322 | try {
323 | is.close();
324 | } catch (IOException e) {
325 | e.printStackTrace();
326 | }
327 | try {
328 | if (os != null) {
329 | os.close();
330 | }
331 | } catch (IOException e) {
332 | e.printStackTrace();
333 | }
334 | }
335 | }
336 |
337 |
338 | /**
339 | * @param content 内容
340 | * @param mode 模式
341 | * Html.FROM_HTML_MODE_COMPACT:html块元素之间使用一个换行符分隔
342 | * Html.FROM_HTML_MODE_LEGACY:html块元素之间使用两个换行符分隔
343 | */
344 | public static CharSequence fromHtml(String content, int mode){
345 | if(TextUtils.isEmpty(content)){
346 | return "";
347 | }
348 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
349 | return Html.fromHtml(content,mode);
350 | } else {
351 | return Html.fromHtml(content);
352 | }
353 | }
354 | }
355 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable-xxhdpi/checkbox_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/drawable-xxhdpi/checkbox_checked.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable-xxhdpi/checkbox_unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/drawable-xxhdpi/checkbox_unchecked.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable-xxhdpi/ic_default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/drawable-xxhdpi/ic_default.jpg
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable-xxhdpi/ic_failed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/drawable-xxhdpi/ic_failed.jpg
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/ic_alarm.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/ic_arrow_back_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/ic_more_vert_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/ic_satellite.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
42 |
45 |
48 |
51 |
52 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/drawable/switch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/layout/activity_largeimage_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
21 |
22 |
26 |
27 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/layout/activity_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
16 |
21 |
28 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/layout/dialog_custom.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
16 |
17 |
18 |
26 |
27 |
34 |
35 |
43 |
44 |
45 |
54 |
55 |
62 |
63 |
71 |
72 |
73 |
74 |
83 |
92 |
103 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/menu/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/largeimage/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/largeimage/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF999999
4 |
5 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 内存大小:%sMB
3 | 文件大小:%sKB
4 | 图片尺寸:%s
5 | View尺寸:%s
6 | 图片地址:%s
7 |
8 |
--------------------------------------------------------------------------------
/largeimage/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
18 |
--------------------------------------------------------------------------------
/largeimage/upload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.novoda.bintray-release'
2 |
3 | publish {
4 |
5 | def groupProjectID = 'org.zzy.lib.largeimage'
6 | def artifactProjectID = 'large-image-monitor'
7 | def publishVersionID = "${rootProject.ext.android["jcenterArchivesVersionName"]}"
8 |
9 | userOrg = 'zzy'
10 | repoName = "imageMonitor"
11 | groupId = groupProjectID
12 | artifactId = artifactProjectID
13 | publishVersion = publishVersionID
14 | desc = 'Oh hi, this is a library which can be monitor large image.'
15 | website = 'https://github.com/121880399/LargeImageMonitor'
16 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='ImageMonitor'
2 | include ':app'
3 | include ':largeimage'
4 | include ':largeimage-plugin'
5 |
--------------------------------------------------------------------------------
/wiki/alipay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/alipay.jpg
--------------------------------------------------------------------------------
/wiki/example1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/example1.jpg
--------------------------------------------------------------------------------
/wiki/example2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/example2.jpg
--------------------------------------------------------------------------------
/wiki/example3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/example3.jpg
--------------------------------------------------------------------------------
/wiki/example4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/example4.jpg
--------------------------------------------------------------------------------
/wiki/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/logo.png
--------------------------------------------------------------------------------
/wiki/wxpay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/121880399/LargeImageMonitor/8db54dfff671c213d39ae06956d8cc4bed10f31e/wiki/wxpay.jpg
--------------------------------------------------------------------------------