美文网首页
Android炫酷应用300例读书笔记六

Android炫酷应用300例读书笔记六

作者: 梧叶已秋声 | 来源:发表于2019-10-05 13:32 被阅读0次

第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);

相关文章

网友评论

      本文标题:Android炫酷应用300例读书笔记六

      本文链接:https://www.haomeiwen.com/subject/swvbuctx.html