精华内容
下载资源
问答
  • MediaPlayer使用

    2017-01-05 15:45:37
    本文来自http://blog.csdn.net/hellogv/前言本文介绍MediaPlayer使用MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要...

    本文来自http://blog.csdn.net/hellogv/

    前言

    本文介绍MediaPlayer的使用。MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了。MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView。SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGL ES库。
    先贴出本文程序运行结果的截图,上面是播放/停止音频,可用SeekBar来调进度,下面是播放/停止视频,也是用SeekBar来调进度:

    这里写图片描述
    在代码中都有详细的注解,这边就不做过多的解析说明了
    XML布局文件代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.zhjy.hxf.hzmediaplayerorsurfaceview.MainActivity"
        tools:showIn="@layout/activity_main">
    
        <SeekBar
            android:id="@+id/SeekBar01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    
        <LinearLayout
            android:id="@+id/LinearLayout01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
    
            <Button
                android:id="@+id/Button01"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="播放音频" />
    
            <Button
                android:id="@+id/Button02"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="停止播放" />
    
        </LinearLayout>
    
        <SeekBar
            android:id="@+id/SeekBar02"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"></SeekBar>
    
    
        <SurfaceView
            android:id="@+id/surfaceview01"
            android:layout_width="match_parent"
            android:layout_height="200dp" />
    
        <LinearLayout
            android:id="@+id/LinearLayout02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
            <Button
                android:id="@+id/Button03"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="播放视频"></Button>
    
            <Button
                android:id="@+id/Button04"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="停止播放"></Button>
        </LinearLayout>
    </LinearLayout>
    

    MainActivity代码:

    public class MainActivity extends AppCompatActivity {
    
        private MediaPlayer mMediaPlayerl;
        private Timer mTimer;
        private TimerTask mTimerTask;
        private boolean isChanging=false;//互斥变量,防止定时器与SeekBar拖动时进度冲突
    
        private Button btn_start_audio;
        private Button btn_stop_audio;
        private SeekBar skb_audio;
    
        private Button btn_start_video;
        private Button btn_stop_video;
        private SeekBar skb_video;
    
        private SurfaceView mSurfaceView;
        private SurfaceHolder mSurfaceHolder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            init();
        }
    
        private void init() {
            mMediaPlayerl = new MediaPlayer();
    
            /**
             * 播放结束之后提示
             */
            mMediaPlayerl.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    Toast.makeText(MainActivity.this, "结束", Toast.LENGTH_SHORT).show();
                    mMediaPlayerl.release();
                }
            });
    
            //----------定时器记录播放进度---------//
            mTimer = new Timer();
            mTimerTask = new TimerTask() {
                @Override
                public void run() {
                    if (isChanging == true){
                        return;
                    }
                    if (mMediaPlayerl.isPlaying()){
                        if (mMediaPlayerl.getVideoHeight() == 0){
                            skb_audio.setProgress(mMediaPlayerl.getCurrentPosition());
                        }else{
                            skb_video.setProgress(mMediaPlayerl.getCurrentPosition());
                        }
                    }
                }
            };
            mTimer.schedule(mTimerTask, 0, 10);
    
            btn_start_audio = (Button) this.findViewById(R.id.Button01);
            btn_stop_audio = (Button) this.findViewById(R.id.Button02);
            skb_audio=(SeekBar)this.findViewById(R.id.SeekBar01);
            //设置监听事件
            btn_start_audio.setOnClickListener(new ClickEvent());
            btn_stop_audio.setOnClickListener(new ClickEvent());
            skb_audio.setOnSeekBarChangeListener(new SeekBarChangeEvent());
    
            btn_start_video = (Button) this.findViewById(R.id.Button03);
            btn_stop_video = (Button) this.findViewById(R.id.Button04);
            skb_video=(SeekBar)this.findViewById(R.id.SeekBar02);
            //设置监听事件
            btn_start_video.setOnClickListener(new ClickEvent());
            btn_stop_video.setOnClickListener(new ClickEvent());
            skb_video.setOnSeekBarChangeListener(new SeekBarChangeEvent());
    
            mSurfaceView = (SurfaceView)findViewById(R.id.surfaceview01);
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.setFixedSize(100, 100);
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    
        /**
         * 按键事件处理
         */
        class ClickEvent implements View.OnClickListener{
    
            @Override
            public void onClick(View v) {
                if (v == btn_start_audio){
                    mMediaPlayerl.reset();//恢复到未初始化的状态
                    mMediaPlayerl = MediaPlayer.create(MainActivity.this,R.raw.cjyx);//读取音频文件
                    skb_audio.setMax(mMediaPlayerl.getDuration());//设置Seekbar的长度
                    try {
                        mMediaPlayerl.prepare();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (IllegalStateException e) {
                        e.printStackTrace();
                    }
                    mMediaPlayerl.start();
                }else if (v==btn_stop_audio || v==btn_stop_video){
                    mMediaPlayerl.stop();
                }else if (v == btn_start_video){
                    mMediaPlayerl.reset();//恢复到未初始化的状态
                    mMediaPlayerl =MediaPlayer.create(MainActivity.this,R.raw.cjyx);//读取视频
                    skb_video.setMax(mMediaPlayerl.getDuration());//设置SeekBar的长度
                    mMediaPlayerl.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    mMediaPlayerl.setDisplay(mSurfaceHolder);//设置屏幕
                    try {
                        mMediaPlayerl.prepare();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }catch (IllegalStateException e) {
                        e.printStackTrace();
                    }
                    mMediaPlayerl.start();
                }
            }
        }
    
        /**
         * 设置SeekBar的进度改变事件
         */
        class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener{
    
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    
            }
    
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                isChanging = true;
            }
    
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                mMediaPlayerl.seekTo(seekBar.getProgress());
                isChanging = false;
    
            }
        }
    }
    
    展开全文
  • Android MediaPlayer使用方法简单介绍
  • Android 多媒体MediaPlayer使用详解一、简介Mediaplayer可以用来控制音频或者视频文件、流的播放。

    Android 多媒体MediaPlayer使用详解


    一、简介

    Mediaplayer可以用来控制音频或者视频文件、流的播放。(MediaPlayer class can be used to control playback of audio/video files and streams. )

    这里是Android的官方API关于Mediaplayer的介绍:http://developers.androidcn.com/reference/android/media/MediaPlayer.html

    二、MediaPlayer支持的格式

    • H.263 3GPP(.3gp) and MPEG-4 (.mp4)
    • H.264 AVC 3GPP (.3gp) and MPEG-4 (.mp4)
    • MPEG-4 SP 3GPP (.3gp)

    三、MediaPlayer支持的格式生命周期

    Mediaplayer的生命周期图

    四、常用方法

    • 方法 说明
    • MediaPlayer 构造方法
    • create 创建一个要播放的多媒体
    • getCurrentPosition 得到当前播放位置
    • getDuration 得到文件的时间
    • getVideoHeight 得到视频的高度
    • getVideoWidth 得到视频的宽度
    • isLooping 是否循环播放
    • isPlaying 是否正在播放
    • pause 暂停
    • prepare 准备(同步)
    • prepareAsync 准备(异步)
    • release 释放MediaPlayer对象相关的资源
    • reset 重置MediaPlayer对象为刚刚创建的状态
    • seekTo 指定播放的位置(以毫秒为单位的时间)
    • setAudioStreamType 设置流媒体的类型
    • setDataSource 设置多媒体数据来源(位置)
    • setDisplay 设置用SurfaceHolder来显示多媒体
    • setLooping 设置是否循环播放
    • setOnButteringUpdateListener 网络流媒体的缓冲监听
    • setOnErrorListener 设置错误信息监听
    • setOnVideoSizeChangedListener 视频尺寸监听
    • setScreenOnWhilePlaying 设置是否使用SurfaceHolder来保持屏幕显示
    • setVolume 设置音量
    • start 开始播放
    • stop 停止播放

    1. 获取实例

    MediaPlayer mp = new MediaPlayer();  
    MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了
    

    2. 设置播放源

    MediaPlayer要播放的文件主要包括3个来源:
    a. 用户在应用中事先自带的resource资源
    例如:MediaPlayer.create(this, R.raw.test);
    b. 存储在SD卡或其他文件路径下的媒体文件
    例如:mp.setDataSource(“/sdcard/test.mp4”);
    c. 网络上的媒体文件
    例如:mp.setDataSource(“http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4“);

    3. 主要控制方法 ###

    prepare()和prepareAsync():提供了同步和异步两种方式设置播放器进入prepare状态,需要注意的是,如果MediaPlayer实例是由create方法创建的,那么第一次启动播放前不需要再调用prepare()了,因为create方法里已经调用过了。
    start():是真正启动文件播放的方法。
    pause()和stop():比较简单,起到暂停和停止播放的作用,
    seekTo():是定位方法,可以让播放器从指定的位置开始播放,需要注意的是该方法是个异步方法,也就是说该方法返回时并不意味着定位完成,尤其是播放的网络文件,真正定位完成时会触发OnSeekComplete.onSeekComplete(),如果需要是可以调用setOnSeekCompleteListener(OnSeekCompleteListener)设置监听器来处理的。
    release():可以释放播放器占用的资源,一旦确定不再使用播放器时应当尽早调用它释放资源。
    reset():可以使播放器从Error状态中恢复过来,重新会到Idle状态。

    4.常用监听事件

        mediaPlayer.setOnCompletionListener(this);      //播放完成监听--对应回调方法:onCompletion(MediaPlayer player)
        mediaPlayer.setOnErrorListener(this);           //播放异常监听--对应回调方法:onError(MediaPlayer player, int whatError, int extra)
        mediaPlayer.setOnInfoListener(this);            //当一些特定信息出现或者警告时监听--对应回调方法:onInfo(MediaPlayer player, int whatInfo, int extra)
        mediaPlayer.setOnPreparedListener(this);        //mediaplayer准备完成监听--对应回调方法:onPrepared(MediaPlayer player)
        mediaPlayer.setOnSeekCompleteListener(this);    //seek操作完成时监听--对应回调方法:onSeekComplete(MediaPlayer arg0)
        mediaPlayer.setOnVideoSizeChangedListener(this);//当video大小改变时监听--对应回调方法:onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2)
    

    视频播放Demo

    package com.devin.videodemo;
    
    import android.media.MediaPlayer;
    import android.os.Bundle;
    import android.os.Environment;
    import android.support.v7.app.AppCompatActivity;
    import android.view.Display;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.widget.LinearLayout;
    import android.widget.SeekBar;
    import android.widget.TextView;
    
    import java.io.IOException;
    
    public class MainActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener,
        MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener, SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener {
    private Display currDisplay;
    private SurfaceView surfaceView;
    private SeekBar seekBar;
    private TextView curTime;
    private TextView totalTime;
    private SurfaceHolder holder;
    private MediaPlayer player;
    private int vWidth, vHeight;
    
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.video_surface);
        init();
    }
    
    private void init() {
        surfaceView = (SurfaceView) findViewById(R.id.video_surface);
        seekBar = (SeekBar) findViewById(R.id.seekBar);
        curTime = (TextView) findViewById(R.id.curTime);
        totalTime = (TextView) findViewById(R.id.totalTime);
        //给SurfaceView添加CallBack监听
        holder = surfaceView.getHolder();
        holder.addCallback(this);
        //为了可以播放视频或者使用Camera预览,我们需要指定其Buffer类型
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        //下面开始实例化MediaPlayer对象
        player = new MediaPlayer();
        player.setOnCompletionListener(this);
        player.setOnErrorListener(this);
        player.setOnInfoListener(this);
        player.setOnPreparedListener(this);
        player.setOnSeekCompleteListener(this);
        player.setOnVideoSizeChangedListener(this);
        seekBar.setOnSeekBarChangeListener(this);
        Debug.d("Begin:::");
        //然后指定需要播放文件的路径,初始化MediaPlayer
        String dataPath = Environment.getExternalStorageDirectory().getPath() + "/test2.mp4";
        String url = "http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4";
        try {
            player.setDataSource(dataPath);
            //player.setDataSource(url);
            Debug.d("Next:::set play path");
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //然后,我们取得当前Display对象
        currDisplay = this.getWindowManager().getDefaultDisplay();
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // 当Surface尺寸等参数改变时触发
        Debug.d("Surface Change::surfaceChanged called");
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 当SurfaceView中的Surface被创建的时候被调用
    
        //在这里我们指定MediaPlayer在当前的Surface中进行播放
        player.setDisplay(holder);
        //在指定了MediaPlayer播放的容器后,我们就可以使用prepare(同步)或者prepareAsync(异步)来准备播放了
        player.prepareAsync();
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    
        Debug.d("Surface Destory:::surfaceDestroyed called");
    }
    
    
    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        // 当video大小改变时触发
        //这个方法在设置player的source后至少触发一次
        Debug.d("Video Size Change:::onVideoSizeChanged called");
    }
    
    @Override
    public void onSeekComplete(MediaPlayer mediaPlayer) {
        // seek操作完成时触发
        Debug.d("Seek Completion:::onSeekComplete called");
        curTime.setText(toTime(seekBar.getProgress()));
    }
    
    @Override
    public void onPrepared(MediaPlayer player) {
        // 当prepare完成后,该方法触发,在这里我们播放视频
    
        //首先取得video的宽和高
        vWidth = player.getVideoWidth();
        vHeight = player.getVideoHeight();
        int duration = player.getDuration();
    
        Debug.d("vWidth:" + vWidth + "----vHeight:" + vHeight);
        Debug.d("cWidth:" + currDisplay.getWidth() + "----cHeight:" + currDisplay.getHeight());
        Debug.d("VideoDuration:" + duration);
        seekBar.setMax(duration / 1000);//设置进度条
        totalTime.setText(toTime(duration / 1000));
    
        if (vWidth > currDisplay.getWidth() || vHeight > currDisplay.getHeight()) {
            //如果video的宽或者高超出了当前屏幕的大小,则要进行缩放
            float wRatio = (float) vWidth / (float) currDisplay.getWidth();
            float hRatio = (float) vHeight / (float) currDisplay.getHeight();
    
            //选择大的一个进行缩放
            float ratio = Math.max(wRatio, hRatio);
    
            vWidth = (int) Math.ceil((float) vWidth / ratio);
            vHeight = (int) Math.ceil((float) vHeight / ratio);
    
            //设置surfaceView的布局参数
            surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight));
        }
        //然后开始播放视频
        Debug.d("Video player.start");
        player.start();
    
        //设置进度条动态更新
        seekBar.postDelayed(runnable, 1000);
    }
    
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            seekBar.setProgress(seekBar.getProgress() + 1);
            curTime.setText(toTime(seekBar.getProgress()));
            if (seekBar.getProgress() < seekBar.getMax()) {
                seekBar.postDelayed(this, 1000);
            }
        }
    };
    
    @Override
    public boolean onInfo(MediaPlayer player, int whatInfo, int extra) {
        // 当一些特定信息出现或者警告时触发
        switch (whatInfo) {
            case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
                break;
            case MediaPlayer.MEDIA_INFO_METADATA_UPDATE:
                break;
            case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
                break;
            case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
                break;
        }
        return false;
    }
    
    @Override
    public boolean onError(MediaPlayer player, int whatError, int extra) {
        Debug.d("Play Error:::onError called");
        switch (whatError) {
            case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                Debug.d("Play Error:::media_error_server_died");
                break;
            case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                Debug.d("Play Error:::播放错误,未知错误");
                break;
            case MediaPlayer.MEDIA_ERROR_IO:
                Debug.d("Play Error:::media_error_io");
                break;
            case MediaPlayer.MEDIA_ERROR_MALFORMED:
                Debug.d("Play Error:::media_error_malformed");
                break;
            case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
                Debug.d("Play Error:::一般视频播放比较慢或视频本身有问题会引发");
                break;
            case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                Debug.d("Play Error:::media_error_timed_out");
                break;
            case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
                Debug.d("Play Error:::media_error_unsupported");
                break;
        }
        return false;
    }
    
    @Override
    public void onCompletion(MediaPlayer player) {
        // 当MediaPlayer播放完成后触发
        Debug.d("Play Over:::onCompletion called");
        if (player != null) {
            player.release();
            seekBar.removeCallbacks(runnable);
        }
    }
    
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        Debug.d("progress:" + progress);
        player.seekTo(progress * 1000);
    }
    
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    
    }
    
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    
    }
    
    
    @Override
    protected void onPause() {
        super.onPause();
        if (player.isPlaying()) {
            player.pause();
        }
    }
    
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (player != null) {
            player.stop();
            player.release();
            seekBar.removeCallbacks(runnable);
        }
    }
    
    private String toTime(int s) {
        long hour = s / 3600;
        long minute = s % 3600 / 60;
        long second = s % 60;
        String b = "";
        String c = "";
        String d = "";
        if (second < 10) {
            b = "0";
        }
        if (minute < 10) {
            c = "0";
        }
        if (hour < 10) {
            d = "0";
        }
        return d + hour + ":" + c + minute + ":" + b + second;
    }
    }
    

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="5">
    
    <SurfaceView
        android:id="@+id/video_surface"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2" />
    
    <android.support.v7.widget.AppCompatSeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp">
    
        <TextView
            android:id="@+id/totalTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:gravity="right"
            android:text="09:54" />
    
        <TextView
            android:id="@+id/curTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:gravity="right"
            android:text="09:54"
            android:textColor="#ff0000" />
    </RelativeLayout>
    

    展开全文
  • 转载:... Android MediaPlayer使用注意   (2013-01-28 00:20:02) 转载▼ 标签:  android   it   mediaplayer   视频   音频 分类:

    转载:http://blog.sina.com.cn/s/blog_6324d6990101dg3g.html

    Android MediaPlayer使用注意

     (2013-01-28 00:20:02)
    标签: 

    android

     

    it

     

    mediaplayer

     

    视频

     

    音频

    分类: android
    Android的多媒体框架包括支持播放多种常见的媒体类型,使您可以轻松地把音频、视频和图像集成到你的应用。你可以播放音频或视频媒体文件,这些文件是存储在你的应用程序的资源文件中的。应用程序的资源文件可以是文件系统中独立的文件,或通过网络连接获取的一个数据流,所有使用MediaPlayer APIS的资源文件。
    1.
    注意:如果你通过一个URL来获取一个在线媒体文件,该文件必须能够支持渐进式下载。
    2.
    警告:当你使用setDataSource()方法时,必须捕捉或通过非法数据异常和输入输出异常,因为正在被你引用的文件可能不存在在. 
    3.

    异步准备 - Asynchronous Preparation

    使用MediaPlayer 的原则很简单。然而,重要的是要记住,有必要将更多的一些东西正确地集成到一个典型的Android应用程序。比如,调用prepare()方法可能需要较长的时间来执行,因为它可能涉及获取和解码媒体数据。因此,如同任何方法,可能需要很长时间执行,你不应该从应用程序的UI线程调用它。这样做将导致UI挂到方法返回,这是一个非常糟糕的用户体验,也可能会引起应用程序没有响应的错误。 即使你预期你的资源能快速加载,记住,任何超过十分之一秒的反应在界面上会造成明显的停顿,将导致给用户的印象是:你的应用程序是缓慢的。 
    为了避免你的UI线程挂起,产生另一个线程准备MediaPlayer 当完成时通知主线程。你可以写自己的线程的逻辑,框架提供prepareAsync() 方法,方便的使用MediaPlayer 。该方法在后台开始准备媒体并立即返回。当媒体准备好了,MediaPlayer.OnPreparedListeneronPrepared 方法,通过配置setonpreparedlistener()方法来调用。

    4.

     

    状态管理 - Managing State

    关于MediaPlayer ,你需要记住的另一点是它的状态。即,在你编写自己的代码的时候,必须时刻意识到MediaPlayer 有一个内部状态,因为 只有当玩家在特定状态,某些特定的操作才会有效。如果您在错误的状态执行一个操作,系统可能会抛出一个异常或引起其它令人不快的行为。 
    MediaPlayer 类里有文件显示一个完整的状态转换图,阐明哪些方法可以把MediaPlayer 从一个状态改变到另一个状态。例如,当您创建一个新的MediaPlayer ,它就处于闲置状态。这时,你应该调用android.net.Uri) setDataSource()方法来初始化它,把它设置为初始化状态。然后,你必须使用prepare()方法或prepareAsync()方法。当MediaPlayer 准备好了,它将进入准备状态,这就意味着你可以调用start()方法来播放媒体。另外,在状态转换图上阐明了,你可以调用start(),pause()和 seekTo()这些方法在Started,Paused和PlaybackCompleted状态之间进行转换。如果您调用stop()方法,这时请注意,你需要再次准备MediaPlayer ,才可以再一次调用start()方法。 
    在编写代码与MediaPlayer 对象交互时,心里要随时想着状态转换图,因为从错误的状态调用它的方法,是引起错误的常见原因。

    释放MediaPlayer-Releasing the MediaPlayer

    MediaPlayer 会消耗宝贵的系统资源。因此 ,你应该经常采取额外的预防措施来确保及时把不需要的MediaPlayer 取消掉。您需要调用release() 方法来确保系统分配给它的资源正确释放。例如,您正在使用MediaPlayer ,同时,你的活动调用onStop()方法,这时你必须释放MediaPlayer,因为你的活动并非与用户交互,留着它没什么意义(除非你是在后台播放多媒体,这是下一节中将讨论的内容)。当你的活动恢复或者重新启动,恢复播放之前,您需要创建一个新的MediaPlayer并且重新准备。 
    下面是释放和取消你的MediaPlayer的方法:

    mediaPlayer.release(); mediaPlayer = null;

    作为思考题,考虑一下如果当活动停止的时候你忘了释放MediaPlayer,活动重启后新建一个MediaPlayer,可能会发生的问题。正如你可能知道的,当用户更改屏幕的方向(或以另一种方式更改设备配置),该系统通过重启活动处理(通过默认方式),所以当用户频繁在纵向和横向之间切换时,你可能会很快消耗掉所有的系统资源,原因是你没有释放方向变化时各个方向上创建的新MediaPlayer。(更多关于运行时重启的资料,请查看Handling Runtime Changes)。 
    你可能会想知道在用户离开活动时后台继续播放媒体是如何实现的,采用同样的方式实现的,如内置的音乐应用程序的行为。在这种情况下,你
    需要通过一个Service来控制MediaPlayer,所以我们开始学习Using a Service with MediaPlayer

    5.

     

    使用服务控制MediaPlayer - Using a Service with MediaPlayer

    如果你希望后台播放媒体,你希望用户操作其他应用时继续播放,你必须开始一个Service并且从那里控制MediaPlayer实例。你必须慎重考虑这个设置,因为用户与系统期望应用程序运行的后台服务应该与系统的其余部分相互作用。如果应用程序不满足这些预期,就不能有良好的用户体验。本节介绍的主要内容是:告诉你相关知识,并提供建议如何接触它们。

    异步运行 - Running asynchronously

    首先,如一个Activity,服务里的所有任务默认在单一线程中完成。如果你从同一个应用程序里运行一个Activity和一个Service,它们默认使用相同的线程(“主线程”)。因此,Service需要迅速处理传入的意图并且响应它们的时候从不执行冗长的计算。如果预计调用一些复杂的任务或阻塞,你必须异步处理这些任务:由另一个线程自己实现自己,或使用框架处理异步。 
    例如,当你从主要线程使用一个MediaPlayer ,你应该调用prepareAsync()方法而不是prepare() 方法,实现MediaPlayer.OnPreparedListener,以便当你准备工作完毕后,得到可以开始播放的通知。 
    代码如下:

    public class MyService extends Service implements MediaPlayer.OnPreparedListener 
    { private static final ACTION_PLAY = "com.example.action.PLAY"
     MediaPlayer mMediaPlayer = null;  
      public int onStartCommand(Intent intent, int flags, int startId) 
    { ... if (intent.getAction().equals(ACTION_PLAY))
    { mMediaPlayer = ... // initialize it here
    mMediaPlayer.setOnPreparedListener(this)
     mMediaPlayer.prepareAsync()// prepare async to not block main thread 
      }
    }  
      public void onPrepared(MediaPlayer player)
    { player.start();
      } }

    处理异步错误 - Handling asynchronous errors

    在同步操作中,错误通常会出现异常或错误代码信息。但当你使用异步资源时,您需要确保您的应用程序有错误提示,在MediaPlayer 中,要做到这一点,可以通过实现MediaPlayer.OnErrorListener,并且将它设置在你的MediaPlayer 实体中。

    public class MyService extends Service implements MediaPlayer.OnErrorListener { MediaPlayer mMediaPlayer; public void initMediaPlayer() { // ...initialize the MediaPlayer here...  mMediaPlayer.setOnErrorListener(this)} @Override public boolean onError(MediaPlayer mp, intwhat, int extra) { // ... react appropriately ... // The MediaPlayer has moved to the Error state, must be reset! } }

    请牢记,当出现错误,将这个MediaPlayer 设置为错误状态(请参考MediaPlayer 类文档的完整的状态关系图)您再次使用它之前,必须重置这个状态。

    使用唤醒锁 - Using wake locks

    应用程序在后台播放媒体,其服务在运行期间,设备可能会进入休眠状态。因为Android系统希望在设备休眠时节省电池。系统试图关闭手机的应用程序,是没有必要的,包括CPU和WiFi硬件。但是,如果你的服务正在运行或播放着音乐,你希望防止系统干扰你的回放。 
    为了确保您的服务在这些条件下能继续运行,你需要使用“wake locks”。唤醒锁是一种信号系统,它发出信号,显示:应用程序正在使用或可用的功能,或手机闲置。

    注意:你应该尽量少用唤醒锁,只有在必要时候才使用它们。它们会使设备的电池寿命大大降低。

    MediaPlayer 正在播放时,需要确保CPU持续运行,当初始化你的MediaPlayer时,调用setWakeMode()方法。一旦你这样做了,当暂停或停止时候,MediaPlayer 持有指定的锁:

    mMediaPlayer = new MediaPlayer()// ... other initialization here ...mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

    在这个例子中获得唤醒锁是指在保证CPU在唤醒状态。当你通过网络获取媒体和您正在使用WiFi时,你可能希望有个WifiLock,可以手动获取并释放。当你开始通过远程URL准备MediaPlayer,你应该创建并获得wi - fi锁。 代码如下:

    WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL"mylock"); wifiLock.acquire();

    当你暂停或停止你的媒体时,或当你不再需要这样的网络,你应该释放该锁: 代码如下:

    wifiLock.release();

    作为前景服务运行 - Running as a foreground service

    服务通常用于执行后台任务,例如获取电子邮件,同步数据,下载内容,或其他。在这些情况下,用户不会意识到这个服务的执行,甚至可能不会注意到这些服务被打断,后来重新启动。毫无疑问,后台播放音乐是一个服务,用户能意识到,任何中断都会严重影响到用户体验。此外,用户可能会希望在这个服务执行期间作用于它。这种情况,服务应该运行一个“前景服务”。前台服务在系统中持有一个更高水平的重要性,系统几乎从未将服务扼杀,因为它对用户有着直接的重要性。当应用在前台运行,该服务还必须提供一个状态栏来通知用户意识有服务正在运行同时允许他们打开一个活动,可以与服务进行交互。
    为了把你的服务变为前景服务,您必须为状态栏创建一个Notification,并且从Service调用startForeground()方法。
    代码如下:

    String songName; // assign the song name to songNamePendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); Notification notification = newNotification(); notification.tickerText = text; notification.icon = R.drawable.play0; notification.flags |= Notification.FLAG_ONGOING_EVENT; notification.setLatestEventInfo(getApplicationContext()"MusicPlayerSample""Playing: " + songName, pi); startForeground(NOTIFICATION_ID, notification);

    通知区域可见的设备告诉你,服务在前台运行。如果用户选择了这个通知,系统将调用你提供的PendingIntent。在上面的例子中,它打开了一个Activity。(MainActivity) 
    图1显示了如何将通知呈现给用户: 
    Img1.png        Img2.png 
    图1:界面的一个前景服务通知,如上图,显示通知图标(在左)、扩展视图(在右)。
    实际执行一些用户能够意识到的服务时,你应该保留“foreground service”的状态。相反情况下,你应该调用stopForeground()方法来释放它。 代码如下:

    stopForeground(true);

    更多信息,请参考Service和 Status Bar Notifications的相关文档。

    处理音频焦点 - Handling audio focus=

    在给定的时间尽管只有一个活动可以运行,但Android是一个多任务环境。这对应用程序使用音频 造成了一个特别大的难度,由于只有一个音频输出,可能会有好几个媒体服务争夺使用它。Android 2.2之前,没有内置机制来解决这个问题,这可能在某些情况下导致糟糕的用户体验。例如,一个用户正在听音乐,同时,另一个应用程序有很重要的事需要通知用户,由于吵闹的音乐用户可能不会听到提示音。从Android 2.2开始,Android平台为应用程序提供了一个方式来协商设备的音频输出。这个机制被称为音频焦点。 
    当您的应用程序需要输出音频如音乐或一个通知,这时你就必须请求音频焦点。一旦得到焦点,它就可以自由的使用声音输出设备,同时它会不断监听焦点的更改。如果它被通知已经失去了音频焦点,它会要么立即杀死音频或立即降低到一个安静的水平(被称为“ducking”——有一个标记,指示哪一个是适当的)当它再次接收焦点时,继续不断播放。
    音频焦点是自然的合作。应用程序都期望(强烈鼓励)遵守音频焦点指南,但规则并不是系统强制执行的。如果应用程序失去音频焦点后想要播放嘈杂的音乐,在系统中没有什么会阻止他。然而,这样可能会让用户有更糟糕的体验,并可能卸载这运行不当的应用程序。
    请求音频焦点,您必须从AudioManager调用requestAudioFocus()方法,下面展示一个例子:

    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE)int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);  if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // could not get audio focus.}

    requestAudioFocus()的第一个参数是AudioManager.OnAudioFocusChangeListener,每当音频焦点有变动的时候其onAudioFocusChange()方法被调用。您还应该在你的服务和活动上实现这个接口。 
    代码如下:

    class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // ....public void onAudioFocusChange(int focusChange) { // Do something based on focus change... } }

    focusChange 参数告诉你音频焦点是如何改变的,并且可以使用以下的值之一(他们都是在AudioManager中定义常量的):

    • AUDIOFOCUS_GAIN: 你已经得到了音频焦点。
    • AUDIOFOCUS_LOSS: 你已经失去了音频焦点很长时间了。你必须停止所有的音频播放。因为你应该不希望长时间等待焦点返回,这将是你尽可能清除你的资源的一个好地方。例如,你应该释放MediaPlayer
    • AUDIOFOCUS_LOSS_TRANSIENT:你暂时失去了音频焦点,但很快会重新得到焦点。你必须停止所有的音频播放,但是你可以保持你的资源,因为你可能很快会重新获得焦点。
    • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 你暂时失去了音频焦点,但你可以小声地继续播放音频(低音量)而不是完全扼杀音频。

    下面是一个示例实现:

    public void onAudioFocusChange(int focusChange) { switch (focusChange) { caseAudioManager.AUDIOFOCUS_GAIN// resume playback if (mMediaPlayer == null) initMediaPlayer()elseif (!mMediaPlayer.isPlaying()) mMediaPlayer.start(); mMediaPlayer.setVolume(1.0f, 1.0f)break;case AudioManager.AUDIOFOCUS_LOSS// Lost focus for an unbounded amount of time: stop playback and release media player if (mMediaPlayer.isPlaying()) mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = nullbreakcase AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:// Lost focus for a short time, but we have to stop // playback. We don't release the media player because playback // is likely to resume if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();breakcase AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK// Lost focus for a short time, but it's ok to keep playing // at an attenuated level if (mMediaPlayer.isPlaying())mMediaPlayer.setVolume(0.1f, 0.1f)break} }

    记住,音频焦点APIs在API级别8(Android 2.2)及以上才有效。所以如果你想要支持的以前版本的Android,(如果有的话)你应该采取一种向后兼容性策略,允许您使用该特性,(如果没有的话),只能选择8以后的版本。
    通过反射调用音频焦点方法或通过在一个单独类中实现所有的音频焦点特性,您可以实现向后兼容性(AudioFocusHelper 中阐明)。下面是这样一个类的示例:

    public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener { AudioManager mAudioManager; // other fields here, you'll probably hold a reference to an interface // that you can use to communicate the focus changes to your Service   public AudioFocusHelper(Context ctx,) { mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)// ... }  public boolean requestFocus() { return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN)}   public boolean abandonFocus() { returnAudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAudioManager.abandonAudioFocus(this)}   @Overridepublic void onAudioFocusChange(int focusChange) { // let your service know about the focus change} }

    当你发现系统运行时API级别在8级或以上时,您可以创建AudioFocusHelper 类的一个实例,例如:

    if (android.os.Build.VERSION.SDK_INT >= 8) { mAudioFocusHelper = newAudioFocusHelper(getApplicationContext()this)} else { mAudioFocusHelper = null}

    执行清理 - Performing cleanup

    正如前面所提到的,MediaPlayer 对象会消耗大量的系统资源,所以你可以在你需要用他的时候保留他,当你不需要他的时候调用release() 方法。调用这个显式地清除方法是重要的,而不是依赖于系统的垃圾收集,因为它可能需要一些时间垃圾收集器才能收回MediaPlayer ,因为这只是内存敏感的需求而不是其他媒体资源的短缺。既然如此,当你使用一个服务时,你应该覆盖onDestroy()方法,来确定你的MediaPlayer释放了。

    代码如下:

      public class MyService extends Service { MediaPlayer mMediaPlayer; // ...   @Override publicvoid onDestroy() { if (mMediaPlayer != null) mMediaPlayer.release()} }

    你最好始终寻找其它机会来释放你的MediaPlayer,关闭的时候就释放掉。例如,如果你期望较长的一段时间不能够播放媒体(例如,失去音频焦点后),你肯定得先释放你现有的MediaPlayer ,以后要用的时候再创建它。另一方面,如果你只希望停止播放很短的一段时间,你应该尽量保留你的MediaPlayer,以免花费时间重新创建和准备一遍。

    处理AUDIO_BECOMING_NOISY意图 - Handling the AUDIO_BECOMING_NOISY Intent

    许多编写良好的应用程序有以下特点,当一个事件导致音频变得聒噪时,自动停止音频播放。(通过外部扬声器输出)。例如,一个用户戴着耳机听音乐,可能会不小心切断耳机和设备的链接。虽然,这种行为不会自动发生。如果您没有实现这个特性,设备的外部扬声器会将音频播放出来,这可能是用户不希望发生的。
    这些情况下通过处理ACTION_AUDIO_BECOMING_NOISY意图,可以让你的应用程序停止播放音乐,通过在你的manifest里添加以下代码,你可以注册一个接收器:

    ".MusicIntentReceiver"> "android.media.AUDIO_BECOMING_NOISY" />

    注册MusicIntentReceiver 类当作一个广播接收器的意图,然后您应该实现这类,代码如下:

    public class MusicIntentReceiver implements android.content.BroadcastReceiver { @Overridepublic void onReceive(Context ctx, Intent intent) { if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { // signal your service to stop playback// (via an Intent, for instance) } } }

    从内容解析器检索媒体 - Retrieving Media from a Content Resolver

    在媒体播放器应用程序中,另一个可能有用的特性是用户可以在设备上检索音乐。你可以通过为外部媒体查询ContentResolver,代码如下:

    ContentResolver contentResolver = getContentResolver(); Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URICursor cursor = contentResolver.query(uri, nullnullnullnull)if (cursor == null) { // query failed, handle error. } else if (!cursor.moveToFirst()) { // no media on the device } else { inttitleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)do { long thisId = cursor.getLong(idColumn)String thisTitle = cursor.getString(titleColumn)// ...process entry... } while (cursor.moveToNext())}

    要和MediaPlayer一起使用,你可以这样做,代码如下:

    long id = ; Uri contentUri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id); mMediaPlayer = newMediaPlayer(); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setDataSource(getApplicationContext(), contentUri);   // ...prepare and start...

    展开全文
  • MediaPlayer使用setVolem调整音量大小无效的解决方法 private MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); mediaPlayer.setDataSource...

    MediaPlayer使用setVolem调整音量大小无效的解决方法

    private MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
    mediaPlayer.setDataSource(MainActivity.this, Settings.System.DEFAULT_NOTIFICATION_URI);
    mediaPlayer.prepareAsync();
    mediaPlayer.setVolume(1.0f,1.0f);
    mediaPlayer.start();
    

    由于我要使用系统Notification的资源铃声,所以setAudioStreamType参数为AudioManager.STREAM_NOTIFICATION, 后续使用setVolume后就生效了

    注意:使用系统资源如通知,闹钟的铃声时setAudioStreamType设置
    AudioManager.STREAM_MUSIC后 再设置 声音大小是不生效的
    AudioManager下还有很多,具体可一看AudioManager.java源码

    展开全文
  • Android MediaPlayer使用之网络访问异常

    千次阅读 2019-04-03 20:37:48
    Android MediaPlayer使用之网络访问异常 1.问题描述 2019-04-02 21:26:15.552 22138-22138/com.uyeh.mediaplayertest D/MainActivity: onClick: play 2019-04-02 21:26:15.568 22138-22138/...
  • GDI绘制时钟,mediaplayer使用,秒表等,以及如何设置铃声,如何更改当前时间。由于timer短计时不精确,故采用系统毫秒数优化。
  • MediaPlayer使用总结

    2015-10-13 16:50:59
    MediaPlayer类可用于控制音频...关于如何使用这个类的方法还可以阅读VideoView类的文档。 1.状态图 对播放音频/视频文件和流的控制是通过一个状态机来管理的。下图显示一个MediaPlayer对象被支持的播放控
  • android MediaPlayer使用

    2013-06-07 10:20:46
    1)如何获得MediaPlayer实例:  可以使用直接new的方式:  MediaPlayer mp = new MediaPlayer();  也可以使用create的方式,如: MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用...
  • Android MediaPlayer使用小结,包括具体流程以及注意事项
  • MediaPlayer类是Android开发中用于控制音频/视频文件和流的播放。
  • Android -- 多媒体播放之MediaPlayer使用内部实现简析 转载于:https://www.cnblogs.com/lipeineng/p/9894703.html
  • ASP.Net的MediaPlayer使用

    2017-11-28 10:17:54
    直接引用dll,MediaSource设置文件路径,MediaSkinSource设置控件外观
  • 1)如何获得MediaPlayer实例: 可以使用直接new的方式: MediaPlayer mp = new MediaPlayer(); 也可以使用create的方式,如: MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用...
  • Android开发之MediaPlayer使用

    千次阅读 2018-03-28 11:42:56
    MediaPlayer MediaPlayer是Android系统自带的,可以用来播放音频、视频和流媒体。MediaPlayer包含了Audio和Video的播放功 常用方法 方法 说明 create 创建一多媒体 getCurrentPosition 当前播放位置 ...
  • android的mediaPlayer使用

    2016-09-18 13:21:25
    应用程序的资源文件可以是文件系统中独立的文件,或通过网络连接获取的一个数据流,所有使用MediaPlayer APIS的资源文件。 1. 注意:如果你通过一个URL来获取一个在线媒体文件,该文件必须能够支持渐进式
  • 1 介绍MediaPlayer类是Android开发中用于控制音频/视频文件和流的播放。 下图显示了MediaPlayer对象的生命周期和状态。 椭圆表示MediaPlayer对象可能驻留的状态。弧表示驱动对象状态转换的回放控制操作。 有两种...
  • 视频播放有声音没图像也许是在使用MediaPlayer最容易出现的问题,几乎所有使用MediaPlayer的新手都会遇到。视频播放的图像呈现需要一个载体,需要利用MediaPlayer.setDisplay设置一个展示视频画面的SurfaceHolder,...
  • 应用程序的资源文件可以是文件系统中独立的文件,或通过网络连接获取的一个数据流,所有使用MediaPlayer APIS的资源文件。 1. 注意:如果你通过一个URL来获取一个在线媒体文件,该文件必须能够支持渐进式下载。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,874
精华内容 1,549
关键字:

mediaplayer使用