Coder Social home page Coder Social logo

coolweatherjetpack's Introduction

酷欧天气Jetpack版

酷欧天气的Jetpack版本实现,采用了MVVM架构。

这里我先给出一张酷欧天气Jetpack版的架构设计图,这张图是模仿Google Codelabs的Sunshine项目画出来的。拥有良好架构设计的项目都是可以用简洁清晰的架构图表示出来的,而一个杂乱无章没有架构设计的项目则很难用架构图表示出来。

上述架构图可能一开始看你会找不着重点,其实这张架构图非常清晰,我来带大家解读一下。

首先我们通过这张架构图成功将程序分为了若干层。

绿色部分表示的是UI控制层,这部分就是我们平时写的Activity和Fragment。

蓝色部分表示的是ViewModel层,ViewModel用于持有和UI元素相关的数据,以保证这些数据在屏幕旋转时不会丢失,以及负责和仓库之间进行通讯。

黄色部分表示的是仓库层,仓库层要做的工作是自主判断接口请求的数据应该是从数据库中读取还是从网络中获取,并将数据返回给调用方。如果是从网络中获取的话还要将这些数据存入到数据库当中,以避免下次重复从网络中获取。简而言之,仓库的工作就是在本地和网络数据之间做一个分配和调度的工作,调用方不管你的数据是从何而来的,我只是要从你仓库这里获取数据而已,而仓库则要自主分配如何更好更快地将数据提供给调用方。

接下来灰色部分表示是的本地数据层,实现方式并不固定,我使用了LitePal来进行数据持久化处理,你也可以使用别的框架。

最后红色部分表示的是网络数据层,这里使用了Retrofit从web服务接口获取数据。

借助这张架构图,我想会在很大程度上便于大家理解酷欧天气Jetpack版这个开源项目,而如果你自己编写的项目也能尝试画出这样一张架构图,那么你的代码结构一定是非常不错的。

另外对于这张架构图我还有必要再解释一下,图中所有的箭头都是单向的,比方说WeatherActivity指向了WeatherViewModel,表示WeatherActivity持有WeatherViewModel的引用,但是反过来WeatherViewModel不能持有WeatherActivity的引用。其他的几层也是一样的道理,一个箭头就表示持有一个引用。

还有,引用不能跨层持有,就比方说UI控制层不能持有仓库层的引用,每一层的组件都只能和它的相邻层交互。

大概就介绍这么多吧,剩下的就靠大家自己去阅读源码进行学习了。

项目运行截图如下:

            

最后,希望这个项目能够帮助大家更好地学习Jetpack,更好地学习MVVM架构。

学习更多的Android技术知识,请关注我的微信公众号:

coolweatherjetpack's People

Contributors

guolindev avatar sinyu890807 avatar zcc1234567 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

coolweatherjetpack's Issues

请求天气数据出错

抓包看返回的数据: Request weather info with error: undefined method `[]' for nil:NilClass

勘误,文字拼写错误

郭婶~发现2处书写错误,不知道能不能看到?
1、架构图上的WeatherNetworkSourse中的Sourse书写错误 应为 Source;
2、架构图下第6段“表示是的” 应为 表示的是。

网络提示问题

郭神你好!,这个架构,如果统一封装处理网络loading呢,看了半天不知道加在哪里.

com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Request weather info with error: undefined method `city' for nil:NilClass
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: <-- END HTTP (73-byte body)
03-18 16:06:32.653 22906-22906/com.landleaf.mvvm D/MainActivity: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

