android播放音频

来源:互联网 发布:云内动力网络商学院 编辑:程序博客网 时间:2024/04/30 03:05

最近需要项目涉及到了音频播放功能,有可能需要在后台播放,并且在通知栏显示状态。通过查阅资料,自己模拟了一个demo。样式如下:

这里写图片描述

这里写图片描述

在运行中,界面内的控件更新使用的是eventBus发送的,在Notification中,是通过广播发送操作,目前只加入了播放和暂停的功能。
首先是在MainActivity注册的广播和Notification,全部设置为静态的,广播是写在了播放界面

    public BPlayActivity.MusicServiceReceiver mr;    public static NotificationManager manager;    public static RemoteViews remoteViews;    public static Notification notify;    // 广播监听的动作    public static final String ACTION_BF = "ACTION_BF";    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        initData();        showStartNotification();    }    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)    public void showStartNotification() {        // 注册receiver        mr = new BPlayActivity().getReceiver();        IntentFilter intentfilter = new IntentFilter();        intentfilter.addAction(ACTION_BF);        registerReceiver(mr, intentfilter);        manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);        notify = builder.build();        remoteViews = new RemoteViews(this.getPackageName(), R.layout.layout_view_title);        notify.contentView = remoteViews; // 设置下拉图标        notify.bigContentView = remoteViews; // 防止显示不完全,需要添加apisupport        notify.flags = Notification.FLAG_ONGOING_EVENT;        notify.icon = R.drawable.img_reward_bg_down;        Intent intent1 = new Intent();        intent1.setAction(ACTION_BF);        PendingIntent contentIntent = PendingIntent.getBroadcast(this, 0,                intent1, 0);        remoteViews.setOnClickPendingIntent(R.id.iv_notify_play, contentIntent);    }

在BPlayActivity.class 播放界面,使用了SeekBar和自定义的MediaPlayer。

public class MyPlay implements MediaPlayer.OnBufferingUpdateListener,        MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener,        MediaPlayer.OnErrorListener {    public static SeekBar skbProgress;    private Timer mTimer = new Timer();    public static MediaPlayer mediaPlayer;    private static onShowTimeListener listener;    /**     * 0未播放     * 1播放     * 2暂停     */    public static int playState = 0;    public interface onShowTimeListener {        public void showTime(long time, long endtime);    }    public MyPlay(SeekBar skbProgress, onShowTimeListener showTimeListener) {        skbProgress.setClickable(false);        listener = showTimeListener;        setSkbProgress(skbProgress);        if (mediaPlayer == null) {            mediaPlayer = new MediaPlayer();        }        mTimer.schedule(mTimerTask, 0, 300);        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);        mediaPlayer.setOnBufferingUpdateListener(this);        mediaPlayer.setOnPreparedListener(this);//        skbProgress.setOnSeekBarChangeListener(this);    }    public void play() {        playState = 1;        mediaPlayer.start();    }    public static void setSkbProgress(SeekBar skbProgre) {        skbProgress = skbProgre;        skbProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {                if (mediaPlayer != null) {                    progress = i * mediaPlayer.getDuration()                            / seekBar.getMax();                }            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {                Log.i("msg", "onStartTrackingTouch");            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {                if (mediaPlayer != null) {                    mediaPlayer.seekTo(progress);                    Log.i("msg", "progress==" + progress);                    if (progress == mediaPlayer.getDuration()) {                        playState = 0;                        if (listener != null)                            listener.showTime(progress, progress);                    }                }            }        });    }    public void playUrl(String videoUrl) {        try {            mediaPlayer.reset();            mediaPlayer.setDataSource(videoUrl);            mediaPlayer.prepare();//prepare之后自动播放            play();            skbProgress.setClickable(true);        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalStateException e) {            e.printStackTrace();        } catch (IOException e) {            ToastBean bean = new ToastBean();            bean.setMsg("音频地址错误");            EventBus.getDefault().post(bean);            e.printStackTrace();        } catch (Exception e) {            e.printStackTrace();        }    }    public void pause() {        playState = 2;        mediaPlayer.pause();    }    public void stop() {        if (mediaPlayer != null) {            mediaPlayer.stop();            playState = 0;            mediaPlayer.release();            mediaPlayer = null;        }    }    /*******************************************************     * 通过定时器和Handler来更新进度条     ******************************************************/    TimerTask mTimerTask = new TimerTask() {        @Override        public void run() {            if (mediaPlayer == null)                return;            try {                if (mediaPlayer.isPlaying() && skbProgress.isPressed() == false) {                    handleProgress.sendEmptyMessage(0);                }            } catch (Exception e) {            }        }    };    Handler handleProgress = new Handler(Looper.getMainLooper()) {        public void handleMessage(Message msg) {            if (mediaPlayer != null) {                int position = mediaPlayer.getCurrentPosition();                int duration = mediaPlayer.getDuration();                if (duration > 0) {                    long pos = skbProgress.getMax() * position / duration;                    TimeBean bean = new TimeBean();                    bean.setPos(pos);                    EventBus.getDefault().post(bean);                }                if (listener != null)                    listener.showTime(position, duration);            }        }    };    @Override    public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {        skbProgress.setSecondaryProgress(i);        if (mediaPlayer.getDuration() != 0) {            int currentProgress = skbProgress.getMax() * mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration();        }    }    @Override    public void onCompletion(MediaPlayer mediaPlayer) {    }    @Override    public void onPrepared(MediaPlayer mediaPlayer) {        mediaPlayer.start();        playState = 1;    }    @Override    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {        return false;    }    //返回播放状态    public int isPalyState() {        return playState;    }    static int progress;}

在播放界面首相注册EventBus

