Android开发,使用kotlin学习多媒体功能(详细)

2023-12-19

一、通知

1.用到的类和方法

(1) Context类

getSystemService() 接收一个字符串参数用于确定获取系统的哪个服务,这里我们传入Context.NOTIFICATION_SERVICE,获取NotificationManager

(2) NotificationManager类

createNotificationChannel() 创建通知渠道
notify() 让通知显示出来,第一个参数是id,第二个参数是Notification对象

(3) NotificationChannel类

NotificationChannel() 构建通知渠道,第一个参数,渠道ID,第二个参数,渠道名称,第三个参数,通知的重要等级,等级从高到低有IMPORTANCE_HIGH、IMPORTANCE_DEFAULT、IMPORTANCE_LOW、IMPORTANCE_MIN这几种。

(4) NotificationCompat类

NotificationCompat.builder() 创建Notification对象,第一个参数是context,第二个参数是渠道ID。

(5) Notification

setContentTitle() 指定通知的标题内容
setContentText() 指定通知的正文内容
setSmallIcon() 设置通知的小图标
setLargeIcon() 设置通知的大图标
setWhen() 设置创建的时间
setContentIntent() 通过PendingIntent构建一个延迟执行的”意图“,参数为PendingIntent对象
setAutoCancel() 方法传入true,就表示点击这个通知时,通知会自动取消
setStyle() 接收一个NotificationCompat.Style参数,这个参数时用来构建具体的富文本信息的,如长文字、图片等。
.setStyle(NotificationCompat.BigTextStyle().bigText(".........................")

.setStyle(NotificationCompat.BigPictureStyle().bigPicture(BigmapFactory.decodeResource(resources,R.drawable.big_image)))

(6) PendingIntent

getActivity() 获得PendingIntent对象,第一个参数是Context,第二个参数用不到,传入0,第三个参数是一个Intent对象,第四个参数是确定PendingIntent的行为,行为有FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT和FLAG_UPDATE_CURRENT四种可选。

2.创建通知

步骤

(1)创建通知渠道

获取NotificationManager的实例,,由于NotificationManager类和createNotificationChannel()方法都是Android 8.0系统新增的API,因此在使用的时候要进行版本判断,接下来使用NotificationChannel类构建通知渠道,并调用NotificationManager类的createNotificationChannel()方法完成创建。

val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            val channel=NotificationChannel("normal","Normal",NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }

(2)设置通知点击事件,构建Notification对象并显示通知。

val sendNotion:Button=findViewById(R.id.sendNotion)
        sendNotion.setOnClickListener {
            val intent= Intent(this,otherActivity::class.java)
            val pi=PendingIntent.getActivity(this,0,intent,0)
            val notification= NotificationCompat.Builder(this,"normal")
                .setContentTitle("This is content title")
                .setContentText("This is content text")
                .setSmallIcon(R.drawable.small)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.big))
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pi)
                .setAutoCancel(true)
                .build()
            manager.notify(1,notification)
        }

二、调用摄像头和相册

1.用到的方法

Uri.fromFile() 将File对象转换成Uri对象,参数为File对象
FileProvider.getUriForFile() 将File对象转换成一个封装过的Uri对象,第一个参数是    Context   对象,第二个参数是任意唯一的字符串,第三个参数是File对象。
BitmapFactory.decodeStream() 将输入流传入,把图片加载成Bitmap
imageView.setImageBitmap(): 显示图片
File类常用方法
File(pathname:String) 通过路径名创建一个新的File实例
File(parent:File,child:String) 从父抽象路径和子路径名字符串创建新的File实例
File(parent:String,child:String) 从父路径名字符串和子路径名字符串创建新的File实例
exists() 路径是否存在
delete() 删除文件或者路径
createNewFile() 创建新文件
getPath() 得到File的路径

2.步骤

(1)在布局文件中,添加Button和ImageView

<Button
        android:id="@+id/takePhotoBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="take Photo"/>
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

(2)设置变量

    private val takePhoto=1
    lateinit var imageUri: Uri
    lateinit var outputImage:File

(3)创建File对象

将图片命名为output_image.jpg并存放在手机SD卡的应用关联缓存目录下

outputImage = File(externalCacheDir, "output_image.jpg")
            if (outputImage.exists()) {//如果路径存在,就先删除
                outputImage.delete()
            }
            outputImage.createNewFile()//创建一个新的File

(4)把File转换成Uri