一毛一样的接口用retrofit自带Gson解析报错,用okhttp请求到数据再gson解析解析到了,百度到的一堆全都是说json不规范的,各种抓狂见鬼

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://guolin.tech/")
            .client(okHttpClient.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    WeatherService weatherService = retrofit.create(WeatherService.class);
    retrofit2.Call<HeWeather> call1 = weatherService.getWeather("CN101010100", "79a79674ca6149c0a6a0900eadf99576");
    call1.enqueue(new retrofit2.Callback<HeWeather>() {
        @Override
        public void onResponse(retrofit2.Call<HeWeather> call, retrofit2.Response<HeWeather> response) {
            Log.d("MainActivity", "response.body():" + response.body());
        }

        @Override
        public void onFailure(retrofit2.Call<HeWeather> call, Throwable t) {
            Log.d("MainActivity", t.toString());
        }
    });

    Request build = new Request.Builder().url("http://guolin.tech/api/weather?cityid=CN101010100&key=79a79674ca6149c0a6a0900eadf99576").build();
    Call call = okHttpClient.build().newCall(build);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d("MainActivity", e.toString());
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            String string = response.body().string();
            Gson gson = new Gson();

            HeWeather heWeather = gson.fromJson(string, HeWeather.class);
            Log.d("MainActivity", "heWeather:" + heWeather);
        }
    });

