PendingIntent翻译成中文为“待定意图”,这个翻译很好地表示了它的涵义。PendingIntent描述了封装Intent意图以及该意图要执行的目标操作。PendingIntent封装Intent的目标行为的执行是必须满足一定条件,只有条件满足,才会触发意图的目标操作。
一.获取PendingIntent对象
获取PendingIntent对象有以下几种方式:
- PendingIntent.getActivity(Context, int, Intent, int):启动活动
- PendingIntent.getActivities(Context, int, Intent[], int):启动多个活动,意图中为数组
- PendingIntent.getBroadcast(Context, int, Intent, int):启动广播
- PendingIntent.getService(Context, int, Intent, int):启动服务
参数说明:
- Context:context上下文,PendingIntent启动活动的上下文
- int:requestCode请求码 ,发送者发送的请求码
- Intent:intent意图:要加载活动的意图
- int:flags 标记
对于其中的标记可以定义为下列形式
- FLAG_ONE_SHOT:PendingIntent对象仅使用一次;
- FLAG_NO_CREATE:如果PendingIntent对象不存在则返回null
- FLAG_CANCEL_CURRENT:如果PendingIntent对象已存在,则取消原有的对象,创建新的PendingIntent对象
- FLAG_UPDATE_CURRENT:如果PendingIntent对象已存在,则保留原有的对象,修改原有对象的属性数据
- FLAG_IMMUTABLE:PendingIntent对象是不可变的
- FLAG_MUTABLE:PendingIntent对象是可变的
- 另外其他Intent中支持的标记都可以在标记参数中使用。
二、应用实例
例如:在MainActivity启动前台服务播放音乐,利用前台服务的通知提供的内容跳转到其他活动例如SongActivity介绍歌曲。界面如下所示。
点击第一张图的播放,会播放音频,同时发布通知如第二张图所示。在第二张图的红色箭头区域点击,可以屏幕会跳转到第三张图。在第三张图中点击“返回”,则返回主活动。
1. AndroidManifest.xml清单配置权限
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
2. 定义MusicService
class MusicService : Service() {
lateinit var mediaPlayer: MediaPlayer
override fun onCreate() {
super.onCreate()
mediaPlayer = MediaPlayer.create(this,R.raw.song3)
}
override fun onBind(intent: Intent): IBinder? {
postNotification()
playMusic()
return null
}
override fun onUnbind(intent: Intent?): Boolean {
stopMusic()
return super.onUnbind(intent)
}
/**
* 播放音乐
*/
private fun playMusic(){
mediaPlayer.setOnPreparedListener {
mediaPlayer.start()
}
mediaPlayer.setOnCompletionListener {
mediaPlayer.release()
}
}
/**
* 停止播放
*/
private fun stopMusic(){
if(mediaPlayer.isPlaying){
mediaPlayer.stop()
mediaPlayer.release()
}
}
/**
* 创建通知渠道
* @param id String
* @param name String
*/
private fun createNotificationChannel(id:String,name:String){
//创建通知管理器
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//定义通知渠道
val channel = NotificationChannel(id,name,NotificationManager.IMPORTANCE_DEFAULT)
//创建通知渠道
notificationManager.createNotificationChannel(channel)
}
/**
* 发布通知
*/
private fun postNotification(){
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
createNotificationChannel("music_service","歌曲")
}
//定义启动服务的意图
val intent = Intent(this,SongActivity::class.java)
//定义跳转SongActivity的PendingIntent
val descPendingIntent = getSongPendingIntent()
//定义启动控制音乐播放广播接受器的PendingIntent
val playPendingIntent = getPlayPendingIntent()
//定义启动控制音乐停止播放广播接受器的PendingIntent
val stopPendingIntent = getStopPendingIntent()
//定义动作
val playAction = NotificationCompat.Action(android.R.drawable.ic_media_play,"播放",playPendingIntent)
val stopAction = NotificationCompat.Action(android.R.drawable.ic_media_pause,"停止",stopPendingIntent)
//创建通知
val notification = NotificationCompat.Builder(this,"music_service").apply{
setOngoing(true)
setOnlyAlertOnce(true)
setContentTitle("播放音乐")
setContentText("正在播放歌曲...")
setSmallIcon(R.mipmap.ic_launcher)
setColorized(true)
color = resources.getColor(R.color.teal_200,null)
setContentIntent(descPendingIntent)
// addAction(android.R.drawable.ic_media_play,"播放",playPendingIntent) //android23开始不支持
// addAction(android.R.drawable.ic_media_pause,"停止",stopPendingIntent)//android23开始不支持
addAction(playAction)
addAction(stopAction)
}.build()
startForeground(1,notification)
}
/**
* 跳转到歌曲介绍的界面
* @return PendingIntent
*/
private fun getSongPendingIntent():PendingIntent{
//定义启动服务的意图
val intent = Intent(this,SongActivity::class.java)
//定义PendingIntent
return PendingIntent.getActivity(this,1,
intent,PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
}
private fun getPlayPendingIntent(): PendingIntent {
//创建意图过滤器
val intentFilter = IntentFilter()
//增加动作
intentFilter.addAction("PLAY_ACTION")
//创建音乐播放广播接受器
val playReceiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
playMusic()
}
}
//注册播放音乐广播器
registerReceiver(playReceiver,intentFilter)
//创建播放意图
val intent = Intent("PLAY_ACTION")
return PendingIntent.getBroadcast(this,
2,intent,PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getStopPendingIntent():PendingIntent{
//创建意图过滤器
val intentFilter = IntentFilter()
//增加动作
intentFilter.addAction("STOP_ACTION")
//创建停止播放广播接受器
val stopReceiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
stopMusic()
}
}
//注册广播接收器
registerReceiver(stopReceiver,intentFilter)
//创建意图
val intent = Intent("STOP_ACTION")
return PendingIntent.getBroadcast(this,
3,intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
}
}
3.定义主活动MainActivity
class MainActivity : ComponentActivity() {
lateinit var intent1:Intent
val conn = object:ServiceConnection{
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
playMusic()
}
override fun onServiceDisconnected(name: ComponentName?) {
stopMusic()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent1 = Intent(this,MusicService::class.java)
requestNotificationPermission()
setContent {
Lab03Theme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MainScreen(playAction=::playMusic,stopAction=::stopMusic)
}
}
}
}
/**
* 请求通知权限
*/
private fun requestNotificationPermission(){
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.TIRAMISU) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
0
)
}
}
/**
* 绑定播放音频的服务
*/
private fun playMusic(){
bindService(intent1,conn, Context.BIND_AUTO_CREATE)
}
/**
* 解除绑定
*/
private fun stopMusic(){
unbindService(conn)
}
}
@Composable
fun MainScreen(playAction:()->Unit,stopAction:()->Unit) {
Column(horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center){
Row{
TextButton(onClick = {
playAction.invoke()
}){
Row{
Icon(imageVector = Icons.Filled.PlayArrow,contentDescription = "play")
Text("播放")
}
}
TextButton(onClick = {
stopAction.invoke()
}){
Row{
Icon(imageVector = Icons.Filled.Stop,contentDescription = "play")
Text("停止")
}
}
}
}
}
4.定义显示歌曲介绍的SongActivity
class SongActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent{
Column{
Text("正在播放歌曲,歌曲介绍内容描述暂时没有定义")
TextButton(onClick = {
//结束当前活动
finish()
}){
Text("返回")
}
}
}
}
}
参考文献
1.PendingIntent
https://developer.android.google.cn/reference/android/app/PendingIntent