    private static ItemData intentBean;    private ImageView iv_play;    private TextView tv_starttime;    private TextView tv_endtime;    private static SeekBar sb_play;    private ImageView iv_roat;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_bplay);        EventBus.getDefault().register(this);        intentBean = (ItemData) getIntent().getSerializableExtra("selList");        initView();        initData();    }//因为是用过列表点击进入的,这里判断了进入的时候是否在播放,如果是相同的就同步时间,如果不同,就将seekBar设置为0,//音频继续播,知道点击了播放按钮,在请求另一个地址的音频进行播放,时间重置   private void initData() {        if (PlayService.mPlay != null) {            if (PlayService.playId == intentBean.getId()) {                MyPlay.setSkbProgress(sb_play);                //初始进入,判断是不是当前播放的Id                if (PlayService.mPlay.mediaPlayer.isPlaying()) {                    iv_play.setSelected(true);                    if (notify != null) {                        notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play_stop);                        manager.notify(0, notify);                    }                    setAnim(true);                }            }        }    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.iv_play:                //显示通知栏Notification                manager.notify(0, notify);                startService();                break;        }    }//这里的context使用的是Application的 public void startService() {        PlayService.sb_play = sb_play;        Intent intent = null;        intent = new Intent(MyApplication.getContext(), PlayService.class);        intent.putExtra("intentBean", intentBean);        MyApplication.getContext().startService(intent);    }//设置中间的原图播放旋转效果    private boolean isAnimStart = false;    ObjectAnimator rotate = null;    Float currentValue = 0f;    public void setAnim(boolean state) {        if (state) {            if (!isAnimStart) {                isAnimStart = true;                rotate = ObjectAnimator.ofFloat(iv_roat, "Rotation",                        currentValue - 360, currentValue);                // 设置持续时间                rotate.setDuration(3000);                // 设置循环播放                rotate.setRepeatCount(ObjectAnimator.INFINITE);                rotate.setInterpolator(new LinearInterpolator());//not stop                rotate.setRepeatCount(-1);//set repeat time forever                rotate.start();                rotate.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        // 监听动画执行的位置,以便下次开始时,从当前位置开始                        currentValue = (Float) animation.getAnimatedValue();                    }                });            }        } else {            isAnimStart = false;            if (rotate != null)                rotate.cancel();        }    }   /**     * 在主线程中显示当前的控件状态     */    @Subscribe(threadMode = ThreadMode.MainThread)    public void EventUpdateTime(UpdateTimeBean bean) {        if (tv_starttime == null || tv_endtime == null) {            return;        }        if (PlayService.playId == intentBean.getId()) {            tv_starttime.setText(DateUtil.setHmsQian(bean.getStartTime()));            tv_endtime.setText(DateUtil.setHmsQian(bean.getEndTime()));            if (DateUtil.setHmsQian(bean.getStartTime()).equals(DateUtil.setHmsQian(bean.getEndTime()))) {                //说明是播放完成了                iv_play.setSelected(false);                if (notify != null) {                    notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play);                    manager.notify(0, notify);                }                setAnim(false);            }        }    }    /**     * 在主线程中显示当前的控件状态     */    @Subscribe(threadMode = ThreadMode.MainThread)    public void EventPlayState(BPlayStateBean bean) {        if (iv_play == null) {            return;        }        if (bean.isSelect()) {            iv_play.setSelected(true);            if (notify != null) {                notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play_stop);                manager.notify(0, notify);            }            setAnim(true);        } else {            iv_play.setSelected(false);            if (notify != null) {                notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play);                manager.notify(0, notify);            }            setAnim(false);        }    }    /**     * 设置seekVar的显示状态     *     * @param bean     */    @Subscribe(threadMode = ThreadMode.MainThread)    public void EventPlayState(TimeBean bean) {        if (PlayService.playId == intentBean.getId() && sb_play != null) {            sb_play.setProgress((int) bean.getPos());        }    }    /**     * 返回错误提示     *     * @param bean     */    @Subscribe(threadMode = ThreadMode.MainThread)    public void EventMsg(ToastBean bean) {        Toast.makeText(this, bean.getMsg(), Toast.LENGTH_LONG).show();    }    @Override    protected void onDestroy() {        super.onDestroy();        EventBus.getDefault().unregister(this);    }    public MusicServiceReceiver getReceiver() {        return new MusicServiceReceiver();    }    class MusicServiceReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context arg0, Intent arg1) {            manager.notify(0, notify);            startService();        }    }

