編輯:關於Android編程
一丶音樂播放頁實現功能
1.音樂格信息顯示,大圖顯示
2.播放功能,上一曲,下一曲,暫停
3.音樂進度顯示
4.切換播放模式
二丶顯示效果

三丶原理及代碼實現
1.自定義接口回調的方法實現UI狀態切換(進度位置,播放那一首歌)
2.seekbar實現歌曲進度同步及監聽
3.service統一實現Activity,Fragment的播放功能及UI圖片統一
4.BaseActivity基類統一實現服務綁定,音樂播放狀態,直接調用MusicPlayService
代碼實現
activity_play_ui.xml
<!--?xml version="1.0" encoding="utf-8"?-->
<relativelayout android:background="@drawable/skin2" android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<relativelayout android:id="@+id/relativeLayout" android:layout_height="wrap_content" android:layout_width="match_parent">
<imageview android:id="@+id/iv_pull_down" android:layout_centervertical="true" android:layout_height="20dp" android:layout_marginleft="10dp" android:layout_width="wrap_content" android:src="@drawable/backtrack">
<linearlayout android:gravity="center" android:id="@+id/ll_play_ui_top" android:layout_height="wrap_content" android:layout_margintop="5dp" android:layout_toleftof="@+id/iv_share" android:layout_torightof="@+id/iv_pull_down" android:layout_width="match_parent" android:orientation="vertical">
<textview android:id="@+id/tv_play_ui_song" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="聽媽媽的話" android:textcolor="@color/white" android:textsize="18sp">
<textview android:id="@+id/tv_play_ui_artist" android:layout_height="wrap_content" android:layout_width="wrap_content" android:paddingtop="5dp" android:text="周傑倫" android:textcolor="#c1c1c1">
</textview></textview></linearlayout>
<imageview android:id="@+id/iv_share" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_height="25dp" android:layout_marginright="10dp" android:layout_width="wrap_content" android:src="@drawable/share">
</imageview></imageview></relativelayout>
<linearlayout android:id="@+id/linearLayout" android:layout_alignparentbottom="true" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical">
<relativelayout android:layout_height="wrap_content" android:layout_width="match_parent">
<textview android:id="@+id/tv_play_ui_play_time" android:layout_centervertical="true" android:layout_height="wrap_content" android:layout_marginleft="10dp" android:layout_width="wrap_content" android:text="00:00" android:textcolor="@color/white">
<seekbar android:id="@+id/sb_play_ui_seekbar" android:layout_height="wrap_content" android:layout_toleftof="@+id/tv_play_ui_end_time" android:layout_torightof="@+id/tv_play_ui_play_time" android:layout_width="match_parent" android:thumb="@drawable/seekbar_cycle">
<textview android:id="@+id/tv_play_ui_end_time" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_height="wrap_content" android:layout_marginright="10dp" android:layout_width="wrap_content" android:text="00:00" android:textcolor="@color/white">
</textview></seekbar></textview></relativelayout>
<linearlayout android:gravity="center_vertical" android:layout_height="wrap_content" android:layout_marginleft="30dp" android:layout_marginright="30dp" android:layout_margintop="20dp" android:layout_width="match_parent" android:orientation="horizontal">
<imageview android:id="@+id/iv_play_ui_play_mode" android:layout_height="30dp" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/list_cycle">
<imageview android:id="@+id/iv_play_ui_previous" android:layout_height="wrap_content" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/previous">
<imageview android:id="@+id/iv_play_ui_play" android:layout_height="wrap_content" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/play">
<imageview android:id="@+id/iv_play_ui_next" android:layout_height="wrap_content" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/next">
<imageview android:id="@+id/iv_play_ui_menu" android:layout_height="35dp" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/menu">
</imageview></imageview></imageview></imageview></imageview></linearlayout>
<linearlayout android:layout_height="wrap_content" android:layout_marginbottom="10dp" android:layout_marginleft="70dp" android:layout_marginright="70dp" android:layout_margintop="20dp" android:layout_width="match_parent">
<imageview android:id="@+id/iv_play_ui_like" android:layout_height="25dp" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/like">
<imageview android:id="@+id/iv_play_ui_download" android:layout_height="25dp" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/download">
<imageview android:id="@+id/iv_play_ui_add" android:layout_height="28dp" android:layout_weight="1" android:layout_width="wrap_content" android:src="@drawable/add">
</imageview></imageview></imageview></linearlayout>
</linearlayout>
<imageview android:background="#00FFFFFF" android:id="@+id/iv_ablum2" android:layout_below="@+id/relativeLayout" android:layout_height="250dp" android:layout_margintop="25dp" android:layout_width="match_parent">
</imageview></relativelayout>
PlayUIActivity.java
public class PlayUIActivity extends BaseActivity implements View.OnClickListener{
private ImageView iv_pull_down,iv_play_ui_play,iv_play_ui_next,iv_play_ui_previous,iv_play_ui_play_mode,iv_ablum2;
private TextView tv_play_ui_song,tv_play_ui_artist,tv_play_ui_end_time,tv_play_ui_play_time;
private ArrayList mp3Infos;
private SeekBar sb_play_ui_seekbar;
private static final int UPDATE_TIME = 0x1;
private static MyHandler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_play_ui);
iv_pull_down = (ImageView)findViewById(R.id.iv_pull_down);
iv_ablum2 = (ImageView)findViewById(R.id.iv_ablum2);
tv_play_ui_song = (TextView)findViewById(R.id.tv_play_ui_song);
tv_play_ui_artist = (TextView)findViewById(R.id.tv_play_ui_artist);
tv_play_ui_end_time = (TextView)findViewById(R.id.tv_play_ui_end_time);
tv_play_ui_play_time = (TextView)findViewById(R.id.tv_play_ui_play_time);
iv_play_ui_play = (ImageView)findViewById(R.id.iv_play_ui_play);
iv_play_ui_next = (ImageView)findViewById(R.id.iv_play_ui_next);
iv_play_ui_previous = (ImageView)findViewById(R.id.iv_play_ui_previous);
iv_play_ui_play_mode = (ImageView)findViewById(R.id.iv_play_ui_play_mode);
sb_play_ui_seekbar = (SeekBar)findViewById(R.id.sb_play_ui_seekbar);
iv_pull_down.setOnClickListener(this);
iv_play_ui_play.setOnClickListener(this);
iv_play_ui_next.setOnClickListener(this);
iv_play_ui_previous.setOnClickListener(this);
iv_play_ui_play_mode.setOnClickListener(this);
mp3Infos = MediaUtils.getMp3Infos(this);
myHandler = new MyHandler(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
bindMusicPlayService();
}
@Override
protected void onPause() {
super.onPause();
unbindMusicPlayService();
}
/**
* 進度條控件已經內部處理過了,開始時間的改變是在子線程中改變主線程的UI,這當然是不可以的
* 怎麼辦呢,用你最熟悉的Handler處理吧
*/
static class MyHandler extends android.os.Handler{
//內部類去要想使用外部類的權限,就得把外部類拿進來
private PlayUIActivity playUIActivity;
public MyHandler(PlayUIActivity playUIActivity){
this.playUIActivity = playUIActivity;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(playUIActivity!=null){
switch (msg.what){
case UPDATE_TIME:
playUIActivity.tv_play_ui_play_time.setText(MediaUtils.formatTime(msg.arg1));
break;
}
}
}
}
//這裡是子線程,不斷的發送msg給主線程,通知其更改UI
@Override
public void publish(int progress) {
Message msg = myHandler.obtainMessage(UPDATE_TIME);
msg.arg1 = progress;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
myHandler.sendMessage(msg);
sb_play_ui_seekbar.setProgress(progress);
}
@Override
public void change(int position) {
Mp3Info mp3Info = mp3Infos.get(position);
tv_play_ui_song.setText(mp3Info.getTitle());
tv_play_ui_artist.setText(mp3Info.getArtist());
tv_play_ui_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));
iv_play_ui_play.setImageResource(R.drawable.pause);
//獲取專輯封面圖片
Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false);
//改變播放界面專輯封面圖片
iv_ablum2.setImageBitmap(albumBitmap);
sb_play_ui_seekbar.setProgress(0);
sb_play_ui_seekbar.setMax((int)mp3Info.getDuration());
if(musicPlayService.isPlaying()){
iv_play_ui_play.setImageResource(R.drawable.pause);
}else {
iv_play_ui_play.setImageResource(R.drawable.play);
}
switch (musicPlayService.getPlay_mode()){
case MusicPlayService.ORDER_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
//iv_play_ui_play_mode.setTag(MusicPlayService.ORDER_PLAY);
break;
case MusicPlayService.RANDOM_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.random);
//iv_play_ui_play_mode.setTag(MusicPlayService.RANDOM_PLAY);
break;
case MusicPlayService.SINGLE_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
//iv_play_ui_play_mode.setTag(MusicPlayService.SINGLE_PLAY);
break;
default:
break;
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.iv_pull_down:
finish();
overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out);
break;
case R.id.iv_play_ui_play:
if(musicPlayService.isPlaying()){
musicPlayService.pause();
iv_play_ui_play.setImageResource(R.drawable.play);
}else{
if(musicPlayService.isPause()){
musicPlayService.start();
iv_play_ui_play.setImageResource(R.drawable.pause);
}else{
musicPlayService.play(0);
}
}
break;
case R.id.iv_play_ui_previous:
musicPlayService.previous();
break;
case R.id.iv_play_ui_next:
musicPlayService.next();
break;
case R.id.iv_play_ui_play_mode:
switch (musicPlayService.getPlay_mode()){
case MusicPlayService.ORDER_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.random);
musicPlayService.setPlay_mode(MusicPlayService.RANDOM_PLAY);
break;
case MusicPlayService.RANDOM_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
musicPlayService.setPlay_mode(MusicPlayService.SINGLE_PLAY);
break;
case MusicPlayService.SINGLE_PLAY:
iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
musicPlayService.setPlay_mode(MusicPlayService.ORDER_PLAY);
}
break;
default:
break;
}
}
}
BaseActivity.java
/**
* 自定義基礎activity,用來讓其他activity繼承,作為工具activity,用於綁定服務
*/
public abstract class BaseActivity extends FragmentActivity {
protected MusicPlayService musicPlayService;
private boolean isBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MusicPlayService.PlayBinder playBinder = (MusicPlayService.PlayBinder)iBinder;
musicPlayService = playBinder.getMusicPlayService();
musicPlayService.setMusicUpdateListener(musicUpdateListener);
//綁定成功後調用監聽onChange方法
musicUpdateListener.onChange(musicPlayService.getCurrentPosition());
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
musicPlayService = null;
isBound = false;
}
};
private MusicPlayService.MusicUpdateListener musicUpdateListener = new MusicPlayService.MusicUpdateListener(){
@Override
public void onPublish(int progress) {
publish(progress);
}
@Override
public void onChange(int position) {
change(position);
}
};
public abstract void publish(int progress);
public abstract void change(int position);
//綁定服務
public void bindMusicPlayService(){
if(!isBound){
Intent intent = new Intent(this,MusicPlayService.class);
bindService(intent,conn,BIND_AUTO_CREATE);
isBound = true;
}
}
//解除綁定服務
public void unbindMusicPlayService(){
if(isBound){
unbindService(conn);
isBound = false;
}
}
}
MusicPlayService.java
/**
* 實現功能:
* 1、點擊列表上的某首歌播放
* 2、點擊播放按鈕,從暫停轉為播放狀態
* 3、點擊暫停按鈕,從播放狀態轉為暫停狀態
* 4、上一首
* 5、下一首
* 6、播放進度顯示
* 7、播放模式
*/
public class MusicPlayService extends Service implements MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener{
private MediaPlayer mediaPlayer;
private ArrayList mp3Infos;
private int currentPosition;//列表當前位置
private MusicUpdateListener musicUpdateListener;//設置屬性
private boolean isPause = false;
//順序播放、單曲循環、隨機播放
public static final int ORDER_PLAY = 1;
public static final int RANDOM_PLAY = 2;
public static final int SINGLE_PLAY = 3;
public int play_mode = ORDER_PLAY;
//用於設置或者獲得播放模式
public int getPlay_mode() {
return play_mode;
}
public void setPlay_mode(int play_mode) {
this.play_mode = play_mode;
}
//在fragment或者activity中輕松獲得狀態
public boolean isPause(){
return isPause;
}
//開啟線程池
private ExecutorService es = Executors.newSingleThreadExecutor();
Runnable updateStatusRunnable = new Runnable() {
@Override
public void run() {
while (true){
if(musicUpdateListener!=null&&mediaPlayer!=null&&mediaPlayer.isPlaying()){
musicUpdateListener.onPublish(getCurrentProgress());
}
}
}
};
public MusicPlayService() {
}
Random random = new Random();
//用於監聽當前歌曲播放完後,下一首該如何播放
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
switch (play_mode){
case ORDER_PLAY:
next();
break;
case RANDOM_PLAY:
play(random.nextInt(mp3Infos.size()));
break;
case SINGLE_PLAY:
play(currentPosition);
break;
default:
break;
}
}
@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
mediaPlayer.reset();
return false;
}
class PlayBinder extends Binder{
public MusicPlayService getMusicPlayService(){
return MusicPlayService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
mp3Infos = MediaUtils.getMp3Infos(this);
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
//在進入每一個綁定service時,就監聽進度改變事件,而狀態改變監聽則是在啟動播放的時候
es.execute(updateStatusRunnable);
}
//啟動線程就得銷毀
@Override
public void onDestroy() {
super.onDestroy();
if(es!=null && es.isTerminated()){
es.shutdown();
es = null;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new PlayBinder();
}
//點擊列表上的某首歌播放
public void play(int position){
if(position>=0 && position= mp3Infos.size()-1){
currentPosition = 0;
}else{
currentPosition++;
}
play(currentPosition);
}
//上一首
public void previous(){
if(currentPosition<=0){
currentPosition = mp3Infos.size()-1;
}else{
currentPosition--;
}
play(currentPosition);
}
//更新狀態的接口
public interface MusicUpdateListener{
public void onPublish(int progress);
public void onChange(int position);
}
public void setMusicUpdateListener(MusicUpdateListener musicUpdateListener) {
this.musicUpdateListener = musicUpdateListener;
}
//在音樂播放中,獲得播放的位置信息
public int getDuration(){
return mediaPlayer.getDuration();
}
//跳轉到某個地方
public void seekTo(int msec){
mediaPlayer.seekTo(msec);
}
//返回當前的位置
public int getCurrentPosition(){
return currentPosition;
}
//獲得當前位置
public int getCurrentProgress(){
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
return mediaPlayer.getCurrentPosition();
}
return 0;
}
//反饋狀態
public boolean isPlaying(){
if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
return mediaPlayer.isPlaying();
}
return false;
}
}
Android Studio系列-HelloWorld
Android Studio系列-HelloWorld前言Hello 各位,小巫這裡要記錄一些關於如何使用Android Studio開發Android app,這一篇是
Android UI:ListView - SimpleAdapter實例詳解
Android UI:ListView -- SimpleAdapterSimpleAdapter是擴展性最好的適配器,可以定義各種你想要的布局,而且使用很方便。layo
【快速搞定】2分鐘搞定極光推送(極光推送Android端集成)
一、前言2分鐘只是一個虛數哈,不過只要你速度快,兩分鐘還真是能搞定的哦。在2.1.8版本以前,極光的配置還是非常麻煩的,需要在清單文件(AndroidManifest.x
Android基礎篇之Android快速入門--你必須要知道的基礎
Android快速入門 1. 搭建開發環境>解壓壓縮文件,得到:①Android SDK (類似於JDK)② Eclipse ③ADT>配置兩個pat