淘先锋技术网

首页 1 2 3 4 5 6 7

业务: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() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public 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{

		@Override
		public 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("暂停");
				}
			}
			
		}
    }	
  
}


MusicService的完整代码


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;

	@Override
	public 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销毁的时候,解除注册广播接收器
	@Override
	public 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;//音乐开始播放,将暂停状态标志置为false
		synchronized (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();
		}
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	//设置自动播放下一首
	public void addlistener(){
		player.setOnCompletionListener(new OnCompletionListener() {
			
			@Override
			public 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{

		@Override
		public 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();
			}	
			
		}
		
	}
}