android-简单音乐播放器的总结
来源:互联网 发布:集团合并报表软件 编辑:程序博客网 时间:2024/04/19 15:45
业务:android的程序,实现播放音乐的功能。
知识点:
1.使用了android的四大组件中的三个(Activity,Service,Broadcast)
activity与serivice之间的通信用广播Broadcast组件实现,程序中有10多个广播的发布和接收。
2.还使用了线程和Application类来保存全局性的数据。
在Service中启动一个线程是为了在activity需要的时候,不间断地给activity发布更新进度的广播,activity收到后再界面上展示出来。
难点:
个人感觉广播虽然多,但是逻辑上一般,不是很复杂,稍微比较难理解的是线程的启动和停止条件的判段和service中Destroy方法中的收尾清理工作。
1.在这几种条件下需要唤醒线程。
1)play()方法中,当开始播放音乐的时候,让它就开始干活。
2)seekto()方法中,当拖动seekBar需要重新定位并且播放音乐的时候,让它就开始干活。
3)当activity发布广播,请求service发布一个更新进度的广播的时候需要唤醒线程,让它就开始干活。
4)Service方法要退出销毁的时候需要唤醒线程,让其退出循环。
完整项目代码:
http://download.csdn.net/detail/tzguo1314/5542427
部分代码:
主Activity的全部代码
package com.tarena.day1901;import com.tarena.entity.Music;import com.tarena.utils.Consts;import com.tarena.utils.FormatUtils;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.ListView;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;import android.widget.TextView;public class MainActivity extends Activity {private ListView lvMusics;private MenuInflater inflater;private MusicAdapter adapter;private Button btnPlayOrPause;private MusicApplication app;private TextView tvMusicName;private TextView tvDuration;private InnerBroadcastReceiver receiver;private SeekBar sbProgress; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); inflater=getMenuInflater(); app=(MusicApplication)getApplication(); //设置界面 setupView(); addlistener(); //启动service Intent intent=new Intent(this, MusicService.class); startService(intent); //创建一个广播接收器 createReceiver(); } //activity启动,发送广播给service告知需要发送进度更新的广播 @Override protected void onStart() { super.onStart(); Intent intent=new Intent(Consts.ACTION_NEED_UPDATE_PROGRESS); intent.putExtra(Consts.EXTRA_NEED_UPDATE_PROGRESS, true); sendBroadcast(intent); Log.i("info", "onStart"); } @Override protected void onResume() { Log.i("info", "onREsume"); super.onResume(); } //activity停止,发送广播给service告知可以停止发送进度更新的广播 @Override protected void onStop() { super.onStop(); Intent intent=new Intent(Consts.ACTION_NEED_UPDATE_PROGRESS); intent.putExtra(Consts.EXTRA_NEED_UPDATE_PROGRESS, false); sendBroadcast(intent); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver);//MainActivity销毁的时候,对广播接收器,解除注册 } //设置界面 public void setupView(){ lvMusics=(ListView)findViewById(R.id.lvMusics); adapter=new MusicAdapter(this); lvMusics.setAdapter(adapter); btnPlayOrPause=(Button)findViewById(R.id.btnPlayOrPause); tvMusicName=(TextView)findViewById(R.id.tvMusicName); tvDuration=(TextView)findViewById(R.id.tvDuration); sbProgress=(SeekBar)findViewById(R.id.sbProgress); } //添加菜单 @Override public boolean onCreateOptionsMenu(Menu menu) { inflater.inflate(R.menu.opts,menu); return super.onCreateOptionsMenu(menu); } //选择系统菜单选项,发送广播 @Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent=null; switch (item.getItemId()) {case R.id.menu_sub_loop:intent=new Intent(Consts.ACTION_PLAY_MODE);intent.putExtra(Consts.EXTRA_PLAY_MODE, Consts.PLAY_MODE_LOOP); sendBroadcast(intent); Log.i("info", "循环");break;case R.id.menu_sub_random:intent=new Intent(Consts.ACTION_PLAY_MODE);intent.putExtra(Consts.EXTRA_PLAY_MODE, Consts.PLAY_MODE_RADOM); sendBroadcast(intent); Log.i("info", "随机");break;case R.id.menu_opts_exit:intent=new Intent(Consts.ACTION_APP_STOPED); sendBroadcast(intent);finish();break;} return super.onOptionsItemSelected(item); } //监听用户拖动seekbar,并记录拖动的位置 private void addlistener() { sbProgress.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {// TODO Auto-generated method stub}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {// TODO Auto-generated method stub}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {if(fromUser){Intent intent=new Intent(Consts.ACTION_SEEK_TO);intent.putExtra(Consts.EXTRA_SEEK_TO, progress);sendBroadcast(intent);}}}); } //用户不同的操作,执行相应的操作 public void doClick(View v){ Intent intent=null; switch (v.getId()) {case R.id.btnNext:intent=new Intent(Consts.ACTION_PLAY_NEXT);btnPlayOrPause.setText("暂停");break;case R.id.btnPlayOrPause:String text=((Button)v).getText().toString();if("播放".equals(text)){intent=new Intent(Consts.ACTION_PLAY);((Button)v).setText("暂停");}else if("暂停".equals(text)){intent=new Intent(Consts.ACTION_PAUSE);((Button)v).setText("播放");}break;case R.id.btnPrevious:intent=new Intent(Consts.ACTION_PLAY_PREVIOUS);btnPlayOrPause.setText("暂停");break;} sendBroadcast(intent); } //创建一个广播接收器 private void createReceiver() { receiver=new InnerBroadcastReceiver(); IntentFilter filter=new IntentFilter(); filter.addAction(Consts.ACTION_CURRENT_MUSIC_CHANGE); filter.addAction(Consts.ACTION_START_UPDATE_PROGRESS); filter.addAction(Consts.ACTION_SEND_PLAYING_STATE); registerReceiver(receiver, filter);} private class InnerBroadcastReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {String action=intent.getAction();//接收广播,音乐变更,前端展示更新为新的音乐的名字和时长if(Consts.ACTION_CURRENT_MUSIC_CHANGE.equals(action)){Music music=app.getCurrentMusic();tvMusicName.setText(music.getName());tvDuration.setText(FormatUtils.format(music.getDuration()));}else if(Consts.ACTION_START_UPDATE_PROGRESS.equals(action)){//当前播放时长int progress=intent.getIntExtra(Consts.EXTRA_CURRENT_MUSIC_TIME_POSITION, 0);//总时长int Duration = (int)app.getCurrentMusic().getDuration();tvDuration.setText(FormatUtils.format(progress));//在界面显示歌曲已播放时长sbProgress.setProgress(progress*100/Duration);}else if(Consts.ACTION_SEND_PLAYING_STATE.equals(action)){int state=intent.getIntExtra(Consts.EXTRA_PLAY_STATE, Consts.STATE_OTHERS);Music m=app.getCurrentMusic();int progress=intent.getIntExtra(Consts.EXTRA_CURRENT_MUSIC_TIME_POSITION, 0);int Duration = (int)app.getCurrentMusic().getDuration();tvDuration.setText(FormatUtils.format(progress));//在界面显示歌曲已播放时长sbProgress.setProgress(progress*100/Duration);tvMusicName.setText(m.getName());if(state==Consts.STATE_PAUSE){btnPlayOrPause.setText("播放");}else if(state==Consts.STATE_ISPLAYING){btnPlayOrPause.setText("暂停");}}} } }
package com.tarena.day1901;import java.io.IOException;import java.util.Random;import com.tarena.entity.Music;import com.tarena.utils.Consts;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.os.IBinder;import android.util.Log;public class MusicService extends Service {private MediaPlayer player;private MusicApplication app;private boolean isPause;private boolean needUpdate; //需要发布更新进度private boolean isLoop;//控制循环语句private int playMode;private Random random;private InnerBroadcastReceiver receiver;private Thread workThread;@Overridepublic void onCreate() {super.onCreate();app=(MusicApplication)getApplication();player=new MediaPlayer();playMode=Consts.PLAY_MODE_LOOP;isLoop=true;needUpdate=true;random=new Random();//设置自动播放下一首的监听器addlistener();//添加接收器createReceiver();workThread=new Thread(){public void run() {while(isLoop){while(isLoop&&needUpdate&&player.isPlaying()){Intent intent=new Intent(Consts.ACTION_START_UPDATE_PROGRESS);//将当前播放的音乐播放的时间抽的位置包装传递intent.putExtra(Consts.EXTRA_CURRENT_MUSIC_TIME_POSITION, player.getCurrentPosition());sendBroadcast(intent);try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}//此工作线程需要不停地循环工作,除非修改循环标志。不需要发送广播的时候就等待,睡大觉synchronized (this) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}}};};workThread.start();}//service销毁的时候,解除注册广播接收器@Overridepublic void onDestroy() {unregisterReceiver(receiver);//唤醒线程,让线程退出循环isLoop = false;synchronized (workThread) {workThread.notify();}//如果音乐还在播放,停止其播放if (player.isPlaying())player.stop();//释放资源player.release();super.onDestroy();}//如果是isPause状态值为true,直接播放,else重置player,最后要记得唤醒线程public void play(){if(isPause){player.start();}else{Music music=app.getCurrentMusic();String path=music.getMusicPath();if(path!=null){try {player.reset();player.setDataSource(path);player.prepare();player.start();//当前索引所表示的歌曲变化,发布广播Intent intent=new Intent(Consts.ACTION_CURRENT_MUSIC_CHANGE);sendBroadcast(intent);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}isPause=false;//音乐开始播放,将暂停状态标志置为falsesynchronized (workThread) {workThread.notify();}}//如果正在播放,暂停播放public void pause(){if(player.isPlaying()){player.pause();isPause=true;}}//开始播放后一首public void next(){int index=app.getCurrentPosition();switch (playMode) {case Consts.PLAY_MODE_LOOP:if(++index>=app.getPlayListSize()){index=0;}break;case Consts.PLAY_MODE_RADOM:do {index=random.nextInt(app.getPlayListSize());} while (index==app.getCurrentPosition());break;}app.setCurrentPosition(index);isPause=false;play();}//开始播放前一首public void previous(){int index=app.getCurrentPosition();switch (playMode) {case Consts.PLAY_MODE_LOOP:if(--index<=0){index=app.getPlayListSize()-1;}break;case Consts.PLAY_MODE_RADOM:do {index=random.nextInt(app.getPlayListSize());} while (index==app.getCurrentPosition());break;}app.setCurrentPosition(index);isPause=false;play();}//定位到指定的时间值开始播放public void seekTo(int positon){player.seekTo(positon);player.start();synchronized (workThread) {workThread.notify();}}@Overridepublic IBinder onBind(Intent intent) {return null;}//设置自动播放下一首public void addlistener(){player.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {next();}});}//添加接收器private void createReceiver() {receiver=new InnerBroadcastReceiver();IntentFilter filter=new IntentFilter();filter.addAction(Consts.ACTION_PAUSE);filter.addAction(Consts.ACTION_PLAY);filter.addAction(Consts.ACTION_PLAY_NEXT);filter.addAction(Consts.ACTION_PLAY_PREVIOUS);filter.addAction(Consts.ACTION_PLAY_MODE);filter.addAction(Consts.ACTION_APP_STOPED);filter.addAction(Consts.ACTION_NEED_UPDATE_PROGRESS);filter.addAction(Consts.ACTION_SEEK_TO);registerReceiver(receiver, filter);}//接收器类private class InnerBroadcastReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {String action=intent.getAction();if(Consts.ACTION_PLAY.equals(action)){play();}else if(Consts.ACTION_PAUSE.equals(action)){pause();}else if(Consts.ACTION_PLAY_NEXT.equals(action)){next();}else if(Consts.ACTION_PLAY_PREVIOUS.equals(action)){previous();}else if(Consts.ACTION_PLAY_MODE.equals(action)){playMode=intent.getIntExtra(Consts.EXTRA_PLAY_MODE, Consts.PLAY_MODE_LOOP);}//获取并判断当前是否需要发送更新进度的广播else if(Consts.ACTION_NEED_UPDATE_PROGRESS.equals(action)){needUpdate=intent.getBooleanExtra(Consts.EXTRA_NEED_UPDATE_PROGRESS, true);if(needUpdate){synchronized (workThread) {workThread.notify();}//更新进度的时候,同时发送音乐播放器的状态(是否正在播放、播放的音乐的位置)Intent intent2=new Intent(Consts.ACTION_SEND_PLAYING_STATE);int state=Consts.STATE_OTHERS;int position=0;if(player.isPlaying()){state=Consts.STATE_ISPLAYING;}else if(isPause){state=Consts.STATE_PAUSE;}position=player.getCurrentPosition();intent2.putExtra(Consts.EXTRA_CURRENT_MUSIC_TIME_POSITION, position);intent2.putExtra(Consts.EXTRA_PLAY_STATE, state);sendBroadcast(intent2);}//根据拖动的位置,计算应当开始播放的时间值}else if(Consts.ACTION_SEEK_TO.equals(action)){int progress=intent.getIntExtra(Consts.EXTRA_SEEK_TO, player.getCurrentPosition());int duration=(int)app.getCurrentMusic().getDuration();seekTo(progress*duration/100);}else if(Consts.ACTION_APP_STOPED.equals(action)){stopSelf();}}}}
- android-简单音乐播放器的总结
- Android--MediaPlayDemo简单的音乐播放器
- android-----简单的音乐播放器
- android 简单的音乐播放器
- 简单的android音乐播放器
- 一个简单的Android音乐播放器
- 简单的android音乐播放器
- Android中简单的音乐播放器
- android实现简单的音乐播放器
- Android音乐播放器的简单实现
- Android-简单音乐播放器
- Android简单音乐播放器
- android简单音乐播放器
- Android简单音乐播放器
- Android简单音乐播放器
- android简单音乐播放器
- 简单Android音乐播放器
- android开发---音乐播放器的简单播放
- 实现了sina微博的自动登录和发送微博功能
- LInux 远程 windows桌面
- 研究了sina微博的开发平台
- Windows远程访问Opensuse桌面的两种方法
- 题目1113:二叉树
- android-简单音乐播放器的总结
- java 压缩流
- 项目上利用ehcache实现了缓存技术
- malloc/free与new/delete的区别
- PHP socket
- 成功attack了某位童鞋的网站
- Windows-核心编程-04-进程-获取进程 线程 模块(DLL)信息
- python多线程图片爬虫
- 用hadoop写了个简单的并行爬虫