再通过一个Service播放音频

public class PlayService extends IntentService {    public static MyPlay mPlay;    public static SeekBar sb_play;    private ItemData intentBean;    public static int playId = -1;    public static int intentId = -1;    public PlayService() {        super("PlayService");    }    @Override    protected void onHandleIntent(@Nullable Intent intent) {        if (intent != null) {            intentBean = (ItemData) intent.getSerializableExtra("intentBean");            intentId = intentBean.getId();            if (intentId != playId && mPlay != null) {                //说明是不同的列表,将当前的清空,再进行播放,相同的话,就设置当前的Post                mPlay.stop();                mPlay = null;            }            if (mPlay == null) {                mPlay = new MyPlay(sb_play, new MyPlay.onShowTimeListener() {                    @Override                    public void showTime(long time, long endtime) {                        if (DateUtil.setHmsQian(time).equals(DateUtil.setHmsQian(endtime))) {                            //说明是播放完成了                            mPlay.playState = 0;                        }                        UpdateTimeBean updateTimeBean = new UpdateTimeBean();                        updateTimeBean.setStartTime(time);                        updateTimeBean.setEndTime(endtime);                        EventBus.getDefault().post(updateTimeBean);                    }                });            }            playId = intentBean.getId();            if (mPlay.isPalyState() == 0) {                thread.start();            } else if (mPlay.isPalyState() == 1) {                mPlay.pause();                setState(false);                if (notify != null) {                    notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play);                    manager.notify(0, notify);                }            } else {                mPlay.play();                setState(true);                if (notify != null) {                    notify.contentView.setImageViewResource(R.id.iv_notify_play, R.drawable.img_play_stop);                    manager.notify(0, notify);                }            }        }    }    public void setState(boolean state) {        BPlayStateBean bean = new BPlayStateBean();        bean.setSelect(state);        EventBus.getDefault().post(bean);    }    Thread thread = new Thread(new Runnable() {        @Override        public void run() {            if (!TextUtils.isEmpty(intentBean.getUrl()) && mPlay != null) {                mPlay.playUrl(intentBean.getUrl());                if (mPlay.isPalyState() == 1) {                    setState(true);                } else {                    setState(false);                }            } else {                showMessage("该音频为空");            }        }    });    private void showMessage(String msg) {        ToastBean bean = new ToastBean();        bean.setMsg(msg);        EventBus.getDefault().post(bean);    }}

//在DateUtil中转换时间

