就看天气V2.0-RxAndroid+Retrofit+Glid

作者: 谢三弟 | 来源:发表于2016-02-21 18:43 被阅读4803次

就看天气

就看天气该应用就是如同它的名字一样,只做一个单纯、简单的看天气软件。这么多天气软件,你选择了我,这是我的幸运。

从15年10月上线,到目前经历两次重大改版,一次代码的重构,一次界面的大幅度改动,目的都是为了你们。 在开源的过程中,收到了很多来自有趣的你们的邮件。

我也曾遇到过棘手的问题无处咨询又谷歌不到。那个时候的我,也可能是现在的你。所以我希望能够帮助到你。


简介

就看天气——是一款遵循Material Design风格的只看天气的APP。无流氓权限,无自启,xxx,用最少的权限做最优的体验。

  • 卡片展现(当前天气情况,未来几小时天气情况,生活建议,一周七天概况)
  • 缓存数据,减少网络请求,保证离线查看
  • 内置两套图标(设置里更改)
  • 彩蛋(自动夜间状态)
  • 定位服务

权限说明

    <!--用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <!--用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!--获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <!--用于访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--用于读取手机当前的状态-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <!--写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

版本更新&&下载地址

Fir.im: http://fir.im/seeWeather

酷安市场:http://www.coolapk.com/apk/com.xiecc.seeWeather

豌豆荚:http://www.wandoujia.com/apps/com.xiecc.seeWeather

魅族应用中心: http://developer.meizu.com/console/apps/detail/6530883

v2.2

  • 新增 多城市管理
  • 新增 Bug反馈和意见
  • 改版 首页UI 更丰富
  • 美化 关于页面
  • 美化 部分图标

v2.1.6

  • 更新 RxUtil
  • 优化 网络和缓存逻辑
  • 更多的封装

v2.1.3

  • 修复 城市列表卡顿
  • 更新 lambda
  • 新增 bugly
  • 修复 高德地图未注销监听器导致的内存泄露

v2.1

  • 修复 定位逻辑
  • 优化 SP的统一化
  • 优化 Error界面
  • 更新 新的天气 ICON
  • 更新 通知栏提醒(后台可能需要白名单,不然无法自动更新)
  • 设置 自动更新频率(0 为不自动更新)

v2.0

  • 重构代码,全新UI,升级体验
  • 就看天气——是一款遵循Material Design风格的只看天气的APP。无流氓权限,无自启,xxx,用最少的权限做最优的体验。
  • 卡片展现(当前天气情况,未来几小时天气情况,生活建议,一周七天概况)
  • 彩蛋(自动夜间状态)
  • 补全城市(第一版本因为自己偷懒所以城市有缺陷对不起各位)
  • 缓存数据,减少网络请求,保证离线查看
  • 内置两套图标(设置里更改)

TODO

  • [ ] 桌面小部件
  • [x] 通知栏提醒
  • [x] 更好,更多的天气ICONS
  • [x] 管理城市(多城市选择)
  • [x] 自动定位
  • [ ] 自由定制的Item界面
  • [ ] 引导页面

项目

公开 API

天气数据来源于:和风天气

城市信息来源于:CSDN

地理定位服务: 高德地图

开源技术

  1. Rxjava
  2. RxAndroid
  3. Retrofit
  4. GLide
  5. ASimpleCache

代码

网络

Update 7.11:

因为天气软件请求比较单一,没必要用其他的缓存,可以直接用 okhttp 缓存。

File cacheFile = new File(BaseApplication.getmAppContext().getExternalCacheDir(), "SeeWeatherCache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = chain -> {
    Request request = chain.request();
    if (!Util.isNetworkConnected(BaseApplication.getmAppContext())) {
        request = request.newBuilder()
            .cacheControl(CacheControl.FORCE_CACHE)
            .build();
    }
    Response response = chain.proceed(request);
    if (Util.isNetworkConnected(BaseApplication.getmAppContext())) {
        int maxAge = 0;
        // 有网络时 设置缓存超时时间0个小时
        response.newBuilder()
            .header("Cache-Control", "public, max-age=" + maxAge)
            .build();
    } else {
        // 无网络时,设置超时为4周
        int maxStale = 60 * 60 * 24 * 28;
        response.newBuilder()
            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
            .build();
    }
    return response;
};
builder.cache(cache).addInterceptor(cacheInterceptor);

