广播机制
- 分类
- 标准广播:完全异步执行的广播,在广播发出后,所有的BroadcastReceiver同时收到
- 有序广播:同步执行的广播,同一时刻之后一个BroadcastReceiver可以收到
- 接收系统广播(手机开机完成会发出一条广播、电量发生变化会发出一条广播等等)
注册BroadcastReceiver
- 代码中注册(动态注册 — 程序启动时才能接收)
- AndroidManifest.xml中注册(静态注册 — 程序)
- 自定义广播
- 发送标准广播
- 接收
自定义广播都是隐式广播,发送标准广播时使用setPackage(packageName)将隐式广播变成一条显式广播,非原则静态注册的BroadcastReceiver无法接收到这条广播
- 发送有序广播
- 接收有序广播
数据持久化
三种方式
- 文件存储
- 存
Context类提供了一个`openFileOutput()`方法,这个方法接收文件名和文件的操作模式两个参数。操作模式有MODE_PRIVATE(若文件存在则覆盖)和MODE_APPEND(文件存在就追加)。所有文件默认存储到/data/data/<package name>/files/下
- 取
Context类提供了一个`openFileInput()`方法,只接收要读取的文件名一个参数,回去默认路径下加载这个文件,并返回一个流对象。
- SharedPreferences存储 — 使用键值对
- 获取SharedPreferences对象
- Context类中的getSharedPreferences()方法
接收两个参数:
- SharedPreferences文件的名称,路径/data/data/<package name>/shared_prefs/目录下
- Activity类中的getPreferences()方法
只接收一个参数:操作模式。默认自动将当前Activity类型作为SharedPreferences文件名
- 存
- 调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象
- 向SharedPreferences.Editor对象中添加数据,使用putInt(), putT()方法。T表示数据类型。
- 调用apply()将添加的数据提交
- 读
getT()
接收两个参数
- SQLite - SQLiteOpenHelper抽象类
onCreate() onUpgrade()
- 创建数据库
下面两种方法均可创建或打开一个数据库,并返回一个可对数据库进行读写操作的对象。数据库文件会存放在/data/data/<package name>/databases/下
- getReadableDatabase(),若数据库不可写入,返回的对象会以只读方式打开数据库
- getWritableDatabase(),若数据库不可写入,则抛异常
- 升级数据库
Notification
- 创建通知渠道 - Android version ≥ 8.0
通知渠道就是每条通知都要属于一个对应的渠道。每个应用程序都可以自由地创建当前应用拥有哪些通知渠道,但是这些通知渠道的控制权是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动或者是否要关闭这个渠道的通知。
- NotificationManager
- NotificationChannel
- 通知的用法
通知的用法还是比较灵活的,既可以在Activity里创建,也可以在BroadcastReceiver里创建,当然还可以在后面我们即将学习的Service里创建。
- 通知可点击
可以把PendingIntent简单地理解为延迟执行的Intent
- setStyle()
调用摄像头和相册
- 摄像头
- 创建储存图片的对象
- 隐式intent调用拍摄
- 在结果回调onActivityResult()中处理图片
class MainActivity : AppCompactActivity() {
lateinit var timeChangeReceiver: TimeChangeReceiver
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val intentFilter = IntentFilter()
intentFilter.addAction("android.intent.action.TIME_TICK") // 想监听什么广播,就加什么action
timeChangeReceiver = TimeChangeReceiver()
registerReceiver(timeChangeReceiver, intentFilter)
}
override fun onDestroy() {
// ...
registerReceiver(timeChangeReceiver)
}
class TimeChangeReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
TODO("...")
}
}
}
// AndroidManifest.xml
<manifest ....>
// 权限声明,安卓规定,如果不声明就会直接崩溃
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">
<application ...>
...
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</>
</>
</>
</>
//
class BootCompleteReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
TODO("...")
}
}
class MainActivity : AppCompactActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
button.setOnClickListener {
val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
intent.setPackage(packageName)
sendBroadcast(intent)
}
}
}
// a中sendBroadcast(intent)改为
sendOrderedBroadcast(intent, null)
// AndroidManifest.xml
...
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</>
...
// Receiver中可以
...
override fun onReceive(context: Context, intent: Intent) {
TODO("...")
abortBroadcast()
}
...
fun save(inputText: String) {
try {
val output = openFileOutput("data", Context.MODE_PRIVATE)
val writer = BufferedWriter(OutputStreamWriter(output))
writer.use { // use保证使用完之后将流关闭,类似python的with
it.write(inputText)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
fun load() {
val content = StringBuilder()
try {
val input = openFileInput("data")
val reader = BufferedReader(InputStreamReader(input))
reader.use {
reader.forEachLine {
content.append(it)
}
}
} catch (e: IOException) {
e.printStackTrace()
}
return content.toString()
}
val editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit()
editor.putString("name", "Tom")
editor.putInt("age", 28)
editor.apply()
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 版本判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 渠道id、渠道名称、重要等级
// 通知的重要等级有IMPORTANCE_HIGH/IMPORTANCE_DEFAULT/IMPORTANCE_LOW/IMPORTANCE_MI几种
val channel = NotificationChannel(channelId, channelName, importance)
mannager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(context, channelId)
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))
.build()
manager.notify(1, notification)
val intent = Intent(this, MainActivity::class.java)
val pi = PendingIntent.getActivity(this, 0, intent, 0)
val notion = // ...
.setContentIntent(pi)
.setAutoCancel(true) // 点击后消失
// ...