GDPU Android移动应用 使用多媒体
制作一个播放器,触发通知。
音视频播放器
1.新建一个项目MultimediaPlayer,
2.创建一个Activity,利用MediaPlayer实现一个简单的音频播放器,功能包括:
a)支持播放一个固定的音频文件
b)包含三个按钮,分别实现播放、暂停和停止
c)在音频播放结束时,触发一个通知,提醒音频播放结束
3.创建另一个Activity,实现视频的播放。
a)支持播放一个固定的视频文件
b)包含三个按钮,分别实现播放、暂停和重新播放
c)在视频播放结束时,触发一个通知,提醒视频播放结束(跟音频播放结束的通知要有所区别)。
新建项目,名称为MultimediaPlayer,不会新建项目的可以翻看以前的文章。然后一个活动用来做音频播放器,一个活动用来做视频播放器,此外可以再建一个活动用来做通知,再分别编写对应的xml即可。由于一个app进去的就是主活动,所以在主活动页面再写一个intent跳转到另一个活动页面。
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.media.MediaPlayer
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Button
import android.widget.SeekBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
class MainActivity : AppCompatActivity() {
private var mediaPlayer: MediaPlayer? = null
private lateinit var btnPlay: Button
private lateinit var btnPause: Button
private lateinit var btnStop: Button
private lateinit var seekBar: SeekBar
private lateinit var songNameTextView: TextView
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 初始化视图
btnPlay = findViewById(R.id.btnPlay)
btnPause = findViewById(R.id.btnPause)
btnStop = findViewById(R.id.btnStop)
seekBar = findViewById(R.id.seekBar)
songNameTextView = findViewById(R.id.songNameTextView)
// 添加一个按钮来启动视频播放器
val btnOpenVideoPlayer: Button = findViewById(R.id.btnOpenVideoPlayer)
btnOpenVideoPlayer.setOnClickListener {
val intent = Intent(this, VideoPlayer::class.java)
startActivity(intent)
}
handler = Handler(Looper.getMainLooper()) // 初始化 handler
mediaPlayer = MediaPlayer()
// 初始化 MediaPlayer
initMediaPlayer()
// 播放音频
btnPlay.setOnClickListener {
mediaPlayer?.let {
if (!it.isPlaying) {
it.start()
updateSeekBar()
}
}
}
// 暂停音频
btnPause.setOnClickListener {
mediaPlayer?.let {
if (it.isPlaying) {
it.pause()
handler.removeCallbacks(updateSeekBarTask)
}
}
}
// 停止音频
btnStop.setOnClickListener {
mediaPlayer?.let {
if (it.isPlaying) {
it.stop()
it.prepareAsync()
handler.removeCallbacks(updateSeekBarTask)
}
}
}
// 创建通知渠道
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)
// 设置音频播放完成的监听器,播放结束时发送通知
mediaPlayer?.setOnCompletionListener {
val notification = NotificationCompat.Builder(this, "normal")
.setContentTitle("音频播放结束")
.setContentText("你的音乐播放完啦~")
.setSmallIcon(R.drawable.notice_icon)
.setLargeIcon(
BitmapFactory.decodeResource(
resources,
R.drawable.large_icon
)
)
.setAutoCancel(true)// 点击后自动取消通知
.build()
manager.notify(1, notification)// 发送通知
}
}
// 为 SeekBar 设置监听器
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
// 如果是用户拖动导致的进度条变化,则更新音频播放位置
if (fromUser) {
mediaPlayer?.seekTo(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
// 音频初始化
private fun initMediaPlayer() {
mediaPlayer?.setDataSource(assets.openFd("等你下课-周杰伦.mp3"))
mediaPlayer?.prepare()
songNameTextView.text = "等你下课-周杰伦"// 显示歌曲名称
seekBar.max = mediaPlayer?.duration ?: 0
}
// 更新进度条
private fun updateSeekBar() {
mediaPlayer?.let {
seekBar.progress = it.currentPosition
handler.postDelayed(updateSeekBarTask, 1000)
}
}
private val updateSeekBarTask = Runnable { updateSeekBar() }
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.release()
handler.removeCallbacks(updateSeekBarTask)
}
}
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.widget.Button
import android.widget.SeekBar
import android.widget.VideoView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
class VideoPlayer : AppCompatActivity() {
private lateinit var videoView: VideoView
private lateinit var btnPlay: Button
private lateinit var btnPause: Button
private lateinit var btnReplay: Button
private lateinit var videoSeekBar: SeekBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_video_player)
// 初始化控件
btnPlay = findViewById(R.id.btnPlay)
btnPause = findViewById(R.id.btnPause)
btnReplay = findViewById(R.id.btnReplay)
videoSeekBar = findViewById(R.id.videoSeekBar)
videoView = findViewById(R.id.videoView)
// 设置视频文件
val videoUri = Uri.parse("android.resource://${packageName}/${R.raw.t11}")
videoView.setVideoURI(videoUri)
// 播放按钮点击事件
btnPlay.setOnClickListener {
if (!videoView.isPlaying) {
videoView.start()
}
}
// 暂停按钮点击事件
btnPause.setOnClickListener {
if (videoView.isPlaying) {
videoView.pause()
}
}
// 重播按钮点击事件
btnReplay.setOnClickListener {
if (!videoView.isPlaying) {
videoView.resume()
}
}
// 设置视频准备完成后的回调
videoView.setOnPreparedListener { mediaPlayer ->
// 设置进度条的最大值为视频的总时长
videoSeekBar.max = mediaPlayer.duration
}
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel2 = NotificationChannel(
"important", "Important", NotificationManager.IMPORTANCE_HIGH
)
manager.createNotificationChannel(channel2)
videoView.setOnCompletionListener {
// 构建通知
val intent = Intent(this, Notification::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, "important")
.setContentTitle("视频播放结束")
.setContentText("你的视频播放完啦…")
.setSmallIcon(R.drawable.notice_icon)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
.setContentIntent(pendingIntent)
.build()
manager.notify(1, notification)
}
}
// 设置视频进度条监听器
videoSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser) {
videoView.seekTo(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
updateSeekBar()
}
// 更新视频进度条
private fun updateSeekBar() {
val handler = android.os.Handler()
handler.postDelayed(object : Runnable {
override fun run() {
videoSeekBar.progress = videoView.currentPosition
handler.postDelayed(this, 1000)
}
}, 0)
}
override fun onDestroy() {
super.onDestroy()
videoView.stopPlayback()
}
}
import android.app.NotificationManager
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class Notification : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_notification)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 取消通知
manager.cancel(1)
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<!-- SeekBar -->
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:max="100"
android:progress="0" />
<!-- Song Name TextView -->
<TextView
android:id="@+id/songNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/seekBar"
android:layout_marginTop="20dp"
android:gravity="center"
android:textSize="18sp"
android:textStyle="bold" />
<!-- Buttons Layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/songNameTextView"
android:layout_marginTop="20dp"
android:gravity="center_horizontal">
<!-- Play Button -->
<Button
android:id="@+id/btnPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放" />
<!-- Pause Button -->
<Button
android:id="@+id/btnPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="暂停" />
<!-- Stop Button -->
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止" />
</LinearLayout>
<!-- New Video Player Button in a new LinearLayout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:gravity="center_horizontal">
<Button
android:id="@+id/btnOpenVideoPlayer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="打开视频播放器" />
</LinearLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- VideoView -->
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- SeekBar -->
<SeekBar
android:id="@+id/videoSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/videoView"
android:max="100"
android:progress="0" />
<!-- Buttons Layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/videoSeekBar"
android:gravity="center"
android:orientation="horizontal">
<!-- Play Button -->
<Button
android:id="@+id/btnPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放" />
<!-- Pause Button -->
<Button
android:id="@+id/btnPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="暂停" />
<!-- Replay Button -->
<Button
android:id="@+id/btnReplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重新播放" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="24sp" />
</RelativeLayout>
注意音视频文件资源引入,可以放在src的main目录下的assets文件(没有就新建),也可以放在main目录下的res文件下的raw文件(没有就新建),再找两个图标文件用于通知显示,放在res下的drawable文件下。
还要在AndroidManifest.xml声明几个权限。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.t11">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.T11">
<activity
android:name=".Notification"
android:exported="false" />
<activity
android:name=".VideoPlayer"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
播放完后拉一下通知栏。
跳到视频播放器。
没有收到应该是还没有开权限,点开设置,找到通知里的app notifications,点进去切换all apps找到你的当前项目,把它开启。
实验心得
有时候,生活平静也是一种奢求。