设置好缓存地址,设置好 header 即可实现缓存。


网络部分:
配合 RetrofitSingleton 中封装的方法:

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());
}

RxUtils 工具类中封装了线程调度:

public static <T> Observable.Transformer<T, T> rxSchedulerHelper() {
        return tObservable -> tObservable.subscribeOn(Schedulers.io())
                .unsubscribeOn(AndroidSchedulers.mainThread())
                .observeOn(AndroidSchedulers.mainThread());
}

感受下实际操作

    private Observable<Weather> fetchDataByNetWork() {
        String cityName = Util.replaceCity(mSharedPreferenceUtils.getCityName());
        return RetrofitSingleton.getInstance()
            .fetchWeather(cityName)
            .onErrorReturn(throwable -> {
                PLog.e(throwable.getMessage());
                return null;
            });
    }

一定要写 onErrorRrturn ,不然是不会执行到缓存的流。

因为和风天气 API 有些城市/省份的末尾的特殊符号需要过滤掉,比如 省|市|自治区|特别行政区|地区|盟,所以在我的方法类中写了一个安全的替换方法。

缓存部分:

private Observable<Weather> fetchDataByCache() {
        return Observable.defer(() -> {
                        Weather weather = (Weather) aCache.getAsObject(C.WEATHER_CACHE);
                        return Observable.just(weather);
                }
        ).compose(RxUtils.rxSchedulerHelper());
}

使用 concat 连接:
优先网络数据

private void load() {
        Observable.concat(fetchDataByNetWork(), fetchDataByCache())
            .first(weather -> weather != null)
            .doOnError(throwable -> {
                mErroImageView.setVisibility(View.VISIBLE);
                mRecyclerView.setVisibility(View.GONE);
            })
            .doOnNext(weather -> {
                mErroImageView.setVisibility(View.GONE);
                mRecyclerView.setVisibility(View.VISIBLE);
            })
            .doOnTerminate(() -> {
                mRefreshLayout.setRefreshing(false);
                mProgressBar.setVisibility(View.GONE);
            })
            .subscribe(observer);
    }
RxBus

具体的逻辑分析在这里RxBus 的简单实现

感谢 Brucezz

RecyclerView 展示

就像洪洋说的一样

整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。

该项目中用到 RecyclerView 中的用法是根据 itemType 展示不同的布局,这就是主页 UI 核心的代码了。

@Override public int getItemViewType(int position) {
        if (position == TYPE_ONE) {
        //标识
            ...
        }
        return super.getItemViewType(position);
    }

@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_ONE) {
        //绑定
            ...
            }
        }
   }

@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //更新布局
        ....

}


截图


感谢

感谢开源,学习到了前辈们优秀的代码

特别感谢简书猿圈

关于作者

简书:http://www.jianshu.com/users/3372b4a3b9e5/latest_articles

知乎:https://www.zhihu.com/people/xcc3641.github.io

微博:http://weibo.com/xcc3641

个人博客: http://IMXIE.CC

LICENSE

Copyright 2016 HugoXie Licensed under the Apache License, Version 2.0 (the "License")

you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

图片来源于网络,版权属于原作者。

