总体介绍
一、基础介绍
1、什么是Jetpack Compose
Jetpack Compose 是Google新发布的用于Android开发的UI工具包。用于替换我们目前常用的XML布局文件搭配findById的UI绘制方法。属于是一个很大的变动了。
compose属于声明式语法,附官方介绍:Jetpack Compose 用更少的代码、强大的工具和直观的 Kotlin API 简化并加速了 Android 上的 UI 开发。就是可以直接在activity里,去“绘制”当前页面布局,比XML布局来回findById确实强不少。能省不少模板代码。
值得一提的是,目前华为的arkui也是声明式语法,鸿蒙和安卓这两个操作系统,虽然采用不同的开发语言,不同的开发框架,但是在UI开发上,却提供了一致的方案,说明声明式UI语法,确实是大势所趋。
2、Kotlin
Kotlin就比较被人所知了,早在2017年的Google I/O大会上,就官宣了成为android开发的官方语言。所以现在还不用kotlin开发app,都会显得有点out。
kotlin作为一个基于JVM的语言,天生就对java兼容,就是说一个项目可以用java和kotlin混合编程,在kotlin的类中,可以直接调用java类文件里的方法。
3、项目简介
好嘞,接下来说说练手项目,我计划是获取系统的通知消息,比如微信消息,微博热搜什么的。把各种推送收集起来进行存储,并同时弹出实时弹幕进行展示!大概效果如截图所示:顶部横着漂浮的,就是一条测试弹幕。顶部是两个权限设置入口。下面是一个可滑动列表,用于展示已接收的历史通知消息。
界面和逻辑全部用compose和kotlin编写,看起来还行吧!
下面我逐步对项目进行说明,项目中对于kotlin和Compose的语法,我会挑一些比较陌生的进行讲解,代码边写边理解。
开干!
二、 大概思路
要完成这个APP,最核心的部分是一定要获取到系统通知。这块比较好说,继承NotificationListenerService类,就可以监听到系统的所有消息通知。接下来就是分几步了。
1、监听到消息后,解析其中我们需要的内容,进行保存。
2、把拿到的消息内容,渲染到APP界面上的列表中。
3、绘制一个展示弹幕的View,由于我们是需要在手机任意界面都可以看到实时消息弹幕,所以这个View就不能放在Activity里。这个View得做成悬浮窗的效果,得通过WindowManager来设置。
三、 项目基础配置
compose涉及的依赖比较多,如果人为配置还是很让人头疼。但是目前Android Studio支持一键创建compose+kotlin项目,所以如果是新建项目,到没有什么特别关注和难的地方。
补充几个项目里我额外用的依赖,部分依赖有版本号关联,不对的话会报错的,需要大家需要根据自己项目的配置,填写合适的版本号。
//kotlin
implementation 'androidx.core:core-ktx:1.9.22'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation 'androidx.navigation:navigation-runtime-ktx:2.4.1'
implementation("androidx.navigation:navigation-compose:2.5.3")
//sqlite
implementation 'org.litepal.guolindev:core:3.1.1'
// compose Image Drawable
implementation "com.google.accompanist:accompanist-drawablepainter:0.28.0"
}
四、开始第一步,监听获取系统消息
创建完项目后,可以先别急着写Activity,我们先去吧系统通知获取的部分做了。
系统消息得从NotificationListenerService继承类,然后去实现onNotificationPosted方法,就可以拿到消息了。所以我们得创建一个Service,继承NotificationListenerService类。
具体逻辑可以看注释
class MyNotificationService : NotificationListenerService() {
private val TAG = "MyNotificationService"
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i(TAG, "Service is started" + "-----")
return super.onStartCommand(intent, flags, startId)
}
//重写消息监听的方法
override fun onNotificationPosted(sbn: StatusBarNotification?) {
//super.onNotificationPosted(sbn)
try {
//有些通知不能解析出TEXT内容,这里做个信息能判断
if (sbn!!.notification.tickerText != null) {
//转成自定义的Notifications对象
val notice = toNotice(sbn)
//协程
GlobalScope.launch(Dispatchers.IO) {
//数据库存储
saveNotice(notice)
}
}
} catch (e: Exception) {
Log.e(TAG, "保存失败:$e")
}
}
private fun toNotice(sbn: StatusBarNotification): Notifications {
val extras = sbn.notification.extras
// 获取接收消息的抬头
val notificationTitle = extras.getString(Notification.EXTRA_TITLE)
// 获取接收消息的内容
val notificationText = extras.getString(Notification.EXTRA_TEXT)
Log.e(TAG, "ticker" + sbn.notification.tickerText)
Log.e(TAG, "$notificationTitle $notificationText")
val simpleDateFormat = SimpleDateFormat("yyyyMMdd-HH:mm:ss")
val date = Date(sbn.notification.`when`)
val n = Notifications() \\Notifications类为自定义的消息Bean类
val time = simpleDateFormat.format(date)
n.time = time
n.visibility = sbn.notification.visibility.toString()
n.title