美文网首页
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