先看下效果图:
在这里,视频进度条会根据视频播放变化,下方的按钮中,播放下一个,上一个都已实现。
代码已经托管到码云上,想下载看的小伙伴可以从下方地址中获取
https://git.oschina.net/joy_yuan/MobilePlayer
1、在这张图上,自定义的显示电量的那一列已经被系统自带的状态栏遮盖,下面就说一下实现方法:
系统电量变化时,系统会发送一个广播,所有对这个广播感兴趣的activity都可以注册广播来接收这个广播。在这里接收系统电量变化,屏幕锁屏、开屏的广播,只能使用动态广播,不能用静态广播,这样是防止在锁屏后,某些程序偷偷干事情,开屏后其又隐藏,导致用户不知道。
定义动态广播接收到系统的电量变化广播后,就根据电量值的区间,来动态的切换电量的图片,具体代码段如下:
//注册电量广播,像锁屏、开屏、电量变化这样的广播,静态注册的广播接收者收不到广播,因为导致安全问题,所以必须动态注册 receiver=new MyReceiver(); IntentFilter intentFilter=new IntentFilter(); //当电量变化时发这个广播 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); registerReceiver(receiver, intentFilter); --------------------------------------------------------------------------------------- /** * 监听电量变化的广播接收者 */ class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { int level=intent.getIntExtra("level",0); //去intent获取key为level的值,默认是0 setBattery(level); } }
接收到电量的区间后,来动态设置电量图片
/** * 电量变化的方法 * @param level */ private void setBattery(int level) { if (level<=0){ ivBattery.setImageResource(R.drawable.ic_battery_0); }else if (level<=10){ ivBattery.setImageResource(R.drawable.ic_battery_10); }else if (level<=20){ ivBattery.setImageResource(R.drawable.ic_battery_20); }else if (level<=40){ ivBattery.setImageResource(R.drawable.ic_battery_40); }else if (level<60){ ivBattery.setImageResource(R.drawable.ic_battery_60); }else if (level<=80){ ivBattery.setImageResource(R.drawable.ic_battery_80); }else if (level<=100){ ivBattery.setImageResource(R.drawable.ic_battery_100); } }
2、视频进度条的变化
seekbar本身有一个setMax();这个是设置seekbar的最大值,我们传入一个视频的总时长就可以。在开始播放视频时,传一个空的handler,来进行更新seekbar方法。
/** * 准备好播放时的监听 */ class MyOnPreparedListener implements MediaPlayer.OnPreparedListener { @Override public void onPrepared(MediaPlayer mp) { videoview.start(); //开始播放 duration = videoview.getDuration(); //获取视频总时长 seekbarVideo.setMax(duration); //设置播放进度的最大值 //发送消息,来更新视频进度 handler.sendEmptyMessage(PROGRESS); } }
然后在handler里,根据handler的what类型,来做更新进度的操作。videoview.getcurrentPosition()方法获取当前的视频进度,然后seekbar有个setpositon()可以设置进度,最后每隔一秒,再发送一个handler来更新这个进度
/** * 定义一个handler来处理信息 */ public Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case PROGRESS: //根据准备好播放时候后,发送的更新视频进度消息,来更新视频进度 int currentPosition=videoview.getCurrentPosition(); seekbarVideo.setProgress(currentPosition); //隔一秒刷新一下进度 removeMessages(PROGRESS); handler.sendEmptyMessageDelayed(PROGRESS,1000); break; } } };
3、系统时间的变化:
在上一面中讲到了视频进度条变换时,用到了handler,在handler里隔一秒刷新下handler,因此在这里也是更新系统时间放到了handler里。
/** * 定义一个handler来处理信息 */ public Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case PROGRESS: //根据准备好播放时候后,发送的更新视频进度消息,来更新视频进度 int currentPosition=videoview.getCurrentPosition(); seekbarVideo.setProgress(currentPosition); //设置当前播放的时间,使其显示在播放器上 tvCurrentTime.setText(utils.stringForTime(currentPosition)); //设置系统播放时间,隔一秒刷新一下 tvSystemTime.setText(getSystemTime()); //隔一秒刷新一下进度 removeMessages(PROGRESS); handler.sendEmptyMessageDelayed(PROGRESS,1000); break; } } }; /** * 获取系统时间 * @return */ private String getSystemTime() { SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); return format.format(new Date()); }
在这里要注意的是,获取系统时间的方法,用的那个SimpleDateFormat()方法,它的包是java.text.SimpleDateFormat;一定要注意了,Android系统可能会自动给我们导成其他包导致报错
4、要实现播放上一个下一个视频功能,我们就要获取视频数据的列表list,那么在videoPager中我们通过bundle,将list写入到bundle中,其中要注意的是 一定要给实体类MediaItem 序列化,即类实现Serializable接口即可,否则会导致报错。
在videoPager中,按如下代码传入list到intent
//给对象序列化后传到SystemVideoPlayer中 Intent intent=new Intent(context, SystemVideoPlayer.class); Bundle bundle=new Bundle(); bundle.putSerializable("mediallist",(ArrayList)mediaList); intent.putExtras(bundle); intent.putExtra("position",position); //将点击的视频的位置传过去,方便定位播放的是哪个视频 context.startActivity(intent);
在SystemVideoPlayer类中获取该list
//获取videopager里传过来的list数据,包含media列表的信息 medialist = (ArrayList) getIntent().getSerializableExtra("mediallist"); position = getIntent().getIntExtra("position",0);
获取到list和position后,即可非常方便的实现播放上一个,下一个视频
public void onClick(View v) { if ( v == btnVoice ) { // Handle clicks for btnVoice } else if ( v == switchPlayer ) { // Handle clicks for switchPlayer } else if ( v == btExit ) { // Handle clicks for btExit 退出 finish(); } else if ( v == btVideoPre ) { // Handle clicks for btVideoPre 播放上一个视频 if (medialist!=null&&medialist.size()>0){ position-=1; if (position<=0){ position=medialist.size()-1; } MediaItem mediaitem=medialist.get(position); tvName.setText(mediaitem.getName()); videoview.setVideoPath(mediaitem.getData()); }else if (uri!=null){ tvName.setText(uri.toString()); videoview.setVideoURI(uri); } } else if ( v == btVideoStartPause ) { // Handle clicks for btVideoStartPause 播放暂停与启动 if (videoview.isPlaying()){ //视频在播放,则暂停 videoview.pause(); //按钮图片设置为暂停 btVideoStartPause.setBackgroundResource(R.drawable.bt_video_play_selector); }else{ //视频在暂停,设置为播放 videoview.start(); //按钮图片设置为播放 btVideoStartPause.setBackgroundResource(R.drawable.bt_video_pause_selector); } } else if ( v == btNext ) { // Handle clicks for btNext 播放下一个 if (medialist!=null&&medialist.size()>0){ position+=1; if (position>=medialist.size()){ position=0; } MediaItem mediaItem = medialist.get(position); tvName.setText(mediaItem.getName()); videoview.setVideoPath(mediaItem.getData()); }else if (uri!=null){ //把上一个下一个按钮设置灰色 tvName.setText(uri.toString()); videoview.setVideoURI(uri); btNext.setEnabled(false); btNext.setBackgroundResource(R.drawable.btn_next_gray); } } else if ( v == btVideoSwitchScreen ) { // Handle clicks for btVideoSwitchScreen } }
这里做的是循环播放,即播放到最后一个后,按下一个,会播放第一个视频。