采用Android Studio
+ Kotlin
开发, 具体技术见实现
部分.
代码行数:
其实本来准备写Flutter
跨平台的, 也花费了2天熟悉Dart
语法, 但是发现网上的资料非常少, 这种少不仅仅是在中文资料上, 英文资料也不是很多.(后来在查资料的过程中证明没选择Fultter
是正确的)
于是准备干回老本行 —— Android
应用程序开发.
本次Android
应用程序采用Jetpack Compose
作为UI
框架, 使用Room
访问本地的sqlite
数据库,使用okHttp3
+ Coroutine
完成后台的网络请求, ViewModel
作为App
的状态保存单元, 应用程序的整体设计风格采用Google
2022年12月份推出的Material3 Design
(主要是Material2
的风格有点不适合现代审美).
整体App
风格比较简洁, 分为两个页面, 主页
和我的
:
在首页
用户可以再无线刷新的列表中浏览帖子, 点击某一帖子会进入详情页, 在详情页可以浏览帖子更详细的信息以及收藏评论等:
点击+
按钮发新帖, Bottom Sheet
风格模仿了iOS
系统:
在我的
页面记录了当前登录用户的一些信息, 包括我的帖子、我的收藏, 如果用户想更改头像、昵称和个人签名, 也可以打开编辑信息
菜单进行修改:
也可以进行刷新:
由于使用了Material3 Design
, 本应用程序天然支持Android 12
的Dynamic Color
:
当然, 夜间模式也不在话下:
由于上学期就是用Compose
完成的结课设计, 所以本次UI
做起来不是很难, 相比于上学期, 这次多学习了一些东西, 一是Compose Animation
, 二是如何使用好ViewModel
管理状态.
Compose
函数接收数据来渲染, 当点击Compose
中可互动的内容时(比如点击Button
), 调用对应ViewModel
中的方法(这时Compose
不仅要接受数据作为参数, 还需要引用ViewModel
作为参数), 由ViewModel
负责更改状态, 这个转态改变会通知Compose
, 得以重新渲染出新的内容.
对于ViewModel
的写法, 这里参考了Google
官方给的样例:
客户端采用okHttp
开发, 对于Response
, 这里采用了Gson
进行反序列化:
由于客户端大部分都是样板代码,这里就不展示过多了.
其中的小插曲便是, 有一些用户比较"顽皮", 他们喜欢反复点击收藏或点赞按钮, 这样会造成一个问题: 客户端会反复发送收藏和取消收藏的请求, 不仅浪费性能, 网络状况不好是还会出现渲染延迟.
这里的解决方案是, 如果用户能点击点赞或收藏, 说明, 用户一定在帖子详情界面, 这时尽管用户反复点击, 不会触发客户端的请求发送, 当且仅当用户点击"返回"离开帖子详情界面时, 才会触发收藏或点赞请求.这个方案参考了操作系统如何处理内存写的请求.
应用程序需要记住用户的登录状态, 这就需要将登录状态保存到本地数据库.
这里采用了Room
作为数据存取框架, 整体写起来也比较简单, 都是一些模板代码, 但同样出现了一些插曲.
这里sqlite
显然不知道如何存储UserInfoState
类型, 所以需要Converter
, 但是第一次笔者只加了UserInfoState
-> String
的Converter
(显然是通过Gson
序列化), 但反复编译还是报错. 搜了很久也没搜到解决方案, 于是上官网看Room
的样例, 抱着尝试的心情又在Converter
中添加了String
-> UserInfoState
的方法, 编译运行, 成功!
也就是说, 如果通过Room
插入sqlite
数据库时, 如果实体有自定义类型, 就需要Converter
, 但是这个Converter
必须是双向的 —— 既能转成String
, 又能转回来.
尽管困难重重, 但是看到最终的App
在物理机上跑起来的那一刻, 觉得努力没有白费.
开发过程也让我的英语水平提升了不少, 尤其时面对Material3
时.
当然, 对ViewModel
的理解更是加深了一大步.