03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: <-- 200 OK http://guolin.tech/api/weather?cityId=CN101010100&key=79a79674ca6149c0a6a0900eadf99576 (341ms)
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Content-Type: text/plain; charset=utf-8
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Transfer-Encoding: chunked
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Connection: keep-alive
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Status: 200 OK
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Cache-Control: max-age=0, private, must-revalidate
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: ETag: W/"6a54780a43f5555f36d3bafb6a9f47f6"
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-Frame-Options: SAMEORIGIN
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-XSS-Protection: 1; mode=block
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-Content-Type-Options: nosniff
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-Runtime: 0.216947
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-Request-Id: ade9fb48-3cd6-40e0-9990-20da17e5ff07
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Date: Mon, 18 Mar 2019 08:06:28 GMT
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: X-Powered-By: Phusion Passenger 5.3.3
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Server: nginx/1.14.0 + Phusion Passenger 5.3.3
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: Request weather info with error: undefined method `city' for nil:NilClass
03-18 16:06:32.653 22906-22920/com.landleaf.mvvm D/OkHttp: <-- END HTTP (73-byte body)
03-18 16:06:32.653 22906-22906/com.landleaf.mvvm D/MainActivity: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: <-- 200 OK http://guolin.tech/api/weather?cityid=CN101010100&key=79a79674ca6149c0a6a0900eadf99576 (557ms)
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Content-Type: text/plain; charset=utf-8
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Transfer-Encoding: chunked
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Connection: keep-alive
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Status: 200 OK
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Cache-Control: max-age=0, private, must-revalidate
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: ETag: W/"8932eefeb8627ff8f8d4e75ab3c0cfbd"
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-Frame-Options: SAMEORIGIN
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-XSS-Protection: 1; mode=block
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-Content-Type-Options: nosniff
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-Runtime: 0.427339
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-Request-Id: ddfd2018-ee68-44ee-b9c5-dc2eecfccd1f
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Date: Mon, 18 Mar 2019 08:06:28 GMT
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: X-Powered-By: Phusion Passenger 5.3.3
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: Server: nginx/1.14.0 + Phusion Passenger 5.3.3
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: {"HeWeather": [{"basic":{"cid":"CN101010100","location":"北京","parent_city":"北京","admin_area":"北京","cnty":"**","lat":"39.90498734","lon":"116.4052887","tz":"+8.00","city":"北京","id":"CN101010100","update":{"loc":"2019-03-18 15:55","utc":"2019-03-18 07:55"}},"update":{"loc":"2019-03-18 15:55","utc":"2019-03-18 07:55"},"status":"ok","now":{"cloud":"0","cond_code":"101","cond_txt":"多云","fl":"19","hum":"25","pcpn":"0.0","pres":"1007","tmp":"21","vis":"8","wind_deg":"186","wind_dir":"南风","wind_sc":"2","wind_spd":"6","cond":{"code":"101","txt":"多云"}},"daily_forecast":[{"date":"2019-03-18","cond":{"txt_d":"多云"},"tmp":{"max":"21","min":"6"}},{"date":"2019-03-19","cond":{"txt_d":"多云"},"tmp":{"max":"24","min":"11"}},{"date":"2019-03-20","cond":{"txt_d":"小雨"},"tmp":{"max":"16","min":"6"}}],"aqi":{"city":{"aqi":"148","pm25":"113","qlty":"轻度污染"}},"suggestion":{"comf":{"type":"comf","brf":"舒适","txt":"白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。"},"sport":{"type":"sport","brf":"适宜","txt":"天气较好,赶快投身大自然参与户外运动,尽情感受运动的快乐吧。"},"cw":{"type":"cw","brf":"较适宜","txt":"较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。"}}}]}
03-18 16:06:32.873 22906-22921/com.landleaf.mvvm D/OkHttp: <-- END HTTP (1364-byte body)
03-18 16:06:32.883 22906-22921/com.landleaf.mvvm D/MainActivity: heWeather:HeWeather{list=[Weather{status='ok', basic=Basic{cityName='北京', weatherId='CN101010100', update=Update{updateTime='2019-03-18 15:55'}}, aqi=AQI{city=AQICity{aqi='148', pm25='113'}}, now=Now{temperature='21', more=More{info='多云'}}, suggestion=Suggestion{comfort=Comfort{info='白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。'}, carWash=CarWash{info='较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。'}, sport=Sport{info='天气较好,赶快投身大自然参与户外运动,尽情感受运动的快乐吧。'}}, forecastList=[Forecast{date='2019-03-18', temperature=Temperature{max='21', min='6'}, more=More{info='多云'}}, Forecast{date='2019-03-19', temperature=Temperature{max='24', min='11'}, more=More{info='多云'}}, Forecast{date='2019-03-20', temperature=Temperature{max='16', min='6'}, more=More{info='小雨'}}]}]}

是否少提交了databinding目录中的资源

我在导入了项目后这几个类报红, 经查找没有找到databinding目录 ;
而在gradle中的依赖文件中也没有看到类似包名的依赖 ;
com.coolweather.coolweatherjetpack.databinding.ForecastItemBinding;
com.coolweather.coolweatherjetpack.databinding.SimpleItemBinding;
com.coolweather.coolweatherjetpack.databinding.ChooseAreaBindingImpl;
com.coolweather.coolweatherjetpack.databinding.ChooseAreaBindingImpl;

CoolWeatherNetwork 的疑问

`
private suspend fun Call.await(): T {
return suspendCoroutine { continuation ->

        enqueue(object : Callback<T> {
            override fun onFailure(call: Call<T>, t: Throwable) {
                continuation.resumeWithException(t)
            }

            override fun onResponse(call: Call<T>, response: Response<T>) {
                val body = response.body()
                if (body != null) continuation.resume(body)
                else continuation.resumeWithException(RuntimeException("response body is null"))
            }
        })


        /* val execute = execute()
        if (execute.isSuccessful){
            val body = execute.body()
            body?.let { continuation.resume(body) }
        }else{
            continuation.resumeWithException(Throwable(execute.message()))
        }*/

    }
}

`
郭神,想请教一下这里为啥使用异步请求. 因为这里是在IO线程执行的. 我尝试了一下把这里改成同步执行也可以. 改成同步执行,唯一的不足之处就是:无法准确的获取onFailure的信息. 所以想请教一下是处于啥方面考虑然后使用异步执行的,

点击事件问题

看到choose_area.xml中backButton点击事件是调用的是ChooseAreaViewModel的onBack()方法..
假如需要在这个方法中进行跳转界面或者销毁界面等UI操作,应该怎么写呢.只能在ViewModel中再写一个livedata改变状态,activity获取引用观察变化操作UI吗.

貌似有bug

每次下拉刷新所有的天气数据都会发生改变,就像换了一个城市一样

请教一下,为什么没有给网络请求,做dispose操作

一般来说,在页面onDestory的时候都会取消当前正在进行的网络请求,但是我没有在这个项目找到这类操作。不取消网络请求的话,不会导致内存泄漏吗,比如页面已经关闭,请求才完成,完成时候调用关闭loading弹框,但是这时候页面已经销毁,就导致了loading弹框leak异常

大佬

有没有,JAVA语言写的啊,kotlin还没学。。。哎

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.