实现一个简单的播放器——Service,Handle和MediaPlayer的使用
实现一个简单的播放器,要求功能有:
1. 播放、暂停,停止,退出功能;
2. 后台播放功能;
3. 进度条显示播放进度、拖动进度条改变进度功能;
4. 播放时图片旋转,显示当前播放时间功能;
效果图:
图片旋转:
图片布局:主要是要实现图片居中,还有就是id
定义rotate旋转效果:在res/anim文件夹下新建tip.xml文件。
下面的代码表示从0到359度开始循环旋转,0-359(若设置成360在停止时会出现停顿现象)度旋转所用时间为10000ms,旋转中心距离view的左顶点为50%距离,距离view的上边缘为50%距离,即正中心.
android:fromDegrees 起始的角度度数
android:toDegrees 结束的角度度数,负数表示逆时针,正数表示顺时针。如10圈则比android:fromDegrees大3600即可
android:pivotX 旋转中心的X坐标
android:pivotY 旋转中心的Y坐标
浮点数或是百分比。浮点数表示相对于Object的左边缘,如5; 百分比表示相对于Object的左边缘,如5%; 另一种百分比表示相对于父容器的左边缘,如5%p; 一般设置为50%表示在Object中心
android:duration 表示从android:fromDegrees转动到android:toDegrees所花费的时间,单位为毫秒。可以用来计算速度。
android:interpolator表示变化率,但不是运行速度。一个插补属性,可以将动画效果设置为加速,减速,反复,反弹等。默认为开始和结束慢中间快,
android:startOffset 在调用start函数之后等待开始运行的时间,单位为毫秒,若为10,表示10ms后开始运行
android:repeatCount 重复的次数,默认为0,必须是int,可以为-1表示不停止
android:repeatMode 重复的模式,默认为restart,即重头开始重新运行,可以为reverse即从结束开始向前重新运行。在android:repeatCount大于0或为infinite时生效
android:detachWallpaper 表示是否在壁纸上运行
android:zAdjustment 表示被animated的内容在运行时在z轴上的位置,默认为normal。
normal保持内容当前的z轴顺序
top运行时在最顶层显示
bottom运行时在最底层显示
运行速度为运行时间(android:duration)除以运行角度差(android:toDegrees-android:fromDegrees)
setInterpolator表示设置旋转速率。LinearInterpolator为匀速效果,Accelerateinterpolator为加速效果、DecelerateInterpolator为减速效果
AnimationUtils.loadAnimation(this,R.anim.tip)就是加载一个动态效果,tip就是前面定义的xml。
开始旋转:imageview.startAnimation(operatingAnim)
停止旋转:imageview.clearAnimation();
代码:
package com.example.hp.lab6; import android.app.Activity; import android.content.ComponentName; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.drawable.BitmapDrawable; import android.media.Image; import android.os.Handler; import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; import android.widget.Button; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import java.text.SimpleDateFormat; public class MainActivity extends Activity implements OnClickListener { private Button play_pauseBtn,stopBtn,quitBtn; private MusicService musicService; private ImageView imageview; private TextView state, playing_time,max_time; private SeekBar seekbar; private SimpleDateFormat time = new SimpleDateFormat("mm:ss"); //Bitmap bmp = BitmapFactory.decodeResource(this.getResources(),R.mipmap.image); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//绑定布局 findView();//findIdByView,找到个个控件 bindButton();//按钮绑定监听器。 musicService=new MusicService();//新建一个MusicService后台服务 connection();//绑定后台服务 max_time.setText(time.format(musicService.mediaPlayer.getDuration()));//设置max_time这个textview的内容是歌曲的时间长度 Animation operatingAnim = AnimationUtils.loadAnimation(this, R.anim.tip); LinearInterpolator lin = new LinearInterpolator();//LinearInterpolator为匀速效果 operatingAnim.setInterpolator(lin);//setInterpolator表示设置旋转速率。 imageview.startAnimation(operatingAnim);//开始旋转 } private void findView(){ /** 通过id获得各种组件 */ play_pauseBtn=(Button) findViewById(R.id.play_pause);//开始/暂停按钮 stopBtn=(Button) findViewById(R.id.stop);//停止按钮 quitBtn=(Button) findViewById(R.id.quit);//退出按钮 state=(TextView) findViewById(R.id.state);//seekbar上面表示状态的文字textview playing_time=(TextView) findViewById(R.id.playing_time);//seekbar左边现在播放的时间 max_time=(TextView) findViewById(R.id.song_time);//播放的这首歌曲的时长 seekbar=(SeekBar) findViewById(R.id.seekbar);//seekbar imageview=(ImageView ) findViewById(R.id.imageview);//旋转的图片 } private void bindButton(){ /** 为按钮添加监听 ,三个按钮的监听器都是MainActivity*/ play_pauseBtn.setOnClickListener(this); stopBtn.setOnClickListener(this); quitBtn.setOnClickListener(this); } private ServiceConnection sc=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { musicService=((MusicService.MyBinder)service).getService(); } @Override public void onServiceDisconnected(ComponentName name) { musicService=null; } }; Handler mHandler=new Handler(); //创建Handler对象 //要用handler来处理多线程可以使用runnable接口,这里先定义该接口,线程中运行该接口的run函数 Runnable mRunnable=new Runnable() { //新建一个Runnable接口 @Override public void run() {//将要执行的操作写在线程对象的run方法当中 //Matrix mtx = new Matrix(); //mtx.postRotate(1); // Rotating Bitmap //Bitmap rotatedBMP = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mtx, true); //BitmapDrawable bmd = new BitmapDrawable(rotatedBMP); //imageview.setImageDrawable(bmd); //设置seekbar左边的playing_time textview为当前歌曲播放到的时间 playing_time.setText(time.format(musicService.mediaPlayer.getCurrentPosition())); //设置seekbar为当前歌曲播放到的时间 seekbar.setProgress(musicService.mediaPlayer.getCurrentPosition()); //seekbar条拖动监听事件 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override//seekbar发生改变时 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if(fromUser){ musicService.mediaPlayer.seekTo(seekBar.getProgress()); }//根据seekbar拖动到的位置改变设置歌曲播放到的进度 } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); mHandler.postDelayed(mRunnable,100);//100ms执行一次tun()函数 } }; @Override public void onClick(View v){ switch (v.getId()){ case R.id.play_pause://点击play_pause按钮事件 musicService.playORpuase();//调用musicService中的playORpause函数,暂停或开始音乐播放 if(musicService.mediaPlayer.isPlaying()){ state.setText("Playing");//当音乐在播放时,我们设置state的内容为Playing play_pauseBtn.setText("PAUSE");//设置button的内容为Puase //Animation operatingAnim = AnimationUtils.loadAnimation(this, R.anim.tip); //LinearInterpolator lin = new LinearInterpolator();//LinearInterpolator为匀速效果 //operatingAnim.setInterpolator(lin);//setInterpolator表示设置旋转速率。 // imageview.startAnimation(operatingAnim);//开始旋转 } else{ state.setText("Paused");//当音乐停止时,设置state内容为Paused play_pauseBtn.setText("PLAY");//button内容为Play } break; case R.id.stop://点击暂停 musicService.stop();//关闭音乐 play_pauseBtn.setText("PLAY");//设置开始和暂停按钮的内容为Play state.setText("Stop");//设置state为Stop //imageview.clearAnimation(); break; case R.id.quit://点击退出 mHandler.removeCallbacks(mRunnable);//回调mRunnable接口 unbindService(sc);//解除后台服务的绑定 try{ MainActivity.this.finish();//结束当前的时间 System.exit(0); } catch (Exception e){ e.printStackTrace(); } break; } } private void connection(){ //启动指定的Service Intent intent=new Intent(this ,MusicService.class); bindService(intent,sc,BIND_AUTO_CREATE);//绑定服务 } @Override protected void onResume() { seekbar.setProgress(musicService.mediaPlayer.getCurrentPosition()); seekbar.setMax(musicService.mediaPlayer.getDuration()); mHandler.post(mRunnable);//通过Handler启动Runnable super.onResume(); } }
package com.example.hp.lab6; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Binder; import android.os.IBinder; public class MusicService extends Service { public MediaPlayer mediaPlayer=new MediaPlayer(); private final IBinder binder=new MyBinder(); public class MyBinder extends Binder { MusicService getService(){ return MusicService.this;//找到后台服务的指针,返回后台服务实例 } } public MusicService() { try{ mediaPlayer.setDataSource("/data/K.Will-Melt.mp3");//绑定播放的歌曲 mediaPlayer.prepare();//进入就绪状态 mediaPlayer.setLooping(true);//设置循环播放 } catch (Exception e){ e.printStackTrace(); } } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. //throw new UnsupportedOperationException("Not yet implemented"); return binder; } @Override public void onCreate(){ super.onCreate(); } @Override public void onDestroy(){ super.onDestroy(); if(mediaPlayer!=null){ mediaPlayer.stop();//停止歌曲播放 mediaPlayer.release();//释放mediaPlayer资源 } } public void playORpuase(){ if(mediaPlayer.isPlaying()){ mediaPlayer.pause();//暂停 } else{ mediaPlayer.start();//开始 } } public void stop(){ if(mediaPlayer!=null){ mediaPlayer.stop();//停止 try{ mediaPlayer.prepare();//就绪 mediaPlayer.seekTo(0);//设置歌曲回到最开始 } catch (Exception e){ e.printStackTrace(); } } } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context="com.example.hp.lab6.MainActivity" > <ImageView android:id="@+id/imageview" android:layout_gravity="center" android:layout_width="300sp" android:layout_height="300sp" android:src="@drawable/image" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical"> <TextView android:id="@+id/state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_top" android:textSize="@dimen/textsize1" android:text="" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="@dimen/margin_top" android:gravity="center_horizontal"> <TextView android:id="@+id/playing_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00"/> <SeekBar android:id="@+id/seekbar" android:layout_width="280sp" android:layout_height="wrap_content" /> <TextView android:id="@+id/song_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="04:00"/> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_top" android:layout_gravity="center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/play_pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="PLAY" /> <Button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/textsize1" android:text="STOP" /> <Button android:id="@+id/quit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/textsize1" android:text="QUIT" /> </LinearLayout> </LinearLayout>