mirror of
https://github.com/xcc3641/SeeWeather.git
synced 2026-10-16 21:13:37 +08:00
readme
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 就看天气
|
||||
|
||||
----
|
||||
----
|
||||
|
||||
### 前言
|
||||
最初上线是在2015年10月,是自己第一个较为成熟的应用,开发完之后刚好答了知乎这篇[如何自学Android编程][1]
|
||||
@@ -10,7 +10,7 @@
|
||||
当然自己也在学习之中,如果发现有任何问题和建议,随时欢迎Email或者开Issues
|
||||
|
||||
|
||||
- **开源不易,希望能给个Star鼓励**
|
||||
- **开源不易,希望能给个Star鼓励**
|
||||
- 项目地址:https://github.com/xcc3641/SeeWeather
|
||||
- 项目主页发布issue: https://github.com/xcc3641/SeeWeather/issues
|
||||
- 本项目为开源项目,技术交流可以通过邮箱联系: Hugo3641@gmail.com
|
||||
@@ -25,7 +25,7 @@
|
||||
- 彩蛋(自动夜间状态)
|
||||
|
||||
|
||||
----
|
||||
----
|
||||
|
||||
权限说明
|
||||
|
||||
@@ -59,6 +59,11 @@ Fir.im: http://fir.im/seeWeather
|
||||
|
||||
魅族应用中心: http://developer.meizu.com/console/apps/detail/6530883
|
||||
|
||||
v2.1.6
|
||||
- 更新 RxUtil
|
||||
- 优化 网络和缓存逻辑
|
||||
- 更多的封装
|
||||
|
||||
v2.1.3
|
||||
- 修复 城市列表卡顿
|
||||
- 更新 lambda
|
||||
@@ -83,12 +88,6 @@ v2.0
|
||||
- 缓存数据,减少网络请求,保证离线查看
|
||||
- 内置两套图标(设置里更改)
|
||||
|
||||
|
||||
v1.1
|
||||
- 加固
|
||||
- 兼容更多系统版本
|
||||
|
||||
|
||||
v1.0
|
||||
- 就看天气V1.0
|
||||
- @图片和信息来源于网络,侵权删
|
||||
@@ -98,16 +97,17 @@ v1.0
|
||||
|
||||
### TODO
|
||||
这学期有点忙,需要花时间巩固基础,准备面试,但是自己还是会抽空尽快做出这些功能的,谢谢大家理解和支持
|
||||
|
||||
- [ ] 桌面小部件
|
||||
- [x] 通知栏提醒
|
||||
- [x] 更好,更多的天气ICONS
|
||||
- [ ] 管理城市(多城市选择)
|
||||
- [x] \~\~自动定位\~\~
|
||||
- [x] 自动定位
|
||||
- [ ] 自由定制的Item界面
|
||||
|
||||
|
||||
|
||||
----
|
||||
----
|
||||
|
||||
### 项目
|
||||
#### 公开 API
|
||||
@@ -125,66 +125,88 @@ v1.0
|
||||
4. [GLide][5]
|
||||
5. [ASimpleCache][6]
|
||||
|
||||
#### 简单介绍代码
|
||||
#### 代码
|
||||
|
||||
##### 网络
|
||||
就看天气的网络部分的支持是用`RxJava+RxAndroid+Retrofit+Gson`再加上`ACache`缓存
|
||||
|
||||
网络部分:
|
||||
配合 RetrofitSingleton 中封装的方法:
|
||||
```java
|
||||
public Observable<Weather> fetchWeather(String city) {
|
||||
return apiService.mWeatherAPI(city, C.KEY)
|
||||
.filter(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0).status.equals("ok"))
|
||||
.map(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0))
|
||||
.compose(RxUtils.rxSchedulerHelper());
|
||||
}
|
||||
```
|
||||
/**
|
||||
* <p/>
|
||||
* 首先从本地缓存获取数据
|
||||
* if 有
|
||||
* 更新UI
|
||||
* else
|
||||
* 直接进行网络请求,更新UI并保存在本地
|
||||
*/
|
||||
private void fetchData() {
|
||||
observer = new Observer<Weather>() {
|
||||
//节约篇幅,已省略
|
||||
...
|
||||
};
|
||||
|
||||
fetchDataByCache(observer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从本地获取
|
||||
*/
|
||||
private void fetchDataByCache(Observer<Weather> observer) {
|
||||
Weather weather = null;
|
||||
try {
|
||||
weather = (Weather) aCache.getAsObject("WeatherData");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
if (weather != null) {
|
||||
//distinct去重
|
||||
Observable.just(weather).distinct().subscribe(observer);
|
||||
} else {
|
||||
fetchDataByNetWork(observer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从网络获取
|
||||
*/
|
||||
private void fetchDataByNetWork(Observer<Weather> observer) {
|
||||
String cityName = mSetting.getString(Setting.CITY_NAME, "重庆");
|
||||
RetrofitSingleton.getApiService(this)
|
||||
.mWeatherAPI(cityName, key)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
////节约篇幅,已省略
|
||||
...
|
||||
}
|
||||
|
||||
RxUtils 工具类中封装了线程调度:
|
||||
|
||||
```java
|
||||
public static <T> Observable.Transformer<T, T> rxSchedulerHelper() {
|
||||
return tObservable -> tObservable.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
```
|
||||
##### RecycerVIew展示
|
||||
|
||||
感受下实际操作
|
||||
|
||||
```java
|
||||
private Observable<Weather> fetchDataByNetWork() {
|
||||
String cityName = Util.replaceCity(mSetting.getCityName());
|
||||
return RetrofitSingleton.getInstance()
|
||||
.fetchWeather(cityName);
|
||||
}
|
||||
```
|
||||
因为和风天气 API 有些城市/省份的末尾的特殊符号需要过滤掉,比如 `省|市|自治区|特别行政区|地区|盟`,所以在我的方法类中写了一个安全的替换方法。
|
||||
|
||||
缓存部分:
|
||||
```java
|
||||
private Observable<Weather> fetchDataByCache() {
|
||||
return Observable.defer(() -> {
|
||||
Weather weather = (Weather) aCache.getAsObject(C.WEATHER_CACHE);
|
||||
return Observable.just(weather);
|
||||
}
|
||||
).compose(RxUtils.rxSchedulerHelper());
|
||||
}
|
||||
```
|
||||
|
||||
使用 concat 连接:
|
||||
优先网络数据
|
||||
|
||||
```java
|
||||
private void load() {
|
||||
Observable.concat(fetchDataByNetWork(), fetchDataByCache())
|
||||
.first(weather -> weather != null)
|
||||
.doOnError(throwable -> {
|
||||
mErroImageView.setVisibility(View.VISIBLE);
|
||||
mRecyclerView.setVisibility(View.GONE);
|
||||
Snackbar.make(fab, "网络不好,~( ´•︵•` )~", Snackbar.LENGTH_INDEFINITE).setAction("重试", v -> {
|
||||
load();
|
||||
}).show();
|
||||
})
|
||||
.doOnNext(weather -> {
|
||||
mErroImageView.setVisibility(View.GONE);
|
||||
mRecyclerView.setVisibility(View.VISIBLE);
|
||||
})
|
||||
.doOnTerminate(() -> {
|
||||
mRefreshLayout.setRefreshing(false);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
})
|
||||
.subscribe(observer);
|
||||
}
|
||||
```
|
||||
|
||||
##### RecyclerView 展示
|
||||
|
||||
就像洪洋说的一样
|
||||
|
||||
> 整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
|
||||
|
||||
该项目中用到RecyclerView中级的用法是根据itemType展示不同的布局,这就是主页核心的代码了。
|
||||
该项目中用到 RecyclerView 中的用法是根据 itemType 展示不同的布局,这就是主页 UI 核心的代码了。
|
||||
|
||||
```
|
||||
@Override public int getItemViewType(int position) {
|
||||
if (position == TYPE_ONE) {
|
||||
@@ -203,18 +225,16 @@ v1.0
|
||||
}
|
||||
|
||||
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
|
||||
if (holder instanceof NowWeatherViewHolder) {
|
||||
//更新布局
|
||||
....
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
----
|
||||
----
|
||||
|
||||
|
||||
### 截图
|
||||
@@ -236,24 +256,24 @@ v1.0
|
||||
特别感谢**简书猿圈**
|
||||
|
||||
### 关于作者
|
||||
|
||||
|
||||
![][image-4]
|
||||
|
||||
|
||||
简书:http://www.jianshu.com/users/3372b4a3b9e5/latest\_articles
|
||||
|
||||
|
||||
知乎:https://www.zhihu.com/people/xcc3641.github.io
|
||||
|
||||
|
||||
微博:http://weibo.com/xcc3641
|
||||
|
||||
|
||||
个人博客: http://IMXIE.CC
|
||||
|
||||
|
||||
### 请我喝杯咖啡
|
||||
|
||||
----
|
||||
----
|
||||
|
||||
![][image-5]
|
||||
----
|
||||
----
|
||||
|
||||
### LICENSE
|
||||
|
||||
@@ -289,4 +309,4 @@ Unless required by applicable law or agreed to in writing, software distributed
|
||||
[image-2]: http://xcc3641.qiniudn.com/app-%E5%B0%B1%E7%9C%8B%E5%A4%A9%E6%B0%94-%E7%99%BD%E5%A4%A9%E6%A8%A1%E5%BC%8F.png
|
||||
[image-3]: http://xcc3641.qiniudn.com/app-%E5%B0%B1%E7%9C%8B%E5%A4%A9%E6%B0%94-%E5%A4%9C%E6%99%9A%E6%A8%A1%E5%BC%8F.png
|
||||
[image-4]: http://xcc3641.qiniudn.com/app-%E5%A4%B4%E5%83%8F-1.jpeg
|
||||
[image-5]: http://xcc3641.qiniudn.com/app-%E6%94%AF%E4%BB%98%E5%AE%9D.jpg
|
||||
[image-5]: http://xcc3641.qiniudn.com/app-%E6%94%AF%E4%BB%98%E5%AE%9D.jpg
|
||||
|
||||
@@ -106,13 +106,17 @@ public class Util {
|
||||
* 安全的 String 返回
|
||||
*
|
||||
* @param prefix 默认字段
|
||||
* @param obj 获得字段
|
||||
* @param obj 拼接字段
|
||||
*/
|
||||
public static String safeText(String prefix, String obj) {
|
||||
if (TextUtils.isEmpty(obj)) return "";
|
||||
return TextUtils.concat(prefix, obj).toString();
|
||||
}
|
||||
|
||||
public static String safeText(String msg) {
|
||||
return safeText(msg, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 天气代码 100 为晴 101-213 500-901 为阴 300-406为雨
|
||||
*
|
||||
@@ -136,7 +140,7 @@ public class Util {
|
||||
* 正则匹配掉错误信息
|
||||
*/
|
||||
public static String replaceCity(String city) {
|
||||
city = city.replaceAll("(?:省|市|自治区|特别行政区|地区|盟)", "");
|
||||
city = safeText(city).replaceAll("(?:省|市|自治区|特别行政区|地区|盟)", "");
|
||||
return city;
|
||||
}
|
||||
}
|
||||
@@ -357,9 +357,9 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||
* 优先网络
|
||||
*/
|
||||
private void load() {
|
||||
Observable.concat(fetchDataByNetWork(), fetchDataByCache()).first(weather -> weather != null)
|
||||
Observable.concat(fetchDataByNetWork(), fetchDataByCache())
|
||||
.first(weather -> weather != null)
|
||||
.doOnError(throwable -> {
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
mErroImageView.setVisibility(View.VISIBLE);
|
||||
mRecyclerView.setVisibility(View.GONE);
|
||||
Snackbar.make(fab, "网络不好,~( ´•︵•` )~", Snackbar.LENGTH_INDEFINITE).setAction("重试", v -> {
|
||||
@@ -367,11 +367,13 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||
}).show();
|
||||
})
|
||||
.doOnNext(weather -> {
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
mErroImageView.setVisibility(View.GONE);
|
||||
mRecyclerView.setVisibility(View.VISIBLE);
|
||||
})
|
||||
.doOnTerminate(() -> mRefreshLayout.setRefreshing(false))
|
||||
.doOnTerminate(() -> {
|
||||
mRefreshLayout.setRefreshing(false);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
})
|
||||
.subscribe(observer);
|
||||
}
|
||||
|
||||
@@ -390,10 +392,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
|
||||
* 从网络获取
|
||||
*/
|
||||
private Observable<Weather> fetchDataByNetWork() {
|
||||
String cityName = mSetting.getCityName();
|
||||
if (cityName != null) {
|
||||
cityName = Util.replaceCity(cityName);
|
||||
}
|
||||
String cityName = Util.replaceCity(mSetting.getCityName());
|
||||
return RetrofitSingleton.getInstance()
|
||||
.fetchWeather(cityName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user