相关文章

  • 就看天气V2.0-RxAndroid+Retrofit+Glid

    就看天气 就看天气该应用就是如同它的名字一样,只做一个单纯、简单的看天气软件。这么多天气软件,你选择了我,这是我的...

  • Android I天气

    I天气 爱天气界面借鉴于就看天气,在此感谢开源项目就看天气。该应用为开源应用,禁止用于任何商业用途。 感谢您的使用...

  • 李鑫诚——亲子日记第71篇

    2018.5.14日,星期一,天气晴热 天气真的是热了,今天中午的温度达到了31度,儿子放学后,我就看到儿子脸上,...

  • 李鑫诚——亲子日记第73篇

    2018.5.16日,星期三,天气雷阵雨(暴雨) 今天早上刚起来就看见,天气阴的很厉害,洗漱完了,去给孩子们做早饭...

  • 看就看

    看客,眼观六路耳听八方?最近我比较喜欢的李诞陷入出轨风波之中,一时众说纷纭,随性变成贬义,是非品端尽收眼底,我眼中...

  • 将就看

    玲珑锁

  • 想看就看

    默然间发现自已生活一个默生抵触世界

  • 有病就看

    昨晚又是半夜醒来,然后再也睡不着。这种状况持续了好久了。看来得再找个赶紧找个中医大夫帮看看了。 命...

  • 就看自己

    把关注点放到自己身上。 我不能改变任何人的想法,有时候我都不能改变自己的习惯,行为举止,凭什么就认为别人会听自己的...

  • 想看就看

    前段时间看记录片《还好有书籍》一集中提到在地铁上阅读的人们,我有点挺感动的。原来在外面的世界,还有这么多的爱书人,...

网友评论

  • 96ed773edb8b:rxjava引起的内存泄漏在这个项目中是如何解决的呢
  • 啊啊啊啊啊啊啊啊啊i:请问这里面用了哪些框架,用到算法了吗
  • ImTudou:如何注释写的好点就好了
    ImTudou:@谢三弟 只是感觉注释有点少:smiley:
    谢三弟:@ImTudou = = 你哪里不明白呀
  • yunhen: 网络缓存是个什么意思呢 :disappointed_relieved:
    谢三弟:@yunhen : 我的锅、用词不当
  • 程序员小熊猫:楼主 api接口的url地址中的参数是cityID,而代码中发送请求的参数是cityName。
    谢三弟:@谢瓜 city 城市名称、支持中英文,不区分大小写和空格,城市和国家之间用英文逗号分割
    程序员小熊猫: @谢三弟 https://api.heweather.com/x3/weather?cityid=城市ID&key
    这个url是城市ID呀。
    谢三弟:@谢瓜 仔细看下是支持的 cityName
  • 御风无忧:疑惑求解:关于rxbus多页面传递,Activity_a发起事件,Acitivity_b订阅处理。 但是从b跳转到a发起事件后,b页面已经onDestroy()了,b完全是没有处理时间的啊。即使从a跳回b,订阅者也是重新订阅一遍,也不会执行之前的onNext()啊!!!
    addSubscription(
    RxBus.getDefault().toObserverable(ChangeCityEvent.class).observeOn(AndroidSchedulers.mainThread()).subscribe(
    changeCityEvent -> {
    mRefreshLayout.setRefreshing(true);
    load();
    }, throwable -> {
    PLog.e(throwable.getMessage())
    ;
    }));
    }
  • 然小七:表示和风天气返回的json数据不是正常的json格式,"HeWeather data service 3.0": 有空格和.
    表示gson没法解析,楼主没说明~~~
    谢三弟:@然小七 可以使用注解
    程序员小熊猫:@然小七 调用deleteCharAt()和delete()方法删了就行
  • 船长酱:我来从头到尾好好研究下,很喜欢这个应用。
    谢三弟: @Captain船长 谢谢喜欢啊~有什么不足随便提哈
  • RicoX2016:感谢分享,学习学习
  • 113aa3aaae7e:有空代码down下来学习学习, 感谢分享
  • 键盘男:建议把acache换成sql
    谢三弟:@苦逼键盘男kkmike999 没用过第三方,下次实践下。但是我感觉这个缓存挺好的
    键盘男:@谢三哥 用第三方框架呀,肯定不是自己写啦
    谢三弟:@苦逼键盘男kkmike999 写SQL真的太烦了
  • wingjay:非常赞!
  • Yousuf_:厉害
    谢三弟:@时空穿越者 谢谢谢谢
  • 36a453c057aa:很不错哦,学习一下
    谢三弟:@我是启昌 谢谢谢谢

本文标题:就看天气V2.0-RxAndroid+Retrofit+Glid

本文链接:https://www.haomeiwen.com/subject/ypzvkttx.html