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就基本完成了。
阅读全文
0 0
- Android AudioTrack 播放音频
- Android MediaPlayer播放音频
- android:音频播放
- android 音频播放 SoundPool
- android 音频播放--MediaPlayer
- Android SoundPool播放音频
- android 音频播放类
- Android播放音频相关
- Android音频播放方法
- Android中的音频播放
- android音频播放
- Android音频播放讲解
- Android:MediaPlayer播放音频
- Android SoundPool播放音频
- Android播放音频中断
- Android 播放音频
- android播放网络音频
- 管理Android音频播放
- 使用QGIS对CAD图进行描边以及路线图的绘制(3)
- Apriori算法
- SQL语句DDL、DCL、DML
- Spring MVC的web.xml配置详解
- 关于自定义重写springboot配置的一些建议
- android播放音频
- Java还要再学一遍基础(五)String,StringBuilder,StringBuffer
- VINS-MONO学习
- 为ImageView设置背景的方法以及区别
- Android 实现歌词滚动
- HDU-1020
- 文件下载——批量,续载
- AS导入
- 【详细资料】ICN6211芯片MIPI转RGB功能