編輯:關於Android編程
實現效果如圖:
實現代碼如下:
PlayActivity如下:
package com.iwanghang.drmplayer; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import com.iwanghang.drmplayer.utils.MediaUtils; import com.iwanghang.drmplayer.vo.Mp3Info; import java.util.ArrayList; /** *PlayActivity 點擊MyMusicListFragment(本地音樂)底部UI中的專輯封面圖片打開的Activity */ public class PlayActivity extends BaseActivity implements OnClickListener{ private TextView textView1_title;//歌名 private ImageView imageView1_ablum;//專輯封面圖片 private SeekBar seekBar1;//進度條 private TextView textView1_start_time,textView1_end_time;//開始時間,結束時間 private ImageView imageView1_play_mode;//菜單 private ImageView imageView3_previous,imageView2_play_pause,imageView1_next;//上一首,播放暫停,下一首 private ArrayListmp3Infos; //private int position;//當前播放的位置 private boolean isPause = false;//當前播放的是否為暫停狀態 private static final int UPDATE_TIME = 0x1;//更新播放事件的標記 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music_play); //初始化界面信息 textView1_title = (TextView) findViewById(R.id.textView1_title);//歌名 imageView1_ablum = (ImageView) findViewById(R.id.imageView1_ablum);//專輯封面圖片 seekBar1 = (SeekBar) findViewById(R.id.seekBar1);//進度條 textView1_start_time = (TextView) findViewById(R.id.textView1_start_time);//開始時間 textView1_end_time = (TextView) findViewById(R.id.textView1_end_time);//結束時間 imageView1_play_mode = (ImageView) findViewById(R.id.imageView1_play_mode);//菜單 imageView3_previous = (ImageView) findViewById(R.id.imageView3_previous);//上一首 imageView2_play_pause = (ImageView) findViewById(R.id.imageView2_play_pause);//播放暫停 imageView1_next = (ImageView) findViewById(R.id.imageView1_next);//下一首 //注冊按鈕點擊監聽事件 imageView1_play_mode.setOnClickListener(this); imageView2_play_pause.setOnClickListener(this); imageView3_previous.setOnClickListener(this); imageView1_next.setOnClickListener(this); mp3Infos = MediaUtils.getMp3Infos(this); //bindPlayService();//綁定服務,異步過程,綁定後需要取得相應的值,來更新界面 myHandler = new MyHandler(this); //以下直接調用change()是不行的,因為異步問題,會發生NullPointerException空指針異常 //從MyMusicListFragment的專輯封面圖片點擊時間傳過來的position(當前播放的位置) //position = getIntent().getIntExtra("position",0); //change(position); //通過在BaseActivity中綁定Service,添加如下代碼實現change() //musicUpdatrListener.onChange(playService.getCurrentProgeress()); //從MyMusicListFragment的專輯封面圖片點擊時間傳過來的isPause(當前播放的是否為暫停狀態) //isPause = getIntent().getBooleanExtra("isPause",false); } //把播放服務的綁定和解綁放在onResume,onPause裡,好處是,每次回到當前Activity就獲取一次播放狀態 @Override protected void onResume() { super.onResume(); bindPlayService(); } @Override protected void onPause() { super.onPause(); unbindPlayService(); } @Override protected void onDestroy() { super.onDestroy(); unbindPlayService();//解綁服務 } //Handler用於更新已經播放時間 private static MyHandler myHandler; static class MyHandler extends Handler{ private PlayActivity playActivity; public MyHandler(PlayActivity playActivity){ this.playActivity = playActivity; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (playActivity!=null){ switch (msg.what){ case UPDATE_TIME://更新時間(已經播放時間) playActivity.textView1_start_time.setText(MediaUtils.formatTime(msg.arg1)); break; } } } } @Override public void publish(int progress) { //以下是是直接調用線程,但是不能這樣做,會報錯,線程異常 //textView1_start_time.setText(MediaUtils.formatTime(progress)); //所以,我們需要使用Handler Message msg = myHandler.obtainMessage(UPDATE_TIME);//用於更新已經播放時間 msg.arg1 = progress;//用於更新已經播放時間 myHandler.sendMessage(msg);//用於更新已經播放時間 seekBar1.setProgress(progress); } @Override public void change(int position) { //if (this.playService.isPlaying()) {//獲取是否為播放狀態 System.out.println("PlayActivity #100 position = " + position); Mp3Info mp3Info = mp3Infos.get(position); textView1_title.setText(mp3Info.getTitle());//設置歌名 //獲取專輯封面圖片 Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false); //改變播放界面專輯封面圖片 imageView1_ablum.setImageBitmap(albumBitmap); textView1_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));//設置結束時間 imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//設置暫停圖片 seekBar1.setProgress(0);//設置當前進度為0 seekBar1.setMax((int)mp3Info.getDuration());//設置進度條最大值為MP3總時間 if (playService.isPlaying()){ imageView2_play_pause.setImageResource(R.mipmap.app_music_pause); }else { imageView2_play_pause.setImageResource(R.mipmap.app_music_play); } //} } //點擊事件 @Override public void onClick(View v) { switch (v.getId()){ case R.id.imageView2_play_pause: {//播放暫停按鈕 if (playService.isPlaying()) {//如果是播放狀態 imageView2_play_pause.setImageResource(R.mipmap.app_music_play);//設置播放圖片 playService.pause(); } else { if (playService.isPause()) { imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//設置暫停圖片 playService.start();//播放事件 } else { //只有打開APP沒有點擊任何歌曲,同時,直接點擊暫停播放按鈕時.才會調用 playService.play(0); } } break; } case R.id.imageView1_next:{//下一首按鈕 playService.next();//下一首 break; } case R.id.imageView3_previous:{//上一首按鈕 playService.prev();//上一首 } default: break; } } }
package com.iwanghang.drmplayer; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; import android.os.Binder; import android.os.IBinder; import com.iwanghang.drmplayer.utils.MediaUtils; import com.iwanghang.drmplayer.vo.Mp3Info; import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 音樂播放的服務組件 * 實現功能: * 播放 * 暫停 * 下一首 * 上一首 * 獲取當前歌曲的播放進度 * * 需要在AndroidManifest.xml添加以下代碼: ** */ public class PlayService extends Service { private MediaPlayer mPlayer; private int currentPosition;//當前正在播放的歌曲的位置 ArrayListmp3Infos; private MusicUpdatrListener musicUpdatrListener; //創建一個單實力的線程,用於更新音樂信息 private ExecutorService es = Executors.newSingleThreadExecutor(); private boolean isPause = false;//歌曲播放中的暫停狀態 public boolean isPause(){ return isPause; } public PlayService() { } public int getCurrentPosition(){ return currentPosition; } //內部類PlayBinder實現Binder,得到當前PlayService對象 class PlayBinder extends Binder{ public PlayService getPlayService(){ System.out.println("PlayService #1 " + PlayService.this); return PlayService.this; } } @Override public IBinder onBind(Intent intent) { return new PlayBinder();//通過PlayBinder拿到PlayService,給Activity調用 } @Override public void onCreate() { super.onCreate(); mPlayer = new MediaPlayer(); mp3Infos = MediaUtils.getMp3Infos(this);//獲取Mp3列表 es.execute(updateSteatusRunnable);//更新進度值 } @Override public void onDestroy() { super.onDestroy(); //回收線程 if (es!=null && !es.isShutdown()){//當進度值等於空,並且,進度值沒有關閉 es.shutdown(); es = null; } } //利用Runnable來實現多線程 /** * Runnable * Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable接口. * Runnable接口非常簡單,就定義了一個方法run(),繼承Runnable並實現這個 * 方法就可以實現多線程了,但是這個run()方法不能自己調用,必須由系統來調用,否則就和別的方法沒有什麼區別了. * 好處:數據共享 */ Runnable updateSteatusRunnable = new Runnable() {//更新狀態 @Override public void run() { //不斷更新進度值 while (true){ //音樂更新監聽不為空,並且,媒體播放不為空,並且媒體播放為播放狀態 if(musicUpdatrListener!=null && mPlayer!=null && mPlayer.isPlaying()){ musicUpdatrListener.onPublish(getCurrentProgress());//獲取當前的進度值 } try { Thread.sleep(500);//500毫秒更新一次 } catch (InterruptedException e) { e.printStackTrace(); } } } }; //播放 public void play(int position){ if (position>=0 && position =mp3Infos.size()-1){//如果超出最大值,(因為第一首是0),說明已經是最後一首 currentPosition = 0;//回到第一首 }else { currentPosition++;//下一首 } play(currentPosition); } //上一首 previous public void prev(){ if (currentPosition-1<0){//如果上一首小於0,說明已經是第一首 currentPosition = mp3Infos.size()-1;//回到最後一首 }else { currentPosition--;//上一首 } play(currentPosition); } //默認開始播放的方法 public void start(){ if (mPlayer!=null && !mPlayer.isPlaying()){//判斷當前歌曲不等於空,並且沒有在播放的狀態 mPlayer.start(); } } //獲取當前是否為播放狀態,提供給MyMusicListFragment的播放暫停按鈕點擊事件判斷狀態時調用 public boolean isPlaying(){ if (mPlayer!=null){ return mPlayer.isPlaying(); } return false; } //獲取當前的進度值 public int getCurrentProgress(){ if(mPlayer!=null && mPlayer.isPlaying()){//mPlayer不為空,並且,為播放狀態 return mPlayer.getCurrentPosition(); } return 0; } //getDuration 獲取文件的持續時間 public int getDuration(){ return mPlayer.getDuration(); } //seekTo 尋找指定的時間位置 public void seekTo(int msec){ mPlayer.seekTo(msec); } //更新狀態的接口(PlayService的內部接口),並在BaseActivity中實現 public interface MusicUpdatrListener{//音樂更新監聽器 public void onPublish(int progress);//發表進度事件(更新進度條) public void onChange(int position); //更新歌曲位置.按鈕的狀態等信息 //聲明MusicUpdatrListener後,添加set方法 } //set方法 public void setMusicUpdatrListener(MusicUpdatrListener musicUpdatrListener) { this.musicUpdatrListener = musicUpdatrListener; } }
BaseActivity如下:
package com.iwanghang.drmplayer; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.v4.app.FragmentActivity; import android.view.View; /** * Created by iwanghang on 16/4/19. * MainActivity繼承BaseActivity,實現APP所有綁定功能 * 繼承後,直接調用子類方法,就可以進行綁定和解除,bindPlayService,unbindPlayService * * 模板設計模式,給FragmentActivity做了一個抽象,用來綁定服務 * */ public abstract class BaseActivity extends FragmentActivity{ protected PlayService playService; private boolean isBound = false;//是否已經綁定 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } //綁定Service private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //轉換 PlayService.PlayBinder playBinder = (PlayService.PlayBinder) service; //綁定播放服務 playService = playBinder.getPlayService(); //設置監聽器 playService.setMusicUpdatrListener(musicUpdatrListener); //真正調用的是PlayActivity裡面change() musicUpdatrListener.onChange(playService.getCurrentPosition()); } @Override public void onServiceDisconnected(ComponentName name) { playService = null; isBound = false; } }; //實現MusicUpdatrListener的相關方法,把PlayService.MusicUpdatrListener的具體內容, // 延遲到子類來具體實現(把具體的操作步驟在子類中實現) private PlayService.MusicUpdatrListener musicUpdatrListener = new PlayService.MusicUpdatrListener() { @Override public void onPublish(int progress) { publish(progress); } @Override public void onChange(int progress) { change(progress); } }; //抽象類(子類來具體實現,用於更新UI) public abstract void publish(int progress); public abstract void change(int progress); //綁定服務(子類決定什麼時候調用,比如在onCreate時調用,或者在onResume,onPause時調用) public void bindPlayService(){ if(!isBound) { Intent intent = new Intent(this, PlayService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); isBound = true; } } //解綁服務(子類決定什麼時候調用,比如在onCreate時調用,或者在onResume,onPause時調用) public void unbindPlayService(){ if(isBound) { unbindService(conn); isBound = false; } } //點擊事件 public void onClick(View v){ } }
activity_music_play.xml如下:
ListView雖然使用廣泛,但系統原生的ListView顯然是不能滿足用戶在審美、功能上不斷提高的需求。不過也不要緊,Android完全可以定制化,讓我們非常方便地對原
這幾天開發要用到微信授權的功能,所以就研究了一下。可是微信開放平台接入指南裡有幾個地方寫的不清不楚。在此總結一下,以便需要的人。很多微信公眾平台的應用如果移植到app上的
今天這篇稍微增強點代碼量,可能要多花上5分鐘喽。本篇完成一個稍微顯得絢麗的菜單項,模仿優酷選擇菜單。如果想對其中的任意一項實現點擊功能,自行加入即可。現在就一步一步做出這
之前自己的編程完全是在PC上進行的,而且主要是在算法和數據結構上。由於某些需要加之認識到Android的重要性,且大學走到現在基本上沒什麼課了,空閒時間很多,於是就開始學