├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── coolweather
│ │ └── android
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── litepal.xml
│ ├── java
│ │ └── com
│ │ │ └── coolweather
│ │ │ └── android
│ │ │ ├── db
│ │ │ ├── City.java
│ │ │ ├── County.java
│ │ │ └── Province.java
│ │ │ ├── gson
│ │ │ ├── AQI.java
│ │ │ ├── Basic.java
│ │ │ ├── DailyForecast.java
│ │ │ ├── Now.java
│ │ │ ├── Suggestion.java
│ │ │ └── Weather.java
│ │ │ ├── service
│ │ │ └── AutoUpdateWeatherService.java
│ │ │ ├── ui
│ │ │ ├── MainActivity.java
│ │ │ ├── WeatherActivity.java
│ │ │ ├── fragment
│ │ │ │ └── ChooseAreaFragment.java
│ │ │ └── widget
│ │ │ │ └── TimeoutProgressBar.java
│ │ │ └── util
│ │ │ ├── BitmapHelper.java
│ │ │ ├── HttpUtil.java
│ │ │ ├── Utility.java
│ │ │ └── listener
│ │ │ └── TimeOutListener.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xxhdpi
│ │ ├── cloudy1.jpg
│ │ ├── cloudy2.jpg
│ │ ├── cloudy3.jpg
│ │ ├── ic_back.png
│ │ ├── ic_forward.png
│ │ ├── location.png
│ │ ├── overcast1.jpg
│ │ ├── panda.png
│ │ ├── rain1.jpg
│ │ ├── rain2.jpg
│ │ ├── settings.png
│ │ ├── snow1.jpg
│ │ ├── snow2.jpg
│ │ ├── sunny1.jpg
│ │ ├── sunny2.jpg
│ │ ├── thunder1.jpg
│ │ ├── thunder2.jpg
│ │ └── timeout_progress_bg.png
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_weather.xml
│ │ ├── aqi.xml
│ │ ├── choose_area.xml
│ │ ├── forcast.xml
│ │ ├── forecast_item.xml
│ │ ├── nav_header.xml
│ │ ├── now.xml
│ │ ├── suggestion.xml
│ │ ├── timeout_progress_bar.xml
│ │ └── weather_title.xml
│ │ ├── menu
│ │ └── nav_menu.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
│ │ └── ic_weather.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── coolweather
│ └── android
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.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 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.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 | # coolweather
2 | 我的第一个完整的安卓项目:酷欧天气
3 |
4 | ## 项目需求分析
5 | 1. 可以罗列全国所有的省、市、县 -- (已实现)
6 | 2. 可以查看全国任意城市的天气信息 -- (已实现)
7 | 3. 可以自由切换城市,去查看其他城市的天气信息 -- (已实现)
8 | 4. 可以手动更新以及后台自动更新天气信息 -- (已实现)
9 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.coolweather.android"
7 | minSdkVersion 22
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | targetCompatibility 1.8
21 | sourceCompatibility 1.8
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | // 此库添加了对操作栏用户界面设计模式的支持。此库包含对 Material Design 用户界面实现的支持
28 | implementation 'com.android.support:appcompat-v7:26.1.0'
29 |
30 | implementation 'com.squareup.okhttp3:okhttp:3.11.0' // 网络请求库
31 | implementation 'org.litepal.android:core:2.0.0' // SQLite数据库框架
32 | implementation 'com.google.code.gson:gson:2.8.5' // 解析JSON格式数据的库
33 | implementation 'com.github.bumptech.glide:glide:3.7.0' // 优秀的第三方图片加载库
34 |
35 | implementation 'com.android.support:design:26.1.0' // 添加 Material Design library
36 | implementation 'de.hdodenhof:circleimageview:2.1.0' // 添加 显示圆形图片【第三方开源库】
37 | implementation 'com.android.support:palette-v7:26.1.0' // Android官方提供的提取图片颜色的调色板库
38 |
39 | // 添加 ButterKnife 第三方库
40 | implementation 'com.jakewharton:butterknife:8.8.1'
41 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
42 |
43 | testImplementation 'junit:junit:4.12'
44 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
45 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
46 | }
47 |
--------------------------------------------------------------------------------
/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/androidTest/java/com/coolweather/android/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.coolweather.android", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/assets/litepal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/db/City.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.db;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | /**
6 | * 市表的model,市的实体类
7 | */
8 | public class City extends LitePalSupport{
9 | private int id;
10 |
11 | private String cityName;
12 |
13 | private int cityCode;
14 |
15 | private int provinceCode;
16 |
17 | public int getId() {
18 | return id;
19 | }
20 |
21 | public void setId(int id) {
22 | this.id = id;
23 | }
24 |
25 | public String getCityName() {
26 | return cityName;
27 | }
28 |
29 | public void setCityName(String cityName) {
30 | this.cityName = cityName;
31 | }
32 |
33 | public int getCityCode() {
34 | return cityCode;
35 | }
36 |
37 | public void setCityCode(int cityCode) {
38 | this.cityCode = cityCode;
39 | }
40 |
41 | public int getProvinceCode() {
42 | return provinceCode;
43 | }
44 |
45 | public void setProvinceCode(int provinceCode) {
46 | this.provinceCode = provinceCode;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/db/County.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.db;
2 |
3 | import org.litepal.crud.LitePalSupport;
4 |
5 | public class County extends LitePalSupport {
6 | private int id;
7 |
8 | private String countyName;
9 |
10 | private int countyCode;
11 |
12 | private int cityCode;
13 |
14 | /** 天气代码:用于查询天气信息 */
15 | private String weatherId;
16 |
17 | public int getId() {
18 | return id;
19 | }
20 |
21 | public void setId(int id) {
22 | this.id = id;
23 | }
24 |
25 | public String getCountyName() {
26 | return countyName;
27 | }
28 |
29 | public void setCountyName(String countyName) {
30 | this.countyName = countyName;
31 | }
32 |
33 | public int getCountyCode() {
34 | return countyCode;
35 | }
36 |
37 | public void setCountyCode(int countyCode) {
38 | this.countyCode = countyCode;
39 | }
40 |
41 | public int getCityCode() {
42 | return cityCode;
43 | }
44 |
45 | public void setCityCode(int cityCode) {
46 | this.cityCode = cityCode;
47 | }
48 |
49 | public String getWeatherId() {
50 | return weatherId;
51 | }
52 |
53 | public void setWeatherId(String weatherId) {
54 | this.weatherId = weatherId;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/db/Province.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.db;
2 |
3 | import org.litepal.crud.DataSupport;
4 | import org.litepal.crud.LitePalSupport;
5 |
6 | /**
7 | * 省份表的model,省份实体类
8 | * @author Administrator
9 | */
10 | public class Province extends LitePalSupport{
11 | private int id;
12 |
13 | private String provinceName;
14 |
15 | private int provinceCode;
16 |
17 | public int getId() {
18 | return id;
19 | }
20 |
21 | public void setId(int id) {
22 | this.id = id;
23 | }
24 |
25 | public String getProvinceName() {
26 | return provinceName;
27 | }
28 |
29 | public void setProvinceName(String name) {
30 | this.provinceName = name;
31 | }
32 |
33 | public int getProvinceCode() {
34 | return provinceCode;
35 | }
36 |
37 | public void setProvinceCode(int code) {
38 | this.provinceCode = code;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/AQI.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * 空气质量指数
7 | */
8 | public class AQI {
9 | public City city;
10 |
11 | public class City {
12 | public String aqi;
13 |
14 | public String pm25;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/Basic.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * 城市基本信息
7 | */
8 | public class Basic {
9 | /** 城市名 */
10 | @SerializedName("city")
11 | public String cityName;
12 |
13 | /** 天气ID */
14 | @SerializedName("id")
15 | public String weatherId;
16 |
17 | public Update update;
18 |
19 | public class Update {
20 | /** 天气的更新时间(当地时间) */
21 | @SerializedName("loc")
22 | public String updateTime;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/DailyForecast.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | /**
5 | * 天气情况预测
6 | */
7 | public class DailyForecast {
8 | /** 日期 */
9 | public String date;
10 |
11 | /** 温度情况 */
12 | @SerializedName("tmp")
13 | public Temperature temperature;
14 |
15 | /** 天气情况 */
16 | @SerializedName("cond")
17 | public More more;
18 |
19 | public class More {
20 | /** 天气描述 */
21 | @SerializedName("txt_d")
22 | public String info;
23 | }
24 |
25 | public class Temperature {
26 | public String max;
27 | public String min;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/Now.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | /**
5 | * 当天的综合天气情况
6 | */
7 | public class Now {
8 | /** 温度 */
9 | @SerializedName("tmp")
10 | public String temperature;
11 |
12 | /** 天气情况 */
13 | @SerializedName("cond")
14 | public More more;
15 |
16 | public class More {
17 | /** 天气描述 */
18 | @SerializedName("txt")
19 | public String info;
20 |
21 | /** 天气代码 */
22 | public String code;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/Suggestion.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | /**
5 | * 依据天气情况,给出的日常生活建议
6 | */
7 | public class Suggestion {
8 | /** 天气舒适度描述 */
9 | @SerializedName("comf")
10 | public Comfort comfort;
11 |
12 | /** 洗车建议 */
13 | @SerializedName("cw")
14 | public CarWash carWash;
15 |
16 | /** 运动建议 */
17 | public Sport sport;
18 |
19 | public class Comfort {
20 | @SerializedName("txt")
21 | public String info;
22 | }
23 |
24 | public class CarWash {
25 | @SerializedName("txt")
26 | public String info;
27 | }
28 |
29 | public class Sport {
30 | @SerializedName("txt")
31 | public String info;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/gson/Weather.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.gson;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.List;
6 | import java.util.concurrent.BlockingDeque;
7 |
8 | /**
9 | * 天气情况实体类
10 | **/
11 | public class Weather {
12 | /**
13 | * 和风天气接口返回数据的状态码:
14 | * ok 数据正常
15 | * invalid key 错误的key,请检查你的key是否输入以及是否输入有误
16 | * unknown location 未知或错误城市/地区
17 | * no data for this location 该城市/地区没有你所请求的数据
18 | * no more requests 超过访问次数,需要等到当月最后一天24点(免费用户为当天24点)后进行访问次数的重置或升级你的访问量
19 | * param invalid 参数错误,请检查你传递的参数是否正确
20 | * too fast 超过限定的QPM,请参考QPM说明
21 | * dead 无响应或超时,接口服务异常请联系我们
22 | * permission denied 无访问权限,你没有购买你所访问的这部分服务
23 | * sign error 签名错误,请参考签名算法
24 | **/
25 | public String status;
26 |
27 | public Basic basic;
28 |
29 | public AQI aqi;
30 |
31 | public Now now;
32 |
33 | public Suggestion suggestion;
34 |
35 | /** 未来几天天气情况预测 */
36 | @SerializedName("daily_forecast")
37 | public List dailyForecastList;
38 |
39 | @Override
40 | public String toString() {
41 | StringBuilder builder = new StringBuilder();
42 | builder.append("heWeather:[{\n");
43 | builder.append("status:" +status+"\n");
44 | builder.append("basic:{\n cityName:"+basic.cityName+"\n weather_id:"+basic.weatherId+
45 | "\n updateTime:"+basic.update.updateTime+"\n}\n");
46 | builder.append("aqi:{\n"+" aqi:"+aqi.city.aqi+"\n pm2.5:"+aqi.city.pm25+"\n}\n");
47 | builder.append("now:{\n 温度:"+now.temperature+"℃"+"\n"
48 | +" 天气:"+ now.more.info + "\n"
49 | +" 天气代码:"+ now.more.code +"\n}\n");
50 |
51 | builder.append("daily_forecast:[\n");
52 | for (DailyForecast dailyForecast : dailyForecastList) {
53 | builder.append(" {\n");
54 | builder.append(" date:" + dailyForecast.date+"\n");
55 | builder.append(" 天气:" + dailyForecast.more.info + "\n");
56 | builder.append(" 最高温度:" + dailyForecast.temperature.max + "℃\n");
57 | builder.append(" 最低温度:" + dailyForecast.temperature.min + "℃\n");
58 | builder.append(" }\n");
59 | }
60 | builder.append("}\n");
61 |
62 | builder.append("suggestion:{\n");
63 | builder.append(" 舒适度:"+suggestion.comfort.info+"\n");
64 | builder.append(" 运动建议:"+suggestion.sport.info+"\n");
65 | builder.append(" 洗车建议:"+suggestion.carWash.info+"\n");
66 | builder.append("}\n");
67 |
68 | builder.append("}]");
69 |
70 | return builder.toString();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/service/AutoUpdateWeatherService.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.service;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.app.Service;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.os.IBinder;
10 | import android.os.SystemClock;
11 | import android.preference.PreferenceManager;
12 | import android.support.v4.app.AlarmManagerCompat;
13 | import android.util.Log;
14 |
15 | import com.coolweather.android.gson.Weather;
16 | import com.coolweather.android.util.HttpUtil;
17 | import com.coolweather.android.util.Utility;
18 |
19 | import java.io.IOException;
20 |
21 | import okhttp3.Call;
22 | import okhttp3.Callback;
23 | import okhttp3.Response;
24 |
25 | public class AutoUpdateWeatherService extends Service {
26 | private long lastTime;
27 | private long currentTime;
28 | @Override
29 | public void onCreate() {
30 | super.onCreate();
31 | lastTime = SystemClock.elapsedRealtime();
32 | }
33 |
34 | @Override
35 | public IBinder onBind(Intent intent) {
36 | return null;
37 | }
38 |
39 | @Override
40 | public int onStartCommand(Intent intent, int flags, int startId) {
41 | currentTime = SystemClock.elapsedRealtime();
42 | Log.d("onAutoUpdateService", "开始进行一次定时任务,时间间隔:"+((currentTime-lastTime)/1000.0)+"s");
43 | updateWeather();
44 | updateBingPic();
45 | setAlarmTask();
46 | return super.onStartCommand(intent, flags, startId);
47 | }
48 |
49 | /** 设置定时任务 */
50 | private void setAlarmTask() {
51 | AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
52 | // 定时任务触发事件间隔,暂设定时间间隔3小时
53 | int intervalTime = 3 * 3600 * 1000;
54 | long triggerAtTime = SystemClock.elapsedRealtime() + intervalTime;
55 | Intent intent = new Intent(this, AutoUpdateWeatherService.class);
56 | PendingIntent pi = PendingIntent.getService(this,0,intent,0);
57 | alarmManager.cancel(pi);
58 |
59 | lastTime = currentTime;
60 | // 设定定时任务
61 | alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);
62 | }
63 |
64 | private void updateBingPic() {
65 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
66 | String weatherId = sp.getString("bing_pic", null);
67 | if (weatherId != null) {
68 | String bingPicUrl = "http://guolin.tech/api/bing_pic";
69 | HttpUtil.sendOkHttpRequest(bingPicUrl, new Callback() {
70 | @Override
71 | public void onFailure(Call call, IOException e) {
72 | Log.e("onUpdateBingPic", "网络连接异常");
73 | e.printStackTrace();
74 | }
75 |
76 | @Override
77 | public void onResponse(Call call, Response response) throws IOException {
78 | String bingPicLink = response.body().string();
79 | // 缓存Bing每日一图片的下载链接
80 | sp.edit().putString("bing_pic",bingPicLink).apply();
81 | }
82 | });
83 | }
84 | }
85 |
86 | private void updateWeather() {
87 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
88 | String weatherId = sp.getString("weather_id", null);
89 | if (weatherId != null) {
90 | String weatherUrl = "http://guolin.tech/api/weather?cityid=" + weatherId
91 | + "&key=c72d9f8149ac436da648ac0e43211edd";
92 | HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {
93 | @Override
94 | public void onFailure(Call call, IOException e) {
95 | Log.w("onUpdateWeather", "网络连接异常");
96 | e.printStackTrace();
97 | }
98 |
99 | @Override
100 | public void onResponse(Call call, Response response) throws IOException {
101 | String weatherInfo = response.body().string();
102 | Weather weather = Utility.handleWeatherResponse(weatherInfo);
103 | if (weather != null & "ok".equals(weather.status)) {
104 | // 缓存天气信息
105 | sp.edit().putString("heWeather", weatherInfo).apply();
106 | }
107 | }
108 | });
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.ui;
2 |
3 | import android.content.Intent;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 |
9 | import com.coolweather.android.R;
10 | import com.coolweather.android.gson.Weather;
11 | import com.coolweather.android.util.Utility;
12 |
13 | public class MainActivity extends AppCompatActivity {
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
20 | // 有缓存的天气信息,则直接跳转到天气显示界面
21 | String weatherInfo = sp.getString("heWeather", null);
22 | if ( weatherInfo != null) {
23 | Weather weather = Utility.handleWeatherResponse(weatherInfo);
24 | if (weather != null) {
25 | Intent intent = new Intent(this, WeatherActivity.class);
26 | intent.putExtra("weather_id", weather.basic.weatherId);
27 | startActivity(intent);
28 | finish();
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/ui/WeatherActivity.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.ui;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.graphics.Bitmap;
8 | import android.graphics.BitmapFactory;
9 | import android.graphics.Color;
10 | import android.os.Build;
11 | import android.os.Bundle;
12 | import android.preference.PreferenceManager;
13 | import android.support.annotation.Nullable;
14 | import android.support.design.widget.NavigationView;
15 | import android.support.v4.app.FragmentManager;
16 | import android.support.v4.app.FragmentTransaction;
17 | import android.support.v4.content.ContextCompat;
18 | import android.support.v4.widget.DrawerLayout;
19 | import android.support.v4.widget.SwipeRefreshLayout;
20 | import android.support.v7.app.AppCompatActivity;
21 | import android.support.v7.graphics.Palette;
22 | import android.util.Log;
23 | import android.view.Gravity;
24 | import android.view.LayoutInflater;
25 | import android.view.MotionEvent;
26 | import android.view.View;
27 | import android.widget.Button;
28 | import android.widget.FrameLayout;
29 | import android.widget.ImageView;
30 | import android.widget.LinearLayout;
31 | import android.widget.TextView;
32 | import android.widget.Toast;
33 |
34 | import com.bumptech.glide.Glide;
35 | import com.bumptech.glide.load.resource.bitmap.CenterCrop;
36 | import com.coolweather.android.R;
37 | import com.coolweather.android.gson.DailyForecast;
38 | import com.coolweather.android.gson.Weather;
39 | import com.coolweather.android.service.AutoUpdateWeatherService;
40 | import com.coolweather.android.ui.fragment.ChooseAreaFragment;
41 | import com.coolweather.android.ui.widget.TimeoutProgressBar;
42 | import com.coolweather.android.util.BitmapHelper;
43 | import com.coolweather.android.util.HttpUtil;
44 | import com.coolweather.android.util.Utility;
45 |
46 | import java.io.IOException;
47 | import java.util.Random;
48 |
49 | import okhttp3.Call;
50 | import okhttp3.Callback;
51 | import okhttp3.Response;
52 |
53 | public class WeatherActivity extends AppCompatActivity {
54 | public final Context mContext = WeatherActivity.this;
55 | public final String TAG = "onWeatherActivity";
56 |
57 | private String mWeatherId;
58 |
59 | private LinearLayout weatherLayout;
60 |
61 | TextView areaTitleTv;
62 |
63 | TextView nowTimeTv;
64 |
65 | TextView temperatureTv;
66 |
67 | TextView weatherInfoTv;
68 |
69 | TextView aqiTv;
70 |
71 | TextView pm25Tv;
72 |
73 | TextView comfortTv;
74 |
75 | TextView carWashTv;
76 |
77 | TextView sportTv;
78 |
79 | LinearLayout forecastLayout;
80 |
81 | public SwipeRefreshLayout swipeRefreshLayout;
82 |
83 | private SharedPreferences sp;
84 |
85 | private ImageView bingPicImg;
86 |
87 | private static final String BingPicAddress = "http://guolin.tech/api/bing_pic";
88 |
89 | public DrawerLayout drawerLayout;
90 | public FrameLayout sideLayout;
91 | public NavigationView mNavView;
92 |
93 | private TimeoutProgressBar mProgressBar;
94 |
95 | private int picResId;
96 | private Bitmap weatherPic;
97 |
98 | @Override
99 | protected void onCreate(@Nullable Bundle savedInstanceState) {
100 | super.onCreate(savedInstanceState);
101 | if (Build.VERSION.SDK_INT >= 21) {
102 | // 将背景图和状态栏融合到一起
103 | View decorView = getWindow().getDecorView();
104 | decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
105 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
106 | getWindow().setStatusBarColor(Color.TRANSPARENT);
107 | }
108 | setContentView(R.layout.activity_weather);
109 |
110 | initData();
111 |
112 | initEvent();
113 |
114 | // 加载天气信息前,先隐藏天气界面布局,优化视觉效果
115 | weatherLayout.setVisibility(View.INVISIBLE);
116 |
117 | //loadBgPic();
118 |
119 | loadWeatherInfo();
120 |
121 | weatherLayout.setVisibility(View.VISIBLE);
122 |
123 | }
124 |
125 | @Override
126 | public void onWindowFocusChanged(boolean hasFocus) {
127 | super.onWindowFocusChanged(hasFocus);
128 | if (hasFocus) {
129 | Log.w(TAG, "获得焦点");
130 | setTemperatureTextColor();
131 | }
132 | }
133 |
134 |
135 | /**
136 | * 设置显示温度文本颜色
137 | */
138 | private void setTemperatureTextColor() {
139 | new Thread(() -> {
140 | // 默认字体颜色为纯白色
141 | int color = 0xffffffff;
142 |
143 | int[] coordinate = new int[10];
144 | coordinate = getViewCoordinate(temperatureTv);
145 |
146 | if (weatherPic == null) {
147 | weatherPic = BitmapFactory.decodeResource(getResources(), picResId);
148 | View decorview = getWindow().getDecorView();
149 | int picWidth = decorview.getWidth();
150 | int picHeight = decorview.getHeight();
151 | Log.d(TAG, "图片缩放宽度:" + picWidth + " 图片缩放高度:" + picHeight);
152 | // 设定缩放图片的宽高和手机屏幕宽高尺寸一致
153 | weatherPic = BitmapHelper.resizePicture(weatherPic, picWidth, picHeight);
154 | }
155 | if (weatherPic != null) {
156 | // 分别获取view左上角、右上角、右下角、左下角、中心点的坐标对应的颜色值
157 | int ltColor = weatherPic.getPixel(coordinate[0], coordinate[1]);
158 |
159 | int rtColor = weatherPic.getPixel(coordinate[2], coordinate[3]);
160 |
161 | int rbColor = weatherPic.getPixel(coordinate[4], coordinate[5]);
162 |
163 | int lbColor = weatherPic.getPixel(coordinate[6], coordinate[7]);
164 |
165 | int centerColor = weatherPic.getPixel(coordinate[8], coordinate[9]);
166 |
167 | // 又5个点对应的颜色值,这里取均值权重 weight = 0.2f
168 | float weight = 0.15f;
169 |
170 | int blue = (int) ((ltColor & 0xff) * weight + (rtColor & 0xff) * weight
171 | + (rbColor & 0xff) * weight + (lbColor & 0xff) * weight + (centerColor & 0xff) * 0.4f + 0.5f);
172 |
173 | int green = (int) (((ltColor >> 8) & 0xff) * weight + ((rtColor >> 8) & 0xff) * weight
174 | + ((rbColor >> 8) & 0xff) * weight + ((lbColor >> 8) & 0xff) * weight
175 | + ((centerColor >> 8) & 0xff) * 0.4f + 0.5f);
176 |
177 | int red = (int) (((ltColor >> 16) & 0xff) * weight + ((rtColor >> 16) & 0xff) * weight
178 | + ((rbColor >> 16) & 0xff) * weight + ((lbColor >> 16) & 0xff) * weight
179 | + ((centerColor >> 16) & 0xff) * 0.4f + 0.5f);
180 |
181 | int alpha = (int) ((ltColor >>> 24) * weight + (rtColor >>> 24) * weight
182 | + (rbColor >>> 24) * weight + (lbColor >>> 24) * weight
183 | + (centerColor >>> 24) * 0.4f + 0.5f);
184 | Log.d(TAG, "取色:alpha:" + alpha + " red:" + red + " green:" + green + " blue:" + blue);
185 |
186 | // 计算补色
187 | blue = 255 - blue;
188 | green = 255 - green;
189 | red = 255 - red;
190 | // alpha = 255 - alpha;
191 | Log.d(TAG, "补色:alpha:" + alpha + " red:" + red + " green:" + green + " blue:" + blue);
192 | // 合并颜色值
193 | color = (alpha << 24) | (red << 16) | (green << 8) | blue;
194 | Log.d(TAG, "合并的颜色值:" + Integer.toHexString(color));
195 | } else {
196 | Log.w(TAG, "bitmap为null,默认设置view文本颜色为纯白色");
197 | }
198 | // 设置显示温度文本字体颜色
199 | int finalColor = color;
200 | runOnUiThread(() -> {
201 | temperatureTv.setTextColor(finalColor);
202 | });
203 | }).start();
204 | }
205 |
206 | private int[] getViewCoordinate(View view) {
207 | int[] coordinate = new int[10];
208 | int[] topLeftCorner = new int[2];
209 | view.getLocationOnScreen(topLeftCorner);
210 | int width = view.getWidth();
211 | int height = view.getHeight();
212 | // 保存view的左上角坐标
213 | coordinate[0] = topLeftCorner[0];
214 | coordinate[1] = topLeftCorner[1];
215 |
216 | // 保存view的右上角的坐标
217 | coordinate[2] = coordinate[0] + width;
218 | coordinate[3] = coordinate[1];
219 |
220 | // 保存view的右下角坐标
221 | coordinate[4] = coordinate[2];
222 | coordinate[5] = coordinate[3] + height;
223 |
224 | // 保存view的左下角坐标
225 | coordinate[6] = coordinate[0];
226 | coordinate[7] = coordinate[5];
227 |
228 | // 保存view的中心点的坐标
229 | coordinate[8] = coordinate[0] + width / 2;
230 | coordinate[9] = coordinate[1] + height / 2;
231 | StringBuilder builder = new StringBuilder();
232 | builder.append("左上角坐标:(" + coordinate[0] + "," + coordinate[1] + ")\n");
233 | builder.append("右上角坐标:(" + coordinate[2] + "," + coordinate[3] + ")\n");
234 | builder.append("右下角坐标:(" + coordinate[4] + "," + coordinate[5] + ")\n");
235 | builder.append("左下角坐标:(" + coordinate[6] + "," + coordinate[7] + ")\n");
236 | builder.append("中心点坐标:(" + coordinate[8] + "," + coordinate[9] + ")");
237 | Log.i(TAG, builder.toString());
238 | return coordinate;
239 | }
240 |
241 | @Override
242 | protected void onResume() {
243 | super.onResume();
244 | }
245 |
246 | @Override
247 | public boolean dispatchTouchEvent(MotionEvent ev) {
248 | switch (ev.getAction()) {
249 | case MotionEvent.ACTION_DOWN:
250 | Log.d("onWeatherActivity", "执行dispatchTouchEvent方法的手指按下");
251 | Log.d(TAG, "点击点坐标:(" + ev.getX() + "," + ev.getY() + ")");
252 | //mProgressBar.resetProgressBar();
253 | mProgressBar.resetProgressBar(true);
254 | break;
255 | case MotionEvent.ACTION_MOVE:
256 | Log.d("onWeatherActivity", "执行dispatchTouchEvent方法的手指滑动");
257 | break;
258 | default:
259 | break;
260 | }
261 | return super.dispatchTouchEvent(ev);
262 | }
263 |
264 | /**
265 | * 加载天气信息
266 | */
267 | private void loadWeatherInfo() {
268 | String weatherInfo = sp.getString("heWeather", null);
269 | if (weatherInfo != null) {
270 | // sp里有缓存的天气信息数据
271 | Weather weather = Utility.handleWeatherResponse(weatherInfo);
272 | if (mWeatherId.equals(weather.basic.weatherId)) {
273 | //且请求的weatherId与sp里缓存的一致,则直接显示缓存的天气信息
274 | // 加载天气背景图片
275 | loadWeatherBgPic(weather.now.more.code);
276 | // 显示天气情况
277 | showWeatherInfo(weather);
278 | } else {
279 | // 请求的天气id和缓存里的不一致,则需重新请求网络来更新天气信息
280 | requestWeather(mWeatherId);
281 | }
282 | } else {
283 | // sp里没有缓存的天气信息数据,需请求网络来获取天气信息
284 | requestWeather(mWeatherId);
285 | }
286 | }
287 |
288 | /**
289 | * 根据天气情况加载对应天气背景图片
290 | *
291 | * @param code 天气代码
292 | * 天气代码对照
293 | * 100 晴天
294 | * 101~103 多云
295 | * 104 阴天
296 | * 300~399 雨天
297 | * 400~499 雪天
298 | * 其他 非上述天气情况
299 | */
300 | private void loadWeatherBgPic(String code) {
301 |
302 | String picResName = getPicResName(code);
303 | if ("other".equals(picResName)) {
304 | // 非上述天气情况,则加载默认天气背景图片:Bing每日一图
305 | loadDefaultBgPic();
306 | } else {
307 | // 加载对应的天气背景图片
308 | picResId = getResources().getIdentifier(picResName, "drawable", getPackageName());
309 | Log.d("天气背景图片资源id", "" + picResId);
310 | if (picResId != 0) {
311 | Glide.with(mContext).load(picResId).into(bingPicImg);
312 | }
313 | }
314 | }
315 |
316 | private String getPicResName(String code) {
317 | // 初始默认设定为非上述天气情况
318 | String name = "other";
319 | if (code.startsWith("1")) {
320 | if ("100".equals(code)) {
321 | name = "sunny" + getPicRandomIndex(1, 2);
322 | } else if ("104".equals(code)) {
323 | // 加载阴天天气背景图片
324 | name = "overcast" + getPicRandomIndex(1, 1);
325 | } else {
326 | // 加载多云天气背景图片
327 | name = "cloudy" + getPicRandomIndex(1, 3);
328 | }
329 | } else if (code.startsWith("3")) {
330 | // 加载雨天天气背景图片
331 | name = "rain" + getPicRandomIndex(1, 2);
332 | } else if (code.startsWith("4")) {
333 | // 加载雪天天气背景图片
334 | name = "snow" + getPicRandomIndex(1, 2);
335 | }
336 | Log.d("天气背景图片名称", name);
337 | return name;
338 | }
339 |
340 | private int getPicRandomIndex(int startIndex, int endIndex) {
341 | return new Random().nextInt(endIndex - startIndex + 1) + startIndex;
342 | }
343 |
344 | /**
345 | * 加载缓存的背景图片
346 | */
347 | private void loadDefaultBgPic() {
348 | String bingPicLink = sp.getString("bing_pic", null);
349 | Log.d("onLoadBgPic", "bing每日背景图链接地址:" + bingPicLink);
350 | if (bingPicLink != null) {
351 | // 有图片链接缓存,就直接读取缓存并加载图片显示出来
352 | Log.d("onLoadBgPic", "有图片链接缓存");
353 | Glide.with(mContext).load(bingPicLink).into(bingPicImg);
354 | } else {
355 | requestBingPic(BingPicAddress);
356 | }
357 | }
358 |
359 | private void initData() {
360 | weatherLayout = findViewById(R.id.weather_layout);
361 | areaTitleTv = findViewById(R.id.title_area);
362 | nowTimeTv = findViewById(R.id.now_time);
363 | temperatureTv = findViewById(R.id.degree_text);
364 | weatherInfoTv = findViewById(R.id.weather_info_text);
365 | aqiTv = findViewById(R.id.aqi);
366 | pm25Tv = findViewById(R.id.pm25);
367 | forecastLayout = findViewById(R.id.forecast_layout);
368 | comfortTv = findViewById(R.id.comfort_text);
369 | carWashTv = findViewById(R.id.car_wash_text);
370 | sportTv = findViewById(R.id.sport_text);
371 |
372 | bingPicImg = findViewById(R.id.bing_pic_img);
373 |
374 | swipeRefreshLayout = findViewById(R.id.swipe_refresh);
375 | swipeRefreshLayout.setColorSchemeColors(ContextCompat.getColor(this, R.color.colorPrimary));
376 |
377 | drawerLayout = findViewById(R.id.drawer_layout);
378 | mNavView = findViewById(R.id.nav_view);
379 | sideLayout = findViewById(R.id.side_layout);
380 | mProgressBar = findViewById(R.id.timeout_progress_bar);
381 | sp = PreferenceManager.getDefaultSharedPreferences(this);
382 |
383 |
384 | mWeatherId = getIntent().getStringExtra("weather_id");
385 | Log.d("onInitData", "天气id:" + mWeatherId);
386 |
387 | }
388 |
389 | private void initEvent() {
390 | addListenerEvent();
391 | Log.d("onInitEvent()方法", "开始启动超时等待任务");
392 | // 开始超时等待任务
393 | Log.d(TAG, "开始属性动画");
394 | mProgressBar.setTimeOut(10);
395 | // mProgressBar.startTimeOut();
396 | mProgressBar.customValueAnimator();
397 | }
398 |
399 | /**
400 | * 事件监听方法
401 | */
402 | private void addListenerEvent() {
403 | /* 添加标题栏展开侧滑栏按钮的点击事件 */
404 | Button switchDrawerBtn = findViewById(R.id.drawer_switch);
405 | switchDrawerBtn.setOnClickListener(view -> {
406 | // lambda表达式
407 | drawerLayout.openDrawer(Gravity.START, true);
408 | });
409 |
410 | /* 添加下拉刷新事件监听 */
411 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
412 | @Override
413 | public void onRefresh() {
414 | Log.d("onRefresh", "天气id:" + mWeatherId);
415 | // 手动下拉刷新天气信息
416 | requestWeather(mWeatherId);
417 | // 数据加载完毕,下拉刷新结束
418 | swipeRefreshLayout.setRefreshing(false);
419 | }
420 | });
421 |
422 | /* 添加点击系统后退按钮事件监听 */
423 |
424 |
425 | /* 设置滑动菜单的item点击事件响应 */
426 | mNavView.setCheckedItem(R.id.nav_location);
427 | mNavView.setNavigationItemSelectedListener(item -> {
428 | switch (item.getItemId()) {
429 | // 点击"选择地址"item
430 | case R.id.nav_location:
431 | // 隐藏滑动菜单
432 | mNavView.setVisibility(View.INVISIBLE);
433 | if (sideLayout.getChildCount() < 2) {
434 | // 添加区域选择界面(fragment view)
435 | FragmentManager fragmentManager = getSupportFragmentManager();
436 | FragmentTransaction transaction = fragmentManager.beginTransaction();
437 | transaction.add(R.id.side_layout, new ChooseAreaFragment(), "frag_view");
438 | transaction.commit();
439 | } else {
440 | // 显示区域选择界面
441 | FragmentManager fragmentManager = getSupportFragmentManager();
442 | FragmentTransaction transaction = fragmentManager.beginTransaction();
443 | transaction.show(fragmentManager.findFragmentByTag("frag_view"));
444 | transaction.commit();
445 | }
446 | return true;
447 |
448 | // 点击"设置"item
449 | case R.id.nav_settings:
450 | Toast.makeText(WeatherActivity.this,
451 | "点击设置菜单选项", Toast.LENGTH_SHORT)
452 | .show();
453 | return true;
454 | default:
455 | return false;
456 | }
457 |
458 | });
459 |
460 | }
461 |
462 | /**
463 | * 请求网络获取背景图片链接地址
464 | **/
465 | private void requestBingPic(String address) {
466 | // 通过网络请求图片链接地址
467 | HttpUtil.sendOkHttpRequest(address, new Callback() {
468 | @Override
469 | public void onFailure(Call call, IOException e) {
470 | Log.w("onLoadBingPic", "请求bing每日背景图片失败:");
471 | }
472 |
473 | @Override
474 | public void onResponse(Call call, Response response) throws IOException {
475 | String bingPicLink = response.body().string();
476 | Log.d("onLoadBingPic", "请求的bing每日背景图链接地址:" + bingPicLink);
477 | // 缓存bing每日一图链接地址
478 | SharedPreferences.Editor editor = sp.edit();
479 | editor.putString("bing_pic", bingPicLink);
480 | editor.apply();
481 | // 加载Bing背景图片
482 | runOnUiThread(new Runnable() {
483 | @Override
484 | public void run() {
485 | Glide.with(mContext).load(bingPicLink).into(bingPicImg);
486 | }
487 | });
488 | }
489 | });
490 |
491 | }
492 |
493 | /**
494 | * 根据天气 id 请求城市天气信息
495 | */
496 | public void requestWeather(String weatherId) {
497 | // requestBingPic(BingPicAddress);
498 | ProgressDialog progressDialog = Utility.showProgressDialog(this);
499 | String address = "http://guolin.tech/api/weather?cityid=" + weatherId
500 | + "&key=c72d9f8149ac436da648ac0e43211edd";
501 | HttpUtil.sendOkHttpRequest(address, new Callback() {
502 | @Override
503 | public void onFailure(Call call, IOException e) {
504 | Log.w("onWeatherActivity", "网络通讯异常");
505 | runOnUiThread(() -> {
506 | Utility.closeProgressDialog(progressDialog);
507 | Toast.makeText(mContext, "网络通讯异常,获取天气信息失败",
508 | Toast.LENGTH_LONG).show();
509 | });
510 | }
511 |
512 | @Override
513 | public void onResponse(Call call, Response response) throws IOException {
514 | String responseText = response.body().string();
515 | if (responseText == null) {
516 | throw new NullPointerException("请求天气信息的响应消息为空");
517 | }
518 | Log.d("onRequestWeather", "天气信息:" + responseText);
519 | // 当前WeatherActivity界面也要保存weatherId
520 | mWeatherId = weatherId;
521 | // 使用SharedPreferences来缓存天气信息数据
522 | SharedPreferences.Editor editor = sp.edit();
523 | editor.putString("heWeather", responseText);
524 | editor.putString("weather_id", weatherId);
525 | editor.apply();
526 | Weather weather = Utility.handleWeatherResponse(responseText);
527 | runOnUiThread(new Runnable() {
528 | @Override
529 | public void run() {
530 | Utility.closeProgressDialog(progressDialog);
531 | if (weather != null && "ok".equals(weather.status)) {
532 | // 加载天气背景图片
533 | loadWeatherBgPic(weather.now.more.code);
534 | showWeatherInfo(weather);
535 | } else {
536 | Log.w("onWeatherActivity", "天气信息json数据异常");
537 | Toast.makeText(WeatherActivity.this, "获取天气信息失败",
538 | Toast.LENGTH_LONG).show();
539 | }
540 | }
541 | });
542 | }
543 | });
544 |
545 | }
546 |
547 | /**
548 | * 处理并展示Weather实体类中的数据
549 | */
550 | private void showWeatherInfo(Weather weather) {
551 |
552 | Log.d("onWeatherActivity", "天气实体类:\n" + weather.toString());
553 | // 显示区域标题
554 | areaTitleTv.setText(weather.basic.cityName);
555 |
556 | // 显示当前天气更新的时间(本地时间)
557 | // weather.basic.update.updateTime 格式:2018-10-29 19:46
558 | String updateTime = weather.basic.update.updateTime.split(" ")[1];
559 | nowTimeTv.setText("更新时间\n" + updateTime);
560 |
561 | // 显示当前天气的气温
562 | temperatureTv.setText(weather.now.temperature + "℃");
563 |
564 | // 显示当前天气情况
565 | weatherInfoTv.setText(weather.now.more.info);
566 |
567 | // 显示未来几天天气情况
568 | showForecastInfo(weather);
569 |
570 | if (weather.aqi != null) {
571 | /* 显示空气质量情况 */
572 | aqiTv.setText(weather.aqi.city.aqi); // 空气质量指数
573 | pm25Tv.setText(weather.aqi.city.pm25); // 显示PM2.5指数
574 | }
575 |
576 | /* 显示生活建议 */
577 | comfortTv.setText("【舒适度】:" + weather.suggestion.comfort.info); // 天气舒适度
578 | carWashTv.setText("【洗车建议】:" + weather.suggestion.carWash.info); // 洗车建议
579 | sportTv.setText("【运动建议】:" + weather.suggestion.sport.info); // 运动建议
580 |
581 | // 加载完背景图片后,再显示天气界面布局
582 | weatherLayout.setVisibility(View.VISIBLE);
583 |
584 | Intent intent = new Intent(this, AutoUpdateWeatherService.class);
585 | startService(intent);
586 | }
587 |
588 | /**
589 | * 显示天气预报信息
590 | **/
591 | private void showForecastInfo(Weather weather) {
592 | forecastLayout.removeAllViews();
593 |
594 | /*Palette palette = Palette.from(BitmapFactory.decodeResource(getResources(), picResId)).generate();
595 | // 获取输入图片中亮丽的颜色,获取失败则默认颜色为纯白色
596 | int bgColor1 = palette.getVibrantColor(0xffffffff);
597 | int bgColor2 = palette.getLightMutedColor(0xffffffff);
598 | int bgColor3 = palette.getLightVibrantColor(0xffffffff);*/
599 |
600 | for (DailyForecast dailyForecast : weather.dailyForecastList) {
601 | View view = LayoutInflater.from(this).inflate(R.layout.forecast_item, forecastLayout, false);
602 | TextView dateTv = view.findViewById(R.id.date_text);
603 | TextView infoTv = view.findViewById(R.id.info_text);
604 | TextView tmpMaxTv = view.findViewById(R.id.tmp_max_text);
605 | TextView tmpMinTv = view.findViewById(R.id.tmp_min_text);
606 |
607 | // 显示天气预报的预报日期
608 | dateTv.setText(dailyForecast.date);
609 |
610 | // 显示预报天气情况
611 | String info = dailyForecast.more.info;
612 | infoTv.setText(info);
613 | // infoTv.setTextColor(bgColor1);
614 |
615 | // 显示当天最高气温
616 | tmpMaxTv.setText("最高气温\n" + dailyForecast.temperature.max + "℃");
617 | // tmpMaxTv.setTextColor(bgColor2);
618 | // 显示当天最低气温
619 | tmpMinTv.setText("最低气温\n" + dailyForecast.temperature.min + "℃");
620 | // tmpMaxTv.setTextColor(bgColor3);
621 |
622 | // 添加天气预报信息的 view 到天气预报界面容器内
623 | forecastLayout.addView(view);
624 | }
625 | }
626 |
627 | }
628 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/ui/fragment/ChooseAreaFragment.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.ui.fragment;
2 |
3 | import android.app.Activity;
4 | import android.app.Dialog;
5 | import android.app.ProgressDialog;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.support.annotation.Nullable;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.app.FragmentManager;
11 | import android.support.v4.app.FragmentTransaction;
12 | import android.util.Log;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.AdapterView;
17 | import android.widget.ArrayAdapter;
18 | import android.widget.Button;
19 | import android.widget.ListView;
20 | import android.widget.TextView;
21 | import android.widget.Toast;
22 |
23 | import com.coolweather.android.R;
24 | import com.coolweather.android.db.City;
25 | import com.coolweather.android.db.County;
26 | import com.coolweather.android.db.Province;
27 | import com.coolweather.android.ui.MainActivity;
28 | import com.coolweather.android.ui.WeatherActivity;
29 | import com.coolweather.android.util.HttpUtil;
30 | import com.coolweather.android.util.Utility;
31 |
32 | import org.litepal.LitePal;
33 |
34 | import java.io.IOException;
35 | import java.util.ArrayList;
36 | import java.util.List;
37 | import java.util.logging.Level;
38 |
39 | import okhttp3.Call;
40 | import okhttp3.Callback;
41 | import okhttp3.Response;
42 |
43 | /**
44 | * 显示省、市、县区域信息
45 | */
46 | public class ChooseAreaFragment extends Fragment {
47 | private Activity mActivity;
48 |
49 | private Button backBtn;
50 |
51 | private TextView titleTv;
52 |
53 | private ListView areaListView;
54 |
55 | private ArrayAdapter adapter;
56 |
57 | /**
58 | * 省级列表数据model
59 | */
60 | private List provinceList;
61 | /**
62 | * 市级列表数据model
63 | */
64 | private List cityList;
65 | /**
66 | * 县级列表数据model
67 | */
68 | private List countyList;
69 |
70 | List dataList;
71 |
72 | /**
73 | * 选中的省份
74 | */
75 | private Province selectedProvince;
76 |
77 | /**
78 | * 选中的城市
79 | */
80 | private City selectedCity;
81 |
82 | /**
83 | * 当前区域列表的层级
84 | */
85 | private int currentLevel;
86 |
87 | public static final int LEVEL_PROVINCE = 0;
88 | public static final int LEVEL_CITY = 1;
89 | public static final int LEVEL_COUNTY = 2;
90 |
91 |
92 | @Nullable
93 | @Override
94 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
95 | View view = inflater.inflate(R.layout.choose_area, container, false);
96 | initData(view);
97 | return view;
98 | }
99 |
100 | @Override
101 | public void onActivityCreated(@Nullable Bundle savedInstanceState) {
102 | super.onActivityCreated(savedInstanceState);
103 | initEvent();
104 | queryProvinces();
105 | }
106 |
107 | private void initData(View view) {
108 | mActivity = getActivity();
109 |
110 | backBtn = view.findViewById(R.id.back_button);
111 | titleTv = view.findViewById(R.id.title_text);
112 | areaListView = view.findViewById(R.id.area_list_view);
113 | dataList = new ArrayList<>();
114 | adapter = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, dataList);
115 | areaListView.setAdapter(adapter);
116 | }
117 |
118 | private void initEvent() {
119 | /* 区域列表item的点击事件处理 */
120 | areaListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
121 | @Override
122 | public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
123 | switch (currentLevel) {
124 | case LEVEL_PROVINCE:
125 | selectedProvince = provinceList.get(position);
126 | queryCities();
127 | break;
128 | case LEVEL_CITY:
129 | selectedCity = cityList.get(position);
130 | queryCounties();
131 | break;
132 | case LEVEL_COUNTY:
133 | Activity activity = getActivity();
134 | String weatheId = countyList.get(position).getWeatherId();
135 | if (activity instanceof MainActivity) {
136 | /* 启动weather activity ,显示选定的区域的天气情况 */
137 | Intent intent = new Intent(getActivity(), WeatherActivity.class);
138 | intent.putExtra("weather_id", weatheId);
139 | mActivity.startActivity(intent);
140 | mActivity.finish();
141 | } else if (activity instanceof WeatherActivity) {
142 | WeatherActivity weatherActivity = (WeatherActivity) activity;
143 |
144 | // 移除选择地址的fragment view
145 | weatherActivity.sideLayout.removeViewAt(1);
146 | // 恢复显示滑动菜单
147 | weatherActivity.mNavView.setVisibility(View.VISIBLE);
148 | // 关闭侧滑栏
149 | weatherActivity.drawerLayout.closeDrawers();
150 |
151 | // 显示新选择的地区的天气信息
152 | weatherActivity.swipeRefreshLayout.setRefreshing(true);
153 | weatherActivity.requestWeather(weatheId);
154 | weatherActivity.swipeRefreshLayout.setRefreshing(false);
155 | }
156 | break;
157 | default:
158 | break;
159 | }
160 | }
161 | });
162 |
163 | /* 标题栏 返回按钮 的点击事件处理 */
164 | backBtn.setOnClickListener((view) -> {
165 | /*
166 | * TODO:每次返回到上级区域列表都需要重新查询数据库,影响性能,
167 | * TODO: 可用一数据结构保存各区域列表信息,减少查询数据库的次数
168 | */
169 | if (currentLevel == LEVEL_COUNTY) {
170 | // 返回到市级列表
171 | queryCities();
172 | } else if (currentLevel == LEVEL_CITY) {
173 | // 返回省级列表
174 | queryProvinces();
175 | } else if (currentLevel == LEVEL_PROVINCE) {
176 | WeatherActivity weatherActivity = (WeatherActivity) getActivity();
177 | // 隐藏区域选择fragment view 界面
178 | FragmentManager fragmentManager = weatherActivity.getSupportFragmentManager();
179 | FragmentTransaction transaction = fragmentManager.beginTransaction();
180 | transaction.hide(fragmentManager.findFragmentByTag("frag_view"));
181 | transaction.commit();
182 | // 返回到滑动菜单
183 | weatherActivity.mNavView.setVisibility(View.VISIBLE);
184 | }
185 | });
186 |
187 | }
188 |
189 | /**
190 | * 查询全国所有的省,优先从数据库中查询,如果没有查询到再去服务器上查询
191 | */
192 | private void queryProvinces() {
193 | titleTv.setText(R.string.province_title);
194 | if (getActivity() instanceof MainActivity) {
195 | backBtn.setVisibility(View.GONE);
196 | }
197 | provinceList = LitePal.findAll(Province.class);
198 | if (provinceList.size() > 0) {
199 | // 本地数据库有省份数据
200 | dataList.clear();
201 | for (Province province : provinceList) {
202 | dataList.add(province.getProvinceName());
203 | }
204 | // underlying data 发生改变,则通知刷新ListView列表信息
205 | adapter.notifyDataSetChanged();
206 | // 选中item初始化置为第一项
207 | areaListView.setSelection(0);
208 | currentLevel = LEVEL_PROVINCE;
209 | } else {
210 | // 本地数据库无省份数据,则网络请求服务器获取省份数据
211 |
212 | String address = "http://guolin.tech/api/china"; // 远程服务器省份区域的接口
213 | queryFromServer(address, "province");
214 |
215 | }
216 |
217 | }
218 |
219 | /**
220 | * 查询选中的省内的所有市,优先从数据库中查询,如果没有查询到再去服务器上查询
221 | */
222 | private void queryCities() {
223 | titleTv.setText(selectedProvince.getProvinceName());
224 | backBtn.setVisibility(View.VISIBLE);
225 | int provinceCode = selectedProvince.getProvinceCode();
226 | cityList = LitePal.where("provinceCode = ?", "" + provinceCode)
227 | .find(City.class);
228 | if (cityList.size() > 0) {
229 | dataList.clear();
230 | for (City city : cityList) {
231 | dataList.add(city.getCityName());
232 | }
233 | adapter.notifyDataSetChanged();
234 | areaListView.setSelection(0);
235 | currentLevel = LEVEL_CITY;
236 | } else {
237 | String address = "http://guolin.tech/api/china/" + provinceCode;
238 | queryFromServer(address, "city");
239 | }
240 | }
241 |
242 | /**
243 | * 查询选中的市内所有的县,优先从数据库中查询,如果没有查询到再去服务器上查询
244 | */
245 | private void queryCounties() {
246 | titleTv.setText(selectedCity.getCityName());
247 | int cityCode = selectedCity.getCityCode();
248 | countyList = LitePal.where("cityCode = ?", "" + cityCode)
249 | .find(County.class);
250 | if (countyList.size() > 0) {
251 | dataList.clear();
252 | for (County county : countyList) {
253 | dataList.add(county.getCountyName());
254 | }
255 | adapter.notifyDataSetChanged();
256 | areaListView.setSelection(0);
257 | currentLevel = LEVEL_COUNTY;
258 | } else {
259 | int provinceCode = selectedCity.getProvinceCode();
260 | String address = "http://guolin.tech/api/china/" + provinceCode + "/" + cityCode;
261 | queryFromServer(address, "county");
262 | }
263 | }
264 |
265 | /**
266 | * 根据传入的地址和类型从服务器上查询省市县的数据
267 | */
268 | private void queryFromServer(String address, final String type) {
269 | final ProgressDialog progressDialog = Utility.showProgressDialog(mActivity);
270 | // 发送网络请求
271 | HttpUtil.sendOkHttpRequest(address, new Callback() {
272 | @Override
273 | public void onFailure(Call call, IOException e) {
274 | Log.d("onChooseAreaFragment", "网络请求失败");
275 | // UI的变化,需要在UI线程上进行处理
276 | mActivity.runOnUiThread(new Runnable() {
277 | @Override
278 | public void run() {
279 | Utility.closeProgressDialog(progressDialog);
280 | Toast.makeText(getContext(), "网络请求失败", Toast.LENGTH_LONG).show();
281 | }
282 | });
283 | }
284 |
285 | @Override
286 | public void onResponse(Call call, Response response) throws IOException {
287 | Log.d("onChooseAreaFragment", "当前线程:" + Thread.currentThread().toString());
288 | String responseText = response.body().string(); // json格式的省份数据
289 | boolean result = false;
290 | switch (type) {
291 | case "province":
292 | result = Utility.handleProvinceResponse(responseText);
293 | break;
294 | case "city":
295 | result = Utility.handleCityResponse(responseText, selectedProvince.getProvinceCode());
296 | break;
297 | case "county":
298 | result = Utility.handleCountyResponse(responseText, selectedCity.getCityCode());
299 | break;
300 | default:
301 | break;
302 | }
303 | if (!result) {
304 | Log.d("onChooseAreaFragment", "解析json数据异常");
305 | // UI的变化,需要在UI线程上进行处理
306 | mActivity.runOnUiThread(new Runnable() {
307 | @Override
308 | public void run() {
309 | Utility.closeProgressDialog(progressDialog);
310 | Toast.makeText(mActivity, "解析数据异常", Toast.LENGTH_LONG).show();
311 | }
312 | });
313 | } else {
314 | Log.d("onChooseAreaFragment", "解析json数据成功");
315 | Log.d("onChooseAreaFragment", "mActivity信息:" + mActivity.toString());
316 | mActivity.runOnUiThread(new Runnable() {
317 | // 查询区域信息涉及到UI操作,需要从子线程切换到主线程上来处理
318 | @Override
319 | public void run() {
320 | Utility.closeProgressDialog(progressDialog);
321 | switch (type) {
322 | case "province":
323 | queryProvinces();
324 | break;
325 | case "city":
326 | queryCities();
327 | break;
328 | case "county":
329 | queryCounties();
330 | break;
331 | default:
332 | break;
333 | }
334 | }
335 | });
336 | }
337 | }
338 | });
339 | }
340 |
341 | }
342 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/ui/widget/TimeoutProgressBar.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.ui.widget;
2 |
3 | import android.animation.Animator;
4 | import android.animation.ValueAnimator;
5 | import android.app.Activity;
6 | import android.content.Context;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.util.DisplayMetrics;
11 | import android.util.Log;
12 | import android.view.Display;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.widget.FrameLayout;
16 | import android.widget.ImageView;
17 |
18 | import com.coolweather.android.R;
19 |
20 | import java.util.concurrent.ExecutorService;
21 | import java.util.concurrent.LinkedBlockingQueue;
22 | import java.util.concurrent.ThreadPoolExecutor;
23 | import java.util.concurrent.TimeUnit;
24 |
25 | /**
26 | * 自定义超时进度条,用于界面操作超时,返回到上一步Activity 或 Fragment
27 | **/
28 | public class TimeoutProgressBar extends FrameLayout {
29 | /**
30 | * 超时时长(单位:秒)
31 | */
32 | private int mTimeOut;
33 |
34 | public boolean isTimeOuted() {
35 | return isTimeOuted;
36 | }
37 |
38 | private boolean isTimeOuted;
39 |
40 | /**
41 | * 屏幕水平方向尺寸(单位:pixel)
42 | */
43 | private int mWidthSize;
44 |
45 | /** 重置进度条位置状态的标志 */
46 | private volatile boolean isReset;
47 |
48 | private Context mContext;
49 |
50 | private ImageView mProgressBarIv;
51 |
52 | private View view;
53 |
54 | ValueAnimator mValueAnimator;
55 |
56 | public TimeoutProgressBar(@NonNull Context context, int timeOut) {
57 | super(context);
58 | Log.d("在超时进度条", "构造方法1被执行");
59 | init(context, timeOut);
60 | }
61 |
62 | public TimeoutProgressBar(@NonNull Context context, @Nullable AttributeSet attrs) {
63 | super(context, attrs);
64 | Log.d("在超时进度条", "构造方法2被执行");
65 | init(context, 60);
66 | }
67 |
68 | public TimeoutProgressBar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
69 | super(context, attrs, defStyleAttr);
70 | Log.d("在超时进度条", "构造方法3被执行");
71 | init(context, 60);
72 | }
73 |
74 | private void init(Context context, int timeOut) {
75 | mContext = context;
76 | mTimeOut = timeOut;
77 | Display display = ((Activity) mContext).getWindowManager().getDefaultDisplay();
78 | DisplayMetrics displayMetrics = new DisplayMetrics();
79 | display.getMetrics(displayMetrics);
80 | // 屏幕水平方向尺寸(单位:pixel)
81 | mWidthSize = displayMetrics.widthPixels;
82 | isReset = false;
83 | initView();
84 | }
85 |
86 | private void initView() {
87 | view = LayoutInflater.from(mContext).inflate(R.layout.timeout_progress_bar, this, true);
88 | Log.d("View是", view.toString());
89 | mProgressBarIv = view.findViewById(R.id.progress_bar_image);
90 | Log.d("on超时进度条initView()方法", mProgressBarIv.toString());
91 | }
92 |
93 | /**
94 | * 开始超时等待任务
95 | */
96 | public void startTimeOut() {
97 | Log.d("mWidthSize值:", mWidthSize + "");
98 | /* 每秒宽度增长的步长 *//*
99 | int speed = mWidthSize / mTimeOut;
100 | Log.d("speed值:", "" + speed);*/
101 | defineValueAnimator();
102 | // 启动属性动画
103 | mValueAnimator.start();
104 | }
105 |
106 | /**
107 | * 属性动画,实现进度条随时间自增长
108 | */
109 | private void defineValueAnimator() {
110 | mValueAnimator = ValueAnimator.ofInt(1, mWidthSize);
111 | mValueAnimator.setDuration(mTimeOut * 1000);
112 | // 设置动画重复次数:设定值 + 1
113 | mValueAnimator.setRepeatCount(0);
114 | // 设置重复播放动画模式
115 | mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
116 |
117 | mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
118 | @Override
119 | public void onAnimationUpdate(ValueAnimator valueAnimator) {
120 | int width = (Integer) valueAnimator.getAnimatedValue();
121 | mProgressBarIv.getLayoutParams().width = mWidthSize - width;
122 | mProgressBarIv.requestLayout();
123 | }
124 | });
125 |
126 | mValueAnimator.addListener(new Animator.AnimatorListener() {
127 | @Override
128 | public void onAnimationStart(Animator animator) {
129 | isTimeOuted = false;
130 | isReset = false;
131 | }
132 |
133 | @Override
134 | public void onAnimationEnd(Animator animator) {
135 | if (isReset) {
136 | Log.d("onTimeOutProgressBar","执行属性动画结束回调方法");
137 | return;
138 | }
139 | Log.d("onTimeOutProgressBar","执行属性动画结束回调方法(动画结束)");
140 | isTimeOuted = true;
141 | setVisibility(INVISIBLE);
142 | }
143 |
144 | @Override
145 | public void onAnimationCancel(Animator animator) {
146 | Log.d("onTimeOutProgressBar","执行属性动画取消回调方法");
147 | isReset = true;
148 | //mProgressBarIv.requestLayout();
149 | //mValueAnimator.start();
150 | }
151 |
152 | @Override
153 | public void onAnimationRepeat(Animator animator) {
154 |
155 | }
156 | });
157 | }
158 |
159 |
160 | /**
161 | * 自定义属性动画,实现进度条随时间自增长
162 | */
163 | public void customValueAnimator() {
164 | /* 每秒宽度增长的步长 */
165 | int speed = mWidthSize / mTimeOut;
166 | Log.d("speed值:", "" + speed);
167 | Runnable updateProgressTask = new Runnable() {
168 | @Override
169 | public void run() {
170 | try {
171 | int curWidth = mWidthSize;
172 | isTimeOuted = false;
173 | // 当curWidth == 0 时,表明进度条长度已达最大值,长度变化结束
174 | while (curWidth > 0) {
175 | if (isReset) {
176 | isReset = false;
177 | curWidth = mWidthSize;
178 | mProgressBarIv.getLayoutParams().width = mWidthSize;
179 | ((Activity) mContext).runOnUiThread(new Runnable() {
180 | @Override
181 | public void run() {
182 | // 指定控件的属性值发送改变后,需要请求重绘布局
183 | mProgressBarIv.requestLayout();
184 | }
185 | });
186 | continue;
187 | }
188 | // 每秒curWidth减小speed,即进度条每秒增长speed大小的像素
189 | Thread.sleep(1000);
190 | curWidth -= speed;
191 | if (curWidth < 0) {
192 | curWidth = 0;
193 | }
194 | mProgressBarIv.getLayoutParams().width = curWidth;
195 | ((Activity) mContext).runOnUiThread(new Runnable() {
196 | @Override
197 | public void run() {
198 | // 指定控件的属性值发送改变后,需要请求重绘布局
199 | mProgressBarIv.requestLayout();
200 | if (mProgressBarIv.getLayoutParams().width == 0) {
201 | isTimeOuted = true;
202 | setVisibility(INVISIBLE);
203 | }
204 | }
205 | });
206 | }
207 | } catch (InterruptedException e) {
208 | e.printStackTrace();
209 | }
210 | }
211 | };
212 | // 使用线程池来管理线程的生命周期和系统资源的占用
213 | ExecutorService singleThreadPool = new ThreadPoolExecutor(1,1,0,
214 | TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
215 | singleThreadPool.execute(updateProgressTask);
216 | singleThreadPool.shutdown();
217 | // new Thread(updateProgressTask).start();
218 | }
219 |
220 | public int getTimeOut() {
221 | return mTimeOut;
222 | }
223 |
224 | public void setTimeOut(int mTimeOut) {
225 | this.mTimeOut = mTimeOut;
226 | }
227 |
228 | /** 重置属性动画状态 */
229 | public void resetProgressBar() {
230 | if (mValueAnimator.isRunning()) {
231 | Log.d("onTimeOutProgressBar","执行重置动画");
232 | mValueAnimator.cancel();
233 | mValueAnimator.start();
234 | }
235 |
236 | }
237 |
238 | /**
239 | * 重置进度条状态
240 | * @param isReset true:重置 false:不重置
241 | **/
242 | public void resetProgressBar(Boolean isReset) {
243 | this.isReset = isReset;
244 | }
245 |
246 |
247 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/util/BitmapHelper.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.util;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 | import android.graphics.Matrix;
6 |
7 | import java.io.ByteArrayInputStream;
8 | import java.io.ByteArrayOutputStream;
9 |
10 | public class BitmapHelper {
11 | /** 压缩图片大小 */
12 | private Bitmap comp(Bitmap image) {
13 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
14 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
15 | if (baos.toByteArray().length / 1024 > 1024) {
16 | //判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
17 | baos.reset();//重置baos即清空baos
18 | image.compress(Bitmap.CompressFormat.JPEG, 50, baos);
19 | //这里压缩50%,把压缩后的数据存放到baos中
20 | }
21 | ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
22 | BitmapFactory.Options newOpts = new BitmapFactory.Options();
23 | //开始读入图片,此时把options.inJustDecodeBounds 设回true了
24 | newOpts.inJustDecodeBounds = true;
25 | Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
26 | newOpts.inJustDecodeBounds = false;
27 | int w = newOpts.outWidth;
28 | int h = newOpts.outHeight;
29 | //现在主流手机比较多是800*500分辨率,所以高和宽我们设置为
30 | float hh = 800f;//这里设置高度为800f
31 | float ww = 500f;//这里设置宽度为500f
32 |
33 | //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可,scaling=1 表示不缩放
34 | int scaling = 1;
35 | if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
36 | scaling = (int) (newOpts.outWidth / ww);
37 | } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
38 | scaling = (int) (newOpts.outHeight / hh);
39 | }
40 | if (scaling <= 0) {
41 | scaling = 1;
42 | }
43 | newOpts.inSampleSize = scaling;//设置缩放比例
44 | //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
45 | isBm = new ByteArrayInputStream(baos.toByteArray());
46 | bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
47 | return bitmap;//压缩好比例大小后再进行质量压缩
48 | }
49 |
50 | /**
51 | * 调整图片分辨率
52 | */
53 | public static Bitmap resizePicture(Bitmap bitmap ,int newWidth, int newHeight) {
54 | if (bitmap == null) {
55 | return null;
56 | }
57 | if (newWidth <= 0 || newHeight <= 0) {
58 | return bitmap;
59 | }
60 |
61 | int picWidth = bitmap.getWidth();
62 | int picHeight = bitmap.getHeight();
63 |
64 | float scaleWidth = (float) newWidth / picWidth;
65 | float scaleHeight = (float) newHeight / picHeight;
66 |
67 | Matrix matrix = new Matrix();
68 | matrix.postScale(scaleWidth,scaleHeight);
69 |
70 | return Bitmap.createBitmap(bitmap, 0, 0, picWidth, picHeight, matrix, true);
71 | }
72 |
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/util/HttpUtil.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.util;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import okhttp3.OkHttpClient;
6 | import okhttp3.Request;
7 |
8 | public class HttpUtil {
9 | /** 连接超时时长 */
10 | public final static int CONNECT_TIMEOUT =5;
11 | /** 读超时时长 */
12 | public final static int READ_TIMEOUT=10;
13 | /** 写超时时长 */
14 | public final static int WRITE_TIMEOUT=6;
15 |
16 | /** 发送一条网络请求,并返回响应数据 */
17 | public static void sendOkHttpRequest(String address, okhttp3.Callback callback) {
18 | OkHttpClient client = new OkHttpClient.Builder()
19 | .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
20 | .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)
21 | .writeTimeout(WRITE_TIMEOUT,TimeUnit.SECONDS)
22 | .build();
23 | Request request = new Request.Builder()
24 | .url(address)
25 | .build();
26 | client.newCall(request).enqueue(callback);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/util/Utility.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.util;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Context;
5 | import android.text.TextUtils;
6 | import android.util.Log;
7 |
8 | import com.coolweather.android.R;
9 | import com.coolweather.android.db.City;
10 | import com.coolweather.android.db.County;
11 | import com.coolweather.android.db.Province;
12 | import com.coolweather.android.gson.Weather;
13 | import com.google.gson.Gson;
14 |
15 | import org.json.JSONArray;
16 | import org.json.JSONException;
17 | import org.json.JSONObject;
18 |
19 | public class Utility {
20 | /**
21 | * 解析服务器返回的省级数据(JSON格式),并保持到数据库
22 | */
23 | public static boolean handleProvinceResponse(String response) {
24 | if (!TextUtils.isEmpty(response)) {
25 | Log.d(Utility.class.getSimpleName(), "返回的省级信息:" + response);
26 | try {
27 | /* 解析JSON格式数据 */
28 | JSONArray allProvinces = new JSONArray(response);
29 | JSONObject provinceObject;
30 | Province province;
31 | for (int i = 0; i < allProvinces.length(); i++) {
32 | provinceObject = allProvinces.getJSONObject(i);
33 | province = new Province();
34 | province.setProvinceName(provinceObject.getString("name"));
35 | province.setProvinceCode(provinceObject.getInt("id"));
36 | province.save();
37 | }
38 | return true;
39 | } catch (JSONException e) {
40 | e.printStackTrace();
41 | }
42 | }
43 | return false;
44 | }
45 |
46 | /**
47 | * 解析服务器返回的市级数据(JSON格式)
48 | */
49 | public static boolean handleCityResponse(String response, int provinceCode) {
50 | if (!TextUtils.isEmpty(response)) {
51 | try {
52 | Log.d(Utility.class.getSimpleName(), "返回的市级信息:" + response);
53 | /* 解析JSON格式数据 */
54 | JSONArray allCities = new JSONArray(response);
55 | JSONObject cityObject;
56 | City city;
57 | for (int i = 0; i < allCities.length(); i++) {
58 | cityObject = allCities.getJSONObject(i);
59 | city = new City();
60 | city.setCityCode(cityObject.getInt("id"));
61 | city.setCityName(cityObject.getString("name"));
62 | city.setProvinceCode(provinceCode);
63 | city.save();
64 | }
65 | return true;
66 | } catch (JSONException e) {
67 | e.printStackTrace();
68 | }
69 | }
70 | return false;
71 | }
72 |
73 | /**
74 | * 解析服务器返回的县级数据(JSON格式)
75 | */
76 | public static boolean handleCountyResponse(String response, int cityCode) {
77 | if (!TextUtils.isEmpty(response)) {
78 | try {
79 | Log.d(Utility.class.getSimpleName(), "返回的县级信息:" + response);
80 | JSONObject countyObject;
81 | County county;
82 | /* 解析JSON格式数据 */
83 | JSONArray allCounties = new JSONArray(response);
84 | for (int i = 0; i < allCounties.length(); i++) {
85 | countyObject = allCounties.getJSONObject(i);
86 | county = new County();
87 | county.setCountyCode(countyObject.getInt("id"));
88 | county.setCountyName(countyObject.getString("name"));
89 | county.setWeatherId(countyObject.getString("weather_id"));
90 | county.setCityCode(cityCode);
91 | county.save();
92 | }
93 | return true;
94 | } catch (JSONException e) {
95 | e.printStackTrace();
96 | }
97 | }
98 | return false;
99 | }
100 |
101 | /**
102 | * 解析服务器返回的天气信息数据(JSON格式)
103 | */
104 | public static Weather handleWeatherResponse(String response) {
105 | try {
106 | JSONObject jsonObject = new JSONObject(response);
107 | JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");
108 | String weatherContent = jsonArray.getJSONObject(0).toString();
109 | return new Gson().fromJson(weatherContent, Weather.class);
110 | } catch (JSONException e) {
111 | Log.e("onUtility", "解析weather json 失败");
112 | e.printStackTrace();
113 | }
114 | return null;
115 | }
116 |
117 | /**
118 | * 关闭进度对话框
119 | */
120 | public static void closeProgressDialog(ProgressDialog dialog) {
121 | if (dialog != null) {
122 | dialog.dismiss();
123 | }
124 | }
125 |
126 | /**
127 | * 网络请求数据时显示进度对话框
128 | */
129 | public static ProgressDialog showProgressDialog(Context context) {
130 | ProgressDialog progressDialog = new ProgressDialog(context,R.style.styleDialog);
131 | progressDialog.setTitle("网络请求");
132 | progressDialog.setMessage("正在加载数据...");
133 | progressDialog.setCanceledOnTouchOutside(false);
134 | progressDialog.show();
135 | return progressDialog;
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/com/coolweather/android/util/listener/TimeOutListener.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android.util.listener;
2 |
3 | public interface TimeOutListener {
4 | /** 超时操作处理 */
5 | void timeOut();
6 |
7 | /** 未超时操作处理 */
8 | void unTimeOut();
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/cloudy1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/cloudy1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/cloudy2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/cloudy2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/cloudy3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/cloudy3.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/ic_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_forward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/ic_forward.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/location.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/overcast1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/overcast1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/panda.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/panda.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/rain1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/rain1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/rain2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/rain2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/snow1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/snow1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/snow2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/snow2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/sunny1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/sunny1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/sunny2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/sunny2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/thunder1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/thunder1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/thunder2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/thunder2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/timeout_progress_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/drawable-xxhdpi/timeout_progress_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_weather.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
17 |
18 |
19 |
24 |
25 |
26 |
30 |
31 |
32 |
36 |
37 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
66 |
67 |
68 |
75 |
76 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/aqi.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
19 |
20 |
25 |
26 |
31 |
32 |
39 |
40 |
47 |
48 |
49 |
50 |
51 |
52 |
57 |
62 |
69 |
70 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/choose_area.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
11 |
18 |
19 |
27 |
28 |
29 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/forcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
15 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/forecast_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
26 |
27 |
36 |
37 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
14 |
22 |
23 |
24 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/now.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
21 |
22 |
28 |
29 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/suggestion.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
23 |
24 |
31 |
32 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/timeout_progress_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/weather_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
26 |
27 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xxhdpi/ic_weather.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #FFFFFF
7 | #FF000000
8 | #00000000
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 24dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CoolWeather
3 | 中国
4 |
5 | 天气预报
6 | 空气质量>
7 | PM2.5指数
8 | 空气质量指数
9 | 生活建议
10 | 选择城市
11 | 设置
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/test/java/com/coolweather/android/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.coolweather.android;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.1.3'
12 |
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/flyneat/coolweather/8677ca152608abaa3a8b8f3c587b2ed95dcbe5e9/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 11 09:42:11 CST 2018
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-4.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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------