android播放音频

最近需要项目涉及到了音频播放功能,有可能需要在后台播放,并且在通知栏显示状态。通过查阅资料,自己模拟了一个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就基本完成了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值