編輯:關於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 ArrayListBaseActivity.javamp3Infos; 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; } } }
/** * 自定義基礎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 ArrayListmp3Infos; 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前言Hello 各位,小巫這裡要記錄一些關於如何使用Android Studio開發Android app,這一篇是
Android UI:ListView -- SimpleAdapterSimpleAdapter是擴展性最好的適配器,可以定義各種你想要的布局,而且使用很方便。layo
一、前言2分鐘只是一個虛數哈,不過只要你速度快,兩分鐘還真是能搞定的哦。在2.1.8版本以前,極光的配置還是非常麻煩的,需要在清單文件(AndroidManifest.x
Android快速入門 1. 搭建開發環境>解壓壓縮文件,得到:①Android SDK (類似於JDK)② Eclipse ③ADT>配置兩個pat