从Android7.0系统开始,直接使用本地路径的Uri被认为是不安全,会抛出一个FileUriExposedException异常,而FileProvide则是一种特殊的ContentProvider,它使用了和ContentProvider类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。

imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                FileProvider.getUriForFile(this, "com.example.cameraman's.fileprovider", outputImage);
            } else {
                Uri.fromFile(outputImage);
            }

(5)启动相机程序

// 启动相机程序
           val intent= Intent("android.media.action.IMAGE_CAPTURE")
            intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri)
            requestDataLauncher.launch(intent)

(6)在onActivityResult()函数中,在相机程序拍到的图片显示出来

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        val imageView: ImageView = findViewById(R.id.imageView)
        when (requestCode) {
            takePhoto -> {
                if (resultCode == RESULT_OK) {
                    // 将拍摄的照片显示出来
                    val bitmap =
                        BitmapFactory.decodeStream(contentResolver.openInputStream(imageUri))
                    imageView.setImageBitmap(rotateIfRequired(bitmap))
                }
            }
        }
    }

(7)解决调用相机程序去拍照有可能会在一些手机上发生照片旋转的情况

private fun rotateIfRequired(bitmap: Bitmap): Bitmap {
            val exif = ExifInterface(outputImage.path)
            val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            return when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmap(bitmap, 90)
                ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmap(bitmap, 180)
                ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmap(bitmap, 270)
                else -> bitmap
            }
        }

        private fun rotateBitmap(bitmap: Bitmap, degree: Int): Bitmap {
            val matrix = Matrix()
            matrix.postRotate(degree.toFloat())
            val rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
            bitmap.recycle()
            return rotatedBitmap
        }

(8)在AndroidManifeest.xml对ContentProvider进行注册

android:authorities属性的值必须和刚才FileProvider.getUriForFile()方法中的第二个参数一致,另外,这里还在<provider>标签的内部使用<meta-data>指定Uri的共享路径,并引入一个@xml/file_paths资源。

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.cameraman's.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

(9)右击res目录->New->Directory,创建一个xml目录,接着右击xml目录->New->File,创建一个file_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="/" />
</paths>

三、从相册中选择图片

步骤

(1)在布局文件中加入Button:fromAlbumBtn

<Button
        android:id="@+id/fromAlbumBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="From Album"/>

(2)初始化fromAlbum

val fromAlbum = 2

(3)在按键fromAlbumBtn的点击事件中,打开文件选择器,显示图片

val fromAlbumBtn: Button = findViewById(R.id.fromAlbumBtn)
        fromAlbumBtn.setOnClickListener {
            val intent1=Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent1.addCategory(Intent.CATEGORY_OPENABLE)
            intent1.type="image/*"
            requestDataLauncher1.launch(intent1)
        }

(4)在onActivityResult()函数中,将选择的图片显示出来

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        val imageView: ImageView = findViewById(R.id.imageView)
        when (requestCode) {
            ...
            fromAlbum -> {
                if (resultCode == RESULT_OK && data != null) {
                    data.data?.let { uri ->
                        //将选择的图片显示
                        val bitmap = getBitmapFromUri(uri)
                        imageView.setImageBitmap(bitmap)
                    }
                }
            }
        }
    }

(5)将Uri转换成Bitmap

private fun getBitmapFromUri(uri: Uri) =
        contentResolver.openFileDescriptor(uri, "r")?.use{
            BitmapFactory.decodeFileDescriptor(it.fileDescriptor)
        }

四、播放多媒体文件

1、播放音频

步骤

(1)创建一个MediaPlayer的实例

private val mediaPlayer=MediaPlayer()

(2)为MediaPlayer对象进行初始化操作

通过getAssets()方法得到一个AssetManager的实例,AssetManager可用于读取assets目录下的任何资源,接着调用openFd()方法将音频文件句柄打开,后来调用setDataSource()方法设置要播放的音频文件的位置和prepare()方法完成准备工作。

private fun initMediaPlayer() {
        val assetManager=assets
        val fd=assetManager.openFd("music.mp3")
        mediaPlayer.setDataSource(fd.fileDescriptor,fd.startOffset,fd.length)
        mediaPlayer.prepare()
    }

(3)设置三个按键的点击事件

        val play:Button=findViewById(R.id.play)
        val pause:Button=findViewById(R.id.pause)
        val stop:Button=findViewById(R.id.stop)
        play.setOnClickListener {
            if(!mediaPlayer.isPlaying)
                mediaPlayer.start()
        }
        pause.setOnClickListener {
            if(mediaPlayer.isPlaying){
                mediaPlayer.pause()
            }
        }
        stop.setOnClickListener {
            if(mediaPlayer.isPlaying){
                mediaPlayer.reset()
                initMediaPlayer()
            }
        }

