編輯:關於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 ArrayList mp3Infos;
//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常用拓展(Android群英傳)
ListView雖然使用廣泛,但系統原生的ListView顯然是不能滿足用戶在審美、功能上不斷提高的需求。不過也不要緊,Android完全可以定制化,讓我們非常方便地對原
微信授權登陸接入第三方App(步驟總結)Android
這幾天開發要用到微信授權的功能,所以就研究了一下。可是微信開放平台接入指南裡有幾個地方寫的不清不楚。在此總結一下,以便需要的人。很多微信公眾平台的應用如果移植到app上的
Android簡易實戰教程--第二十三話《絢麗的菜單項》
今天這篇稍微增強點代碼量,可能要多花上5分鐘喽。本篇完成一個稍微顯得絢麗的菜單項,模仿優酷選擇菜單。如果想對其中的任意一項實現點擊功能,自行加入即可。現在就一步一步做出這
Android初識之簡易計算器
之前自己的編程完全是在PC上進行的,而且主要是在算法和數據結構上。由於某些需要加之認識到Android的重要性,且大學走到現在基本上沒什麼課了,空閒時間很多,於是就開始學