MediaPlayer
实现思路
- 本地音频资源播放
播放本地音频资源实例化MediaPlayer对象,依次调用:setDataSource、prepare()、start()方法,获取资源文件路径及准备资源文件,最后播放音频文件。
- 网络音频资源播放
播放网络资源首先需要得到网络访问权限。(代码见下方),使用prepareAsync()方法准备音频资源,使用setOnPreparedListener()方法监听资源准备情况,最后于onPrepared()方法中执行start()方法播放音频资源。
<uses-permission android:name="android.permission.INTERNET"/>
代码实现
- Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/player_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入音乐文件路径" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">" />
<Button
android:id="@+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="||" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="口" />
</LinearLayout>
</LinearLayout>
- Activity
package cn.ybxy.applicaition;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MediaPlayerActivity extends AppCompatActivity implements View.OnClickListener {
private EditText player_path;
private Button btn_start;
private Button btn_pause;
private Button btn_stop;
MediaPlayer player;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player_layout);
player_path = findViewById(R.id.player_path);
btn_start = findViewById(R.id.btn_start);
btn_pause = findViewById(R.id.btn_pause);
btn_stop = findViewById(R.id.btn_stop);
btn_start.setOnClickListener(this);
btn_pause.setOnClickListener(this);
btn_stop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
try {
// 构造多媒体对象
player = new MediaPlayer();
// 音乐加载时构造进度条对话框
final ProgressDialog pd = new ProgressDialog(this);
pd.setMessage("正在加载");
// 重置player对象资源
player.reset();
player.setDataSource(player_path.getText().toString().trim());
// 同步准备方法(主线程执行)
// player.prepare();
// 异步准备方法(子线程执行 -> 网络请求)
player.prepareAsync();
// 显示进度条对话框
pd.show();
// 异步资源准备情况监听器
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// 音乐资源文件加载完毕后隐藏对话框
pd.dismiss();
// 异步执行播放
player.start();
}
});
// 播放出现异常监听器
player.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Toast.makeText(MediaPlayerActivity.this, "播放出现异常" + what, Toast.LENGTH_SHORT).show();
return false;
}
});
// 播放完毕监听器
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MediaPlayerActivity.this, "播放完毕", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
e.printStackTrace();
}
// 同步执行执行播放 -> 异步播放时需要屏蔽这段代码,否则会出现(0,-38)资源未准备就绪错误
// player.start();
break;
case R.id.btn_pause:
// 正在播放中暂停
if (player != null && player.isPlaying()) {
player.pause();
}
// 暂停后继续播放
if (player != null) {
player.start();
}
System.out.println("播放暂停");
break;
case R.id.btn_stop:
// 停止播放
if (player != null) {
player.stop();
// 释放多媒体资源
player.release();
// 将对象初始化 -> 释放内存
player = null;
}
System.out.println("播放停止");
break;
default:
break;
}
}
}
SoundPool
功能介绍
当很多个音频文件需要播放时,需要prepared()
准备资源,在单位时间内准备资源消耗时间过长,使用SoundPool可以规避这个问题。
SoundPool提前将音频资源加载到内存,使用时直接从内存中读取,从而降低响应时间。
代码实现
- Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_play"
android:onClick="play_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="播放"/>
</LinearLayout>
- Activity
package cn.ybxy.applicaition;
import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.View;
public class SoundPoolActivity extends AppCompatActivity {
private SoundPool soundPool;
private int soundID;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pool_layout);
// 声音池最大线程数、声音类型(STREAM_MUSIC占用内存最大)、声音质量
soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC,0);
soundID = soundPool.load(this,R.raw.boom,0);
}
public void play_voice(View view){
// 声音池中的线程ID、左声道音量、右声道音量、优先级、是否循环、声音速率
soundPool.play(soundID,1.0f,1.0f,0,0,1.0f);
}
}
视频播放
实现思路
- Layout
首先需要设置屏幕显示方向为横向,且设置Layout布局为没有标题栏及全屏显示,然后使用VideoView
放置视频媒体。 - Activity
设置视频媒体源,如果需要视频控制控件,则使用MediaController
对象,通过setAnchorView()
方法为父元素(这里代指VideoView)添加控制控件,最后为VideoView对象添加MediaControl
对象,将视频控制控件添加到视频源中。
代码实现
首先需要在styles.xml
中自定义一个无标题栏及全屏显示的主题样式,代码如下:
<style name="BasicTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
</style>
然后在AndroidManifest.xml
中对应的Activity中引用该主题样式,并设置屏幕方向横屏。
<activity
android:name=".VideoActivity"
android:screenOrientation="landscape"
android:theme="@style/BasicTheme"></activity>
- Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<VideoView
android:id="@+id/vv_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
- Activity
package cn.ybxy.applicaition;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.VideoView;
public class VideoActivity extends AppCompatActivity {
private VideoView vv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_layout);
// 初始化视频VideoView对象
vv = findViewById(R.id.vv_video);
vv.setVideoPath("/mnt/sdcard/Download/1.mp4");
// 实例化控制组件 -> 视频控制组件
MediaController mc = new MediaController(this);
mc.setAnchorView(vv);
// 给视频源设置控制源
vv.setMediaController(mc);
vv.start();
}
}
SurfaceView实现多媒体渲染播放
实现原理
代码实现
- Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_playsv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:onClick="start_surf"
android:text="播放" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<SurfaceView
android:id="@+id/sv_surf"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
- Activity
package cn.ybxy.applicaition;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
public class SurfaceViewActivity extends AppCompatActivity {
private SurfaceView sv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.surface_layout);
sv = findViewById(R.id.sv_surf);
// surfaceView回调方法
sv.getHolder().addCallback(new SurfaceHolder.Callback() {
// surface准备成功后调用方法
@Override
public void surfaceCreated(SurfaceHolder holder) {
new Thread(new Runnable() {
@Override
public void run() {
// 遍历100次,绘制半径主键扩大的圆
for (int i = 0; i < 100; i++) {
SurfaceHolder holder = sv.getHolder();
// 锁定画布
Canvas canvas = holder.lockCanvas();
// 100次遍历执行完毕后设置画布颜色为黑色,清空画布已画元素实现画布刷新。
canvas.drawColor(Color.BLACK);
// 绘画半径
int radius = 5 + i;
// 创建画笔对象
Paint paint = new Paint();
paint.setColor(Color.RED);
// 于画布中画圆(圆心坐标(x,y)、半径、画笔)
canvas.drawCircle(250, 250, radius, paint);
// 解锁画布提交数据
holder.unlockCanvasAndPost(canvas);
// 休眠0.1s给程序时间加载画布
SystemClock.sleep(100);
}
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
public void start_surf(View view){
new Thread(new Runnable() {
@Override
public void run() {
// 遍历100次,绘制半径主键扩大的圆
for (int i = 0; i < 100; i++) {
SurfaceHolder holder = sv.getHolder();
// 锁定画布
Canvas canvas = holder.lockCanvas();
// 100次遍历执行完毕后设置画布颜色为黑色,清空画布已画元素实现画布刷新。
canvas.drawColor(Color.BLACK);
// 绘画半径
int radius = 5 + i;
// 创建画笔对象
Paint paint = new Paint();
paint.setColor(Color.RED);
// 于画布中画圆(圆心坐标(x,y)、半径、画笔)
canvas.drawCircle(250, 250, radius, paint);
// 解锁画布提交数据
holder.unlockCanvasAndPost(canvas);
// 休眠0.1s给程序时间加载画布
// SystemClock.sleep(100);
}
}
}).start();
}
}
来源:CSDN
作者:Wondercar
链接:https://blog.csdn.net/weixin_42167233/article/details/103473518