(4)最后在onDestroy()方法中,我们需要调用stop()方法和release()方法将MediaPlayer相关的资源释放掉。

override fun onDestroy() {
        super.onDestroy()
        mediaPlayer.stop()
        mediaPlayer.release()
    }


2、播放视频

步骤

(1)在布局文件中放置三个按钮,分别控制视频的播放,暂停,和重新播放,在按钮下面放置视频VideoView。

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/play"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="play"/>
        <Button
            android:id="@+id/pause"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="pause"/>
        <Button
            android:id="@+id/replay"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="replay"/>
    </LinearLayout>

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="videoView"/>

(2)点击res->New->Directory,然后输入raw,把视频资源放在这。

(3)初始化VideoView

val uri=Uri.parse("android.resource://$packageName/${R.raw.video}")
        videoView.setVideoURI(uri)

(4)设置三个按键的点击事件

 play.setOnClickListener {
            if(!videoView.isPlaying)
                videoView.start()
        }
        pause.setOnClickListener {
            if(videoView.isPlaying){
                videoView.pause()
            }
        }
        replay.setOnClickListener {
            if(videoView.isPlaying){
                videoView.resume()
            }
        }

(5)在onDestroy()方法中,需要调用suspend()方法,将VideoView所占用的资源释放掉。

override fun onDestroy() {
        super.onDestroy()
        videoView.suspend()
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android开发,使用kotlin学习多媒体功能(详细) 的相关文章

  • 未为模块“Example-Example”指定 APK 路径

    我是 Android 应用程序开发领域的新手 我正在创建一个项目示例安卓工作室 我有我的午餐列表 java文件输入src main java apt tutorial lunchlist 直到昨天一切都工作正常 但是当我今天打开 andro
  • 方法调用 mActionBar=getActionBar() 给出错误[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在使用支持库android support v7 app actionbar因为我想要操作栏API 级别 8以上 但是下面的句子给了我
  • 为 DownloadManager 的 BroadcastReceiver 设置附加功能 [重复]

    这个问题在这里已经有答案了 有一种方法可以添加额外内容DownloadManager已登记行动意图DownloadManager ACTION DOWNLOAD COMPLETE 例如 接收一个在意图中设置为额外的布尔值 这就是我创建请求的
  • 更改 Android Spinner 布局/设计

    我正在尝试修改设计Spinner http developer android com intl de reference android widget Spinner html小部件 我可以更改背景 但找不到更改右侧箭头图标的方法 有办法
  • 从 ios 和 android 端连接到 xmpp 时获取所有群组消息

    我在用开放火版本 4 0 1 使用开火Rest Api https github com gidkom php openfire restapi我在服务 servicename xx xx xxx xxx 中创建了群聊室 现在房间已创建 发
  • Android TableRow 垂直拉伸以填充屏幕

    我正在尝试创建一个电话拨号器视图 使用 TableLayout 在 3x4 网格中创建 12 个按钮 我希望行垂直拉伸以平等地使用所有可用空间 但似乎 fill parent 在 TableRows 上不起作用 我不想使用 setMinim
  • 如何处理应用程序对 3d party 的依赖

    我当前正在开发的应用程序依赖于第三方应用程序 OIFileManager 我的问题是处理这些依赖关系的一般方法是什么 告诉用户解决它 嵌入 3d party apk 如果其许可证允许 自动解决 也许Android市场有相应的系统 没有自动的
  • Android 崩溃报告库(Froyo 之前)[重复]

    这个问题在这里已经有答案了 你知道 Android 的崩溃报告库吗 我不想花很多时间来编写自己的报告系统 输出可以发送到电子邮件或某种服务器 我知道 Google 在 Froyo 中引入了崩溃报告 但我想要一些适用于旧版本系统的东西 我们来
  • 在应用程序启动期间更改主题的最快方法

    目前 我确实在我的应用程序中根据用户最后的选择提供了 2 个主题 深色主题和浅色主题 在主要活动启动期间 我将执行以下操作 public class MyFragmentActivity extends FragmentActivity O
  • 方法不必要地被调用?

    我有一个 BaseActivity 它可以通过其他所有活动进行扩展 问题是 每当用户离开 暂停 活动时 我都会将音乐静音 我也不再接听电话 问题是 onPause每当用户在活动之间切换时就会被调用 这意味着应用程序不必要地静音和停止tele
  • Android 上的 Chrome 强制隐藏地址栏

    我最近开发了一个获取混合 http https 内容的网站 因此 我总是将地址栏显示在顶部 它不会像其他网站那样自动隐藏 这就是我要说的 This https planetkde org 是网站的链接 内容是从各种来源获取的 因此无法过滤非
  • 拦截来自外部应用程序的意图

    假设我想开发一个以某种方式扩展的应用程序 让我说 合作 非常受欢迎的应用程序我显然无法控制 为了简单起见 我们还假设非常著名的应用程序作者不会发布更新来阻止我的应用程序 我研究了该应用程序的功能并发现它广泛使用BroadcastReceiv
  • CollapsingToolbarLayout 禁用绘制扩展

    我有一个已有条件禁用的 CollapsingToolbar 当用户在这种情况下加载视图时 它看起来就像一个普通的 ToolBar 对象 唯一奇怪的是 如果它们向下拖动 例如在拉动刷新样式操作中 折叠工具栏就会展开 尽管我的愿望和代码与此相反
  • android:widgetLayout 和 android:layout 之间的区别?

    我得到一些奇怪的配置 其中 widgetLayout 配置列表项的内部空间 而布局配置整个项目列表和屏幕背景 有人能真正解释一下什么是 widgetLayout 吗 android layout 整个首选项的布局 包括标题 摘要和小部件 a
  • 使用 Asp.Net 的 GCM 推送通知

    正如您可能已经看到的 Google 正在迁移其推送通知系统 http developer android com guide google gcm c2dm html http developer android com guide goo
  • getViewByID 对于 Listview 返回 null

    我的 main xml 如下
  • 使用 IntelliJ / Android Studio 调试基于 gradle 的单元测试

    我正在使用robolectric gradle 插件 https github com robolectric robolectric gradle plugin为 Android 编写单元测试 到目前为止 除了能够使用 Android S
  • Android - 如何合并两个视频

    基本上 我正在寻找一种将两个 mp4 视频文件 在 SD 卡上 组合在一起的方法 更像是在第一个视频的末尾附加第二个视频 我进行了很多搜索 但找不到合适的解决方案 好吧 我根本找不到任何解决方案 所以我的问题是 是否有一个库可以组合 并可能
  • ProGuard 与 Android:java.lang.NoSuchMethodError:android.util.Xml.asAttributeSet

    当 ProGuard 被禁用时 我的应用程序运行正常 启用ProGuard后 应用程序将导出为apk并安装到模拟器中 然后当我在模拟器中运行它时 强制关闭 05 10 11 14 10 582 E AndroidRuntime 759 FA
  • 如何自动更新Android Studio?

    我需要将 Android Studio 更新到 0 9 9 版本 但是当我按 下载 在更新信息对话框上 时 它会将我发送到此处 http developer android com sdk index html http developer

随机推荐

  • 对Java Stream 进行二次封装

    对Java Stream 进行二次封装 一共整理了10个工具方法 可以满足 Collection List Set Map 之间各种类型转化 例如 将 Collection
  • idea springboot项目运行出错(运行模式问题)

    问题 解决办法 第一步 第二步 DoperatingMode dev
  • Error: T doesn‘t have .length

    Error T doesn t have length 在 TypeScript 中 当我们使用泛型
  • String.class.equals(value.getClass())

    这段代码是在判断变量 value 是否是 String 类型的示例代码 它使用了 Java 中的反射机制 解析该代码的含义如下 String class 表示获取 String 类的 Class 对象 它是描述 String 类的类对象 v
  • R语言采集获取58商铺出租转让信息

    前两篇文章给我一个朋友分析出店铺商品以及地址房源信息 后来去看了下店铺房租有点贵 还是毛坯房 要自己装修 本着节约成本的原则 熬了个通宵 给他采集了一些转租商铺数据 因为数据比较多 过于先进不方便展示 我就将我爬虫程序的模版展示给大家观看
  • 通俗易懂的讲解Java 中的反射机制

    Java 中的反射机制是指在程序运行时动态地获取类的信息 以及在运行时动态操作类和对象的能力 通过反射机制 我们可以在编译时不知道具体类的情况下 获取类的属性 方法 构造函数等信息 并且可以在运行时调用这些属性 方法或创建对象 反射机制提供
  • 说说一次 Dubbo 服务请求流程?

    Dubbo 是一个高性能 轻量级的开源 Java RPC 框架 用于构建服务化应用程序 下面是一个简单的 Dubbo 服务请求流程 客户端发起请求 客户端通过 Dubbo 提供的 RPC 客户端库发送请求到 Dubbo 服务提供者 请求包含
  • 基于SpringBoot+Vue的中山社区医疗综合服务平台设计实现(源码+lw+部署文档+讲解等)

    文章目录 前言 详细视频演示 具体实现截图 技术栈 后端框架SpringBoot 前端框架Vue 持久层框架MyBaitsPlus 系统测试 系统测试目的
  • 智慧排水检测系统,提升城市生命线管理效率

    随着城市化的快速发展 排水系统作为城市生命线的重要组成部分 其管理和维护对于城市的正常运行至关重要 传统的排水系统监测方法往往依赖人工巡查和定期的设备检查 存在效率低下 易出错等问题 为了解决这些问题 智慧排水监测系统应运而生 本文将详细介
  • Vue 条件渲染 v-if

    v if 指令 用于控制元素的显示或隐藏 执行条件 当条件为 false 时 会将元素从 DOM 中删除 应用场景 适用于显示隐藏切换频率较低的场景 语法格式 div 内容 div 基础用法
  • ISO认证的意义以及费用

    ISO认证是国际标准化组织制定的一套标准体系 它对于企业来说具有重要的意义 ISO认证可以帮助企业提高管理水平 提升产品品质 增强市场竞争力 同时也是企业拓展市场 开拓客户的重要手段 一 ISO认证的意义 ISO认证具有以下几个方面的意义
  • ExperimentalWarning: The http2 module is an experimental API.

    错误提示 Node js ExperimentalWarning The fs promises API is experimental 原因是node的版本不是最新的 而在项目引入的模块是最新的 node js的版本低于模块的版本 解决方
  • 一键证件照换底色软件哪个好?这款让你的证件照独具特色!

    在我们生活中 有很多时候需要用到证件照 无论是报名考试还是申请签证 都需要提供一张规格标准的证件照片 然而 有时候我们拍摄的照片可能存在一些问题 比如背景色不符合要求 这时候 如果有一款一键证件照换底色软件 就能够轻松解决这个问题了 首先
  • 基于单片机设计的电子指南针(LSM303DLH模块(三轴磁场 + 三轴加速度)

    一 前言 本项目是基于单片机设计的电子指南针 主要利用STC89C52作为主控芯片和LSM303DLH模块作为指南针模块 通过LCD1602液晶显示屏来展示检测到的指南针信息 在日常生活中 指南针是一种非常实用的工具 可以帮助我们确定方向
  • C# Tcplistener,Tcp服务端简易封装

    文章目录 前言 相关文章 前言 设计 代码 简单使用 运行结果 前言 我最近有个需求要写Tcp服务端 我发现Tcp服务端的回调函数比较麻烦 简化Tcp的服务 我打算自己封装一个简单的Tcp服务端 相关文章 C TCP应用编程三 异步TCP应
  • 超级好用的SQL语句大全

    文章目录 一 DDL Data Definition Language 数据定义语言 1 操作库 2 操作表 二 DML Data Manipulation Language 数据操作语言 1 增加 insert into 2 删除 del
  • 如何利用 Kubernetes 的新 CronJob API 进行高效的任务调度

    Kubernetes 的 CronJob API 是在云原生环境中自动执行常规任务的关键功能 本指南不仅引导您完成使用此 API 的步骤 还说明了它非常有用的实际用例 先决条件 正在运行的 Kubernetes 集群 版本 1 21 或更高
  • MySQL数据库:为什么它是您的最佳选择?

    MySQL是一个关系型数据库管理系统 由瑞典MySQL AB公司开发 目前属于Oracle旗下产品 MySQL是最流行的关系型数据库管理系统之一 在WEB应用方面 MySQL是最好的RDBMS Relational Database Man
  • Linux中使用HTTP协议进行API交互的示例——你的“API小伙伴”

    大家好 今天我们要聊聊在Linux中如何使用HTTP协议进行API交互 听起来有点高大上 但其实并不难 让我们一起来看看 首先 我们需要了解什么是API API 全名为应用程序接口 Application Programming Inter
  • Android开发,使用kotlin学习多媒体功能(详细)

    一 通知 1 用到的类和方法 1 Context类 getSystemService 接收一个字符串参数用于确定获取系统的哪个服务 这里我们传入Context NOTIFICATION SERVICE 获取NotificationManag