第6章音频和视频
178.使用MediaPlayer播放本地mp3音乐文件
首先,manifest中加入权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
然后在内置sd卡(不可拔插的sd卡)中放一首歌曲。这里我放的是A.mp3(随便一首歌然后重命名为A)。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private String mString = Environment.getExternalStorageDirectory().toString();// /storage/emulated/0
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"mString = " + mString);
try {
MediaPlayer mediaPlayer = new MediaPlayer();
mString = mString + "/A.mp3";
Log.d(TAG,"mString1 = " + mString);
mediaPlayer.setDataSource(mString);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
外置SD卡路径 需要通过反射获取。
/**
* 通过反射调用获取内置存储和外置sd卡根路径(通用)
*
* @param mContext 上下文
* @param is_removale 是否可移除,false返回内部存储路径,true返回外置SD卡路径
* @return
*/
private static String getStoragePath(Context mContext, boolean is_removale) {
String path = "";
//使用getSystemService(String)检索一个StorageManager用于访问系统存储功能。
StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClazz = null;
try {
storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getPath = storageVolumeClazz.getMethod("getPath");
Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
Object result = getVolumeList.invoke(mStorageManager);
for (int i = 0; i < Array.getLength(result); i++) {
Object storageVolumeElement = Array.get(result, i);
path = (String) getPath.invoke(storageVolumeElement);
boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
if (is_removale == removable) {
return path;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return path;
}
这里我本机的外置SD卡路径路径是
/storage/69CA-12F6
参考链接:
Android 获取外置SD卡
179.使用MediaPlayer播放本地mp4视频文件
书上是使用MediaPlayer + SurfaceView的方式播放视频。
书上的surfaceview的用法我稍微改动就出现了MediaPlayer.setDisplay(surfaceHolder)时报错The surface has been released错误,因此需要采用更稳妥一点的使用方法,那就是调用SurfaceHolder.addCallback。
首先把.mp4文件放到内置sd卡根目录下。
加上权限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
MainActivity
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private String mString = Environment.getExternalStorageDirectory().toString();// /storage/emulated/0
private MediaPlayer mMediaPlayer;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.setFixedSize(400,800);
mMediaPlayer = new MediaPlayer();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mString = mString + "/A.mp4";
Log.d(TAG,"mString = " + mString);
mMediaPlayer.setDataSource(mString);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
});
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
180.使用MediaPlayer播放指定网址的音乐文件
这部分这里3个知识点 。
1.下载之后播放网络音乐
2.seekbar 显示播放进度
3.暂停播放。
所以首先需要一个提供下载以及播放mp3的api。
书上用的是170mv网站的链接。
1和3的知识点看这里。
Android-MediaPlayer播放网络音频
https://blog.csdn.net/qq_41113081/article/details/86690615
这里用到的是这个链接,访问这个链接就会自动下载mp3。
http://www.ytmp3.cn/down/57799.mp3
最后代码如下:
首先加入权限。
<uses-permission android:name="android.permission.INTERNET"/>
xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_play"
android:text="下载后播放"
android:layout_width="155dp"
android:layout_height="58dp"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<Button
android:id="@+id/button"
android:text="暂停"
android:layout_width="163dp"
android:layout_height="56dp"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<TextView
android:layout_width="85dp"
android:layout_height="28dp"
android:text="总长"
android:id="@+id/total_textView"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="123dp"/>
<TextView
android:id="@+id/current_textView"
android:layout_width="60dp"
android:layout_height="37dp"
android:text="当前播放时间"
android:layout_marginLeft="29dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="123dp"/>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="154dp"
android:layout_height="49dp"
android:layout_marginRight="115dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="115dp"
/>
</android.support.constraint.ConstraintLayout>
MainActivity
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private MediaPlayer mMediaPlayer;
private Button mButton;
private SeekBar mSeekBar;
private Button mButtonPlay;
private String mTotalString;
private String mCurrentString;
private TextView mTotalTimeTextView;
private TextView mCurrentTimeTextView;
public Handler mHandler = new Handler(){
@Override
public void handleMessage(Message message){
//获取当前播放时间
mCurrentString = mMediaPlayer.getCurrentPosition()/1000/60 + ":" + (mMediaPlayer.getCurrentPosition()/1000%60 < 10 ?
"0" + mMediaPlayer.getCurrentPosition()/1000%60 : mMediaPlayer.getCurrentPosition()/1000%60);
mCurrentTimeTextView.setText(mCurrentString);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTotalTimeTextView = (TextView) findViewById(R.id.total_textView);
mCurrentTimeTextView = (TextView) findViewById(R.id.current_textView);
mButton = (Button) findViewById(R.id.button);
mButtonPlay= (Button) findViewById(R.id.button_play);
mButtonPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//耗时操作,不要放到onCreate中,会影响布局加载速度,而且其实这里应该写个线程
try {
mMediaPlayer.setDataSource("http://www.ytmp3.cn/down/57799.mp3");
mMediaPlayer.prepare();
mMediaPlayer.start();
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
//显示缓冲进度
mSeekBar.setSecondaryProgress((i / 100) * mMediaPlayer.getDuration());
}
});
mSeekBar.setMax(mMediaPlayer.getDuration());
//获取音乐长度
mTotalString = mMediaPlayer.getDuration()/1000/60 + ":" + (mMediaPlayer.getDuration()/1000%60 < 10 ?
"0" + mMediaPlayer.getDuration()/1000%60 : mMediaPlayer.getDuration()/1000%60);
mTotalTimeTextView.setText(mTotalString);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
mHandler.sendEmptyMessage(1);
}
},0,10);
} catch (IOException e) {
e.printStackTrace();
}
}
});
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
mButton.setText("播放");
}else {
mMediaPlayer.start();
mButton.setText("暂停");
}
}
});
mSeekBar = (SeekBar) findViewById(R.id.seekBar);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mMediaPlayer.seekTo(seekBar.getProgress());
}
});
mMediaPlayer = new MediaPlayer();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
}
181.使用滑块同步MediaPlayer播放音频的进度
书上介绍了2个知识点。
1.OnSeekBarChangeListener的onStopTrackingTouch中通过MediaPlayer.seekTo(SeekBar.getProgress())设置音频播放进度。这里跟上一节的代码有重复。上一节就实现了。
mMediaPlayer.seekTo(seekBar.getProgress());
2.从本地获取加载音频并播放。
书上的uri获取路径的方法现在已经不适用了。
首先加入权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
UriUtils
public class UriUtils {
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
MainActivity
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private MediaPlayer mMediaPlayer;
private Button mButton;
private SeekBar mSeekBar;
private Button mButtonChoose;
private String mTotalString;
private String mCurrentString;
private TextView mTotalTimeTextView;
private TextView mCurrentTimeTextView;
public Handler mHandler = new Handler(){
@Override
public void handleMessage(Message message){
//获取当前播放时间
mCurrentString = mMediaPlayer.getCurrentPosition()/1000/60 + ":" + (mMediaPlayer.getCurrentPosition()/1000%60 < 10 ?
"0" + mMediaPlayer.getCurrentPosition()/1000%60 : mMediaPlayer.getCurrentPosition()/1000%60);
mCurrentTimeTextView.setText(mCurrentString);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTotalTimeTextView = (TextView) findViewById(R.id.total_textView);
mCurrentTimeTextView = (TextView) findViewById(R.id.current_textView);
mButton = (Button) findViewById(R.id.button);
mButtonChoose= (Button) findViewById(R.id.button_choose);
mButtonChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("audio/*"); //选择音频
startActivityForResult(Intent.createChooser(intent,null), 2);
}
});
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
mButton.setText("播放");
}else {
mMediaPlayer.start();
mButton.setText("暂停");
}
}
});
mSeekBar = (SeekBar) findViewById(R.id.seekBar);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mMediaPlayer.seekTo(seekBar.getProgress());
}
});
mMediaPlayer = new MediaPlayer();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2) {
if (resultCode == RESULT_OK){
Uri uri = data.getData();
String path = UriUtils.getPath(MainActivity.this,uri);
Log.d(TAG,"path = " + path);
try {
mMediaPlayer.setDataSource(path);
mMediaPlayer.prepare();
mSeekBar.setMax(mMediaPlayer.getDuration());
mTotalString = mMediaPlayer.getDuration()/1000/60 + ":" + (mMediaPlayer.getDuration()/1000%60 < 10 ?
"0" + mMediaPlayer.getDuration()/1000%60 : mMediaPlayer.getDuration()/1000%60);
mTotalTimeTextView.setText(mTotalString);
if(mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
mButton.setText("播放");
}else {
mMediaPlayer.start();
mButton.setText("暂停");
}
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
mHandler.sendEmptyMessage(1);
}
},0,10);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
}
xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_choose"
android:text="选择文件"
android:layout_width="155dp"
android:layout_height="58dp"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<Button
android:id="@+id/button"
android:text="暂停"
android:layout_width="163dp"
android:layout_height="56dp"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<TextView
android:layout_width="85dp"
android:layout_height="28dp"
android:text="总长"
android:id="@+id/total_textView"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="123dp"/>
<TextView
android:id="@+id/current_textView"
android:layout_width="60dp"
android:layout_height="37dp"
android:text="当前播放时间"
android:layout_marginLeft="29dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="123dp"/>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="154dp"
android:layout_height="49dp"
android:layout_marginRight="115dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="115dp"
/>
</android.support.constraint.ConstraintLayout>
参考链接:
Android之根据Uri获得图片或视频文件路径(解决4.4以上版本得不到路径的情况)
https://blog.csdn.net/jenly121/article/details/48373861
182.使用滑块同步MediaPlayer播放视频的进度
首先,加入权限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
UriUtils上一小节有贴出。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private MediaPlayer mMediaPlayer;
private Button mButton;
private SeekBar mSeekBar;
private Button mButtonChoose;
private String mTotalString;
private String mCurrentString;
private TextView mTotalTimeTextView;
private TextView mCurrentTimeTextView;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
public Handler mHandler = new Handler(){
@Override
public void handleMessage(Message message){
//获取当前播放时间
mCurrentString = mMediaPlayer.getCurrentPosition()/1000/60 + ":" + (mMediaPlayer.getCurrentPosition()/1000%60 < 10 ?
"0" + mMediaPlayer.getCurrentPosition()/1000%60 : mMediaPlayer.getCurrentPosition()/1000%60);
mCurrentTimeTextView.setText(mCurrentString);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
mSurfaceHolder = mSurfaceView.getHolder();
mTotalTimeTextView = (TextView) findViewById(R.id.total_textView);
mCurrentTimeTextView = (TextView) findViewById(R.id.current_textView);
mButton = (Button) findViewById(R.id.button);
mButtonChoose= (Button) findViewById(R.id.button_choose);
mButtonChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*");
startActivityForResult(Intent.createChooser(intent,null), 2);
}
});
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
mButton.setText("播放");
}else {
mMediaPlayer.start();
mButton.setText("暂停");
}
}
});
mSeekBar = (SeekBar) findViewById(R.id.seekBar);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mMediaPlayer.seekTo(seekBar.getProgress());
}
});
mMediaPlayer = new MediaPlayer();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2) {
if (resultCode == RESULT_OK){
Uri uri = data.getData();
final String path = UriUtils.getPath(MainActivity.this,uri);
Log.d(TAG,"path = " + path);
mSurfaceHolder.setKeepScreenOn(true);
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mMediaPlayer.setDataSource(path);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mSeekBar.setMax(mMediaPlayer.getDuration());
mTotalString = mMediaPlayer.getDuration()/1000/60 + ":" + (mMediaPlayer.getDuration()/1000%60 < 10 ?
"0" + mMediaPlayer.getDuration()/1000%60 : mMediaPlayer.getDuration()/1000%60);
mTotalTimeTextView.setText(mTotalString);
if(mMediaPlayer.isPlaying()){
mMediaPlayer.pause();
mButton.setText("播放");
}else {
mMediaPlayer.start();
mButton.setText("暂停");
}
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
mHandler.sendEmptyMessage(1);
}
},0,10);
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
});
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
}
}
xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_choose"
android:text="选择文件"
android:layout_width="155dp"
android:layout_height="58dp"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<Button
android:id="@+id/button"
android:text="暂停"
android:layout_width="163dp"
android:layout_height="56dp"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="31dp"/>
<TextView
android:layout_width="85dp"
android:layout_height="28dp"
android:text="总长"
android:id="@+id/total_textView"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="263dp"/>
<TextView
android:id="@+id/current_textView"
android:layout_width="60dp"
android:layout_height="37dp"
android:text="当前播放时间"
android:layout_marginLeft="27dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="263dp"/>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="154dp"
android:layout_height="49dp"
android:layout_marginRight="115dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="251dp"
/>
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="355dp"
android:layout_height="141dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="101dp"
app:layout_constraintHorizontal_bias="0.5"/>
</android.support.constraint.ConstraintLayout>
延伸:
Android 音频开发之 MediaPlayer
https://www.jianshu.com/p/0e597311ebdf
Android mediaplayer的正确用法
https://www.jianshu.com/p/74a764890df8
官方的例子:
https://github.com/googlesamples/android-UniversalMusicPlayer
【Android】播放音频的几种方式介绍
Android之通过网络播放一首简单的音乐
Android 获取本地音乐
https://www.jianshu.com/p/64172861f9ef
183.使用MediaController创建视频播放控制栏
这里涉及到2个知识点。
1.VideoView播放视频
2.MediaController控制栏
VideoView控制视频播放的功能相对较少。具体而言,它只有start和pause方法。为了提供更多的控制,可以实例化一个MediaController,并通过setMediaController方法吧它设置为VideoView的控制器。
默认的MediaController有后退(rewind)、暂停(pause)、播放(play)和快进(fast-forward)按钮,还有一个清除和进度条组合控件,可以用来定位到视频中的任何一个位置。
参考链接:
9.1.4 使用MediaController添加控制
具体使用可以参考这里:
VideoView,MediaController
https://www.jianshu.com/p/3f2f8bf1d581
184.使用MediaMetadataRetriever实现视频截图
书上主要是调用了MediaMetadataRetriever中的getFrameAtTime函数。
public Bitmap getFrameAtTime(long timeUs, int option)
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(mMediaPlayer.getCurrentPosition() *1000,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
public Bitmap getFrameAtTime(long timeUs, int option) 第一个参数是传入时间,只能是us(微秒) 。
OPTION_CLOSEST 在给定的时间,检索最近一个帧,这个帧不一定是关键帧。
OPTION_CLOSEST_SYNC 在给定的时间,检索最近一个同步与数据源相关联的的帧(关键帧)。
OPTION_NEXT_SYNC 在给定时间之后检索一个同步与数据源相关联的关键帧。
OPTION_PREVIOUS_SYNC 顾名思义,同上
参考链接:
[转]android 获取视频帧
延伸:
Android MediaMetadataRetriever获取网络/本地视频第一帧图片
https://www.jianshu.com/p/bd308c8371dd
185.使用MediaMetadataRetriever获取视频缩略图
这里2个知识点,一个是调用getFrameAtTime(-1)获取bitmap,另一个是对bitmap进行裁剪。
大致代码类似这个:
ThumbnailUtils
/**
* Create a video thumbnail for a video. May return null if the video is
* corrupt or the format is not supported.
*
* @param filePath the path of video file
* @param kind could be MINI_KIND or MICRO_KIND
*/
public static Bitmap createVideoThumbnail(String filePath, int kind) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(filePath);
bitmap = retriever.getFrameAtTime(-1);
} catch (IllegalArgumentException ex) {
// Assume this is a corrupt video file
} catch (RuntimeException ex) {
// Assume this is a corrupt video file.
} finally {
try {
retriever.release();
} catch (RuntimeException ex) {
// Ignore failures while cleaning up.
}
}
if (bitmap == null) return null;
if (kind == Images.Thumbnails.MINI_KIND) {
// Scale down the bitmap if it's too large.
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int max = Math.max(width, height);
if (max > 512) {
float scale = 512f / max;
int w = Math.round(scale * width);
int h = Math.round(scale * height);
bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
}
} else if (kind == Images.Thumbnails.MICRO_KIND) {
bitmap = extractThumbnail(bitmap,
TARGET_SIZE_MICRO_THUMBNAIL,
TARGET_SIZE_MICRO_THUMBNAIL,
OPTIONS_RECYCLE_INPUT);
}
return bitmap;
}
然后调用
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path, Thumbnails.MINI_KIND); //用于获取视频的缩略图
代码出处是这里:
我的Android进阶之旅------>使用ThumbnailUtils类获取视频的缩略图
186.使用VideoView播放本地mp4视频文件
187.使用VideoView播放指定网址的视频文件
186和187合并一下可以看这篇。
Android使用VideoView播放本地和网络视频
https://blog.csdn.net/qq_42839797/article/details/88600263
188.使用MediaRecorder录制音频文件
参考链接:
ANDROID-MEDIARECORDER录制音频
189.使用RemoteViews在通知栏上创建播放器
知识点是RemoteViews在通知栏方面的应用。
代码可以参考这篇,虽然不是播放器,但是用作学习基本使用还可以。
RemoteViews一 仿qq音乐自定义通知栏实现快捷切换歌曲
https://www.jianshu.com/p/1f153e64cce5
延伸:
RemoteViews的作用和原理
https://www.jianshu.com/p/c338bc3e6868
190.在使用SurfaceView播放视频时实现横屏显示
基本上可以参考这篇:
横竖屏切换SurfaceView 大小的调整
https://blog.csdn.net/wning1/article/details/52973616
191.在选择音乐曲目窗口中选择音乐文件并播放
这里的知识点是Intent跳转到音乐文件界面,然后选择。这个有点受限于机型,我手上2台机跑起来不太一样。
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,"audio/*");
startActivityForResult(intent, 2);
延伸:
Activity 常见的意图整理
https://www.jianshu.com/p/85e899df158c
192.在RecyclerView中加载音乐文件并播放
知识点如下:
1.获取本地音乐文件,绑定到RecyclerView。
RecyclerView这里就略过了,获取本地音乐文件参考这篇。
Android 获取本地音乐
https://www.jianshu.com/p/64172861f9ef
2.播放音乐。这里是用的MediaPlayer.setDataSource(path)方法去播放的。这部分使用的是seekbar显示播放进度的。从RecyclerView中的数据中就可以获得path的。
193.依次播放在RecyclerView中的音乐文件
关键知识点是依次播放。主要用到这个函数MediaPlayer.setOnCompletionListener(MediaPlayer.OnCompletionListener listener)。
简略版参考这个:
Android播播放完SD卡指定文件夹音乐之后,自动播放下一首
详细版可以参考这个(这种带github下载地址的太友好了):
Android 简易音乐播放器
https://blog.csdn.net/qq_41105058/article/details/82813361
194.在ListView上加载手机外存的音乐文件
这个跟前面2小节的差别就是ListView和RecyclerView的使用差异。
195.使用SoundPool播放较短的声音片段
参考链接:
Android SoundPool的简单使用
https://www.jianshu.com/p/62a22367caef
196.使用AudioManager增大或减小音量
写2个button,一个增大音量一个减小音量。控制代码如下。
减小音量
AudioManager audioManager =(AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER,AudioManager.FX_FOCUS_NAVIGATION_UP);
增大音量
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE,AudioManager.FX_FOCUS_NAVIGATION_UP);
197.使用AudioManager播放系统预置的声音
这里书上调用的是playSoundEffect,但是我实际运行没有成功,原因未知,先跳过了。
audioManager.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN,1000);//播放返回音效
198.使用AudioManager获取和设置铃声模式
3个模式:普通模式、静音模式和震动模式 。
public static final int RINGER_MODE_NORMAL = 2;
public static final int RINGER_MODE_SILENT = 0;
public static final int RINGER_MODE_VIBRATE = 1;
相关代码
AudioManager audioManager =(AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.getRingerMode();//获取当前铃声模式
//设置3种模式
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
网友评论