 /**     * 给一个时间,然后算出总长度hms/1000     **/    public static String setHmsQian(long time) {        long hour = (time / (60 * 60 * 1000));        long min = ((time / (60 * 1000)) - hour * 60);        long s = (time / 1000 - hour * 60 * 60 - min * 60);        String str_s = s + "";        String str_m = min + "";        String str_h = hour + "";        if (min < 10) {            str_m = "0" + min;        }        if (s < 10) {            str_s = "0" + s;        }        if (hour < 10) {            str_h = "0" + hour;        }        if (hour <= 0) {            return str_m + ":" + str_s;        } else {            return str_h + ":" + str_m + ":" + str_s;        }    }

播放界面的布局文件

<?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:background="#008888"    android:gravity="center_horizontal"    android:orientation="vertical">    <SeekBar        android:id="@+id/sb_play"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="10dp"        android:maxHeight="1dp"        android:progressDrawable="@color/white"        android:thumbTint="@color/c_ff7a7a" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="10dp"        android:orientation="horizontal"        android:paddingLeft="12dp"        android:paddingRight="12dp">        <TextView            android:id="@+id/tv_starttime"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="00:00"            android:textColor="@color/white"            android:textSize="13sp" />        <TextView            android:id="@+id/tv_endtime"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="right"            android:text="00:00"            android:textColor="@color/white"            android:textSize="13sp" />    </LinearLayout>    <ImageView        android:id="@+id/iv_play"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_marginTop="15dp"        android:src="@drawable/select_playvideo" />    <ImageView        android:id="@+id/iv_roat"        android:layout_width="300dp"        android:layout_height="300dp"        android:layout_gravity="center"        android:scaleType="centerCrop"        android:layout_marginTop="20dp"        android:src="@drawable/img_share_friend" /></LinearLayout>

通知栏的布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_vertical">    <ImageView        android:id="@+id/iv_notify_head"        android:layout_width="80dp"        android:layout_height="80dp"        android:src="@drawable/img_default_head" />    <TextView        android:id="@+id/tv_notify_title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignTop="@+id/iv_notify_head"        android:layout_toEndOf="@+id/iv_notify_head"        android:layout_toRightOf="@+id/iv_notify_head"        android:paddingBottom="10dp"        android:paddingRight="20dp"        android:text="标题1"        android:textSize="15sp" />    <RelativeLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@id/iv_notify_head"        android:layout_below="@id/tv_notify_title"        android:layout_toRightOf="@id/iv_notify_head">        <ImageView            android:id="@+id/tv_notify_left"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:paddingRight="20dp"            android:src="@drawable/img_left" />        <ImageView            android:id="@+id/iv_notify_play"            android:layout_width="50dp"            android:layout_height="50dp"            android:layout_centerVertical="true"            android:layout_toRightOf="@id/tv_notify_left"            android:src="@drawable/img_play" />        <ImageView            android:id="@+id/tv_notify_right"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_toRightOf="@id/iv_notify_play"            android:paddingLeft="20dp"            android:paddingRight="10dp"            android:src="@drawable/img_right" />    </RelativeLayout></RelativeLayout>

在就是在AndroidManifest中启动服务和网络请求的权限

    <activity android:name=".BPlayActivity" />      <uses-permission android:name="android.permission.INTERNET" />
public class MyApplication extends Application {    public static Context mContext = null;    @Override    public void onCreate() {        super.onCreate();        mContext = this;    }    public static Context getContext() {        return mContext;    }}

在build.gradle中添加引用,里面有些其他引用不用管

dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {        exclude group: 'com.android.support', module: 'support-annotations'    })    //compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"    compile 'com.android.support:appcompat-v7:25.3.1'    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'    compile 'de.greenrobot:eventbus:3.0.0-beta1'    testCompile 'junit:junit:4.12'}

一个demo就基本完成了。

原创粉丝点击