平台:Android studio

APK:http://fir.im/apps/56ea5187e75e2d69af000042

本地的音乐播放器,主要功能就是可以播放音乐,能够读取本地的音乐,并显示出来,播放,暂停,上一首,下一首,进度条可以拖拽播放,添加了前台service,看一下实现

      

首先我是先做了一个大概的布局,样子先出来,需要其他的空间后期再添加,毕竟一开始不可能想的太详细,看一下主布局文件,就是一个listView 和几个ImageButton,又自己添加了一个title,有个可以进度条,需要可以拖动,使用了seekBar

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.cl.android.music.MusicActivity"android:background="@color/background"android:id="@+id/contentmusic"><include layout="@layout/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:id="@+id/include" /><ListViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/musicListView"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_below="@+id/include"android:layout_above="@+id/seekBar" /><SeekBarandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/seekBar"android:layout_above="@+id/musicinfo"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><TextViewandroid:layout_width="match_parent"android:layout_height="25dp"android:gravity="center"android:id="@+id/musicinfo"android:layout_above="@+id/previous"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><ImageViewandroid:id="@+id/previous"android:layout_width="50dp"android:layout_height="50dp"android:background="@drawable/previous"android:onClick="previous"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><ImageViewandroid:id="@+id/play_pause"android:layout_width="50dp"android:layout_height="50dp"android:background="@drawable/play"android:onClick="play_pause"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true" /><ImageViewandroid:id="@+id/next"android:layout_width="50dp"android:layout_height="50dp"android:background="@drawable/next"android:onClick="next"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:layout_alignParentEnd="true" /><!--<ImageButtonandroid:id="@+id/previous"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/previous"android:onClick="previous"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><ImageButtonandroid:id="@+id/play_pause"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/play"android:onClick="play_pause"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true" /><ImageButtonandroid:id="@+id/next"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/next"android:onClick="next"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:layout_alignParentEnd="true" />--></RelativeLayout>

每个音乐文件显示时的样式

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:layout_width="60dp"android:layout_height="60dp"android:id="@+id/video_imageView" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/video_title"android:text="@string/music_title"android:layout_alignTop="@+id/video_size"android:layout_alignLeft="@+id/video_singer"android:layout_alignStart="@+id/video_singer" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/video_singer"android:text="@string/music_singer"android:layout_marginLeft="20dp"android:layout_marginStart="20dp"android:layout_alignBaseline="@+id/video_duration"android:layout_alignBottom="@+id/video_duration"android:layout_toRightOf="@+id/video_imageView"android:layout_toEndOf="@+id/video_imageView" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/video_size"android:text="@string/music_size"android:layout_above="@+id/video_duration"android:layout_alignLeft="@+id/video_duration"android:layout_alignStart="@+id/video_duration" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/video_duration"android:text="@string/music_duration"android:layout_marginRight="75dp"android:layout_marginEnd="75dp"android:layout_alignBottom="@+id/video_imageView"android:layout_alignParentRight="true"android:layout_alignParentEnd="true"android:layout_marginBottom="15dp" /></RelativeLayout>

以及最上面的那个title

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/toolbarbackground"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="30sp"android:text="@string/app_name"android:id="@+id/textView"android:layout_centerVertical="true"android:layout_centerHorizontal="true" /><ImageViewandroid:id="@+id/click_share"android:onClick="clickShare"android:layout_width="20dp"android:layout_height="wrap_content"android:src="@drawable/share"android:layout_alignParentTop="true"android:layout_alignParentRight="true"android:layout_alignParentEnd="true"android:layout_marginRight="29dp"android:layout_marginEnd="29dp" />
</RelativeLayout>

大概的布局出来后,就可以在填写逻辑代码了,思路肯定是先找到本地的音乐文件再显示出来了,本来思路是想 扫描SD卡获取本地文件,找出MP3文件,这样也是可以的,但是 Android系统会在SD卡有更新的时候自动将SD卡文件分类(视频/音频/图片...),并存入SQLite数据库,就保存在媒体存储器里面(com.android.providers.media),而我们要做的只是像正常读取数据库一样去读数据库的信息就好了,所以直接上代码,代码里都有注释

当前需要先加权限,src/main/AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
/*加载媒体库里的音频*/public ArrayList<MusicMedia> scanAllAudioFiles(){//生成动态数组,并且转载数据ArrayList<MusicMedia> mylist = new ArrayList<MusicMedia>();/*查询媒体数据库参数分别为(路径,要查询的列名,条件语句,条件参数,排序)视频:MediaStore.Video.Media.EXTERNAL_CONTENT_URI图片;MediaStore.Images.Media.EXTERNAL_CONTENT_URI*/Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);//遍历媒体数据库if(cursor.moveToFirst()){while (!cursor.isAfterLast()) {//歌曲编号int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));//歌曲标题String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));//歌曲的专辑名:MediaStore.Audio.Media.ALBUMString album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));//歌曲的歌手名: MediaStore.Audio.Media.ARTISTString artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));//歌曲文件的路径 :MediaStore.Audio.Media.DATAString url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));//歌曲的总播放时长 :MediaStore.Audio.Media.DURATIONint duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));//歌曲文件的大小 :MediaStore.Audio.Media.SIZELong size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));if (size >1024*800){//大于800KMusicMedia musicMedia = new MusicMedia();musicMedia.setId(id);musicMedia.setArtist(artist);musicMedia.setSize(size);musicMedia.setTitle(tilte);musicMedia.setTime(duration);musicMedia.setUrl(url);musicMedia.setAlbum(album);musicMedia.setAlbumId(albumId);mylist.add(musicMedia);}cursor.moveToNext();}}return mylist;}

获取到之后我需要显示在list里,需要ArryList<Map<Object,object>>格式的数据,我上面是存储的一个对象,因为后面我需要单个音乐文件的信息,如果不需要单个文件信息可以在这里直接返回这种格式的数据,listView显示数据

musicList  = scanAllAudioFiles();//这里其实可以直接在扫描时返回 ArrayList<Map<String, Object>>()listems = new ArrayList<Map<String, Object>>();for (Iterator iterator = musicList.iterator(); iterator.hasNext();) {Map<String, Object> map = new HashMap<String, Object>();MusicMedia mp3Info = (MusicMedia) iterator.next();
//            map.put("id",mp3Info.getId());map.put("title", mp3Info.getTitle());map.put("artist", mp3Info.getArtist());map.put("album", mp3Info.getAlbum());
//            map.put("albumid", mp3Info.getAlbumId());map.put("duration", mp3Info.getTime());map.put("size", mp3Info.getSize());map.put("url", mp3Info.getUrl());map.put("bitmap", R.drawable.musicfile);listems.add(map);}/*SimpleAdapter的参数说明* 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要* 第二个参数表示生成一个Map(String ,Object)列表选项* 第三个参数表示界面布局的id  表示该文件作为列表项的组件* 第四个参数表示该Map对象的哪些key对应value来生成列表项* 第五个参数表示来填充的组件 Map对象key对应的资源一依次填充组件 顺序有对应关系* 注意的是map对象可以key可以找不到 但组件的必须要有资源填充  因为 找不到key也会返回null 其实就相当于给了一个null资源* 下面的程序中如果 new String[] { "name", "head", "desc","name" } new int[] {R.id.name,R.id.head,R.id.desc,R.id.head}* 这个head的组件会被name资源覆盖* */SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,listems,R.layout.music_item,new String[] {"bitmap","title","artist", "size","duration"},new int[] {R.id.video_imageView,R.id.video_title,R.id.video_singer,R.id.video_size,R.id.video_duration});//listview里加载数据musicListView.setAdapter(mSimpleAdapter);

现在音乐列表显示在listView里了,可以点击,可以上下滑动,但是怎么实现点击播放呢,使用MediaPler,这是Android系统自带的播放器,这里给出其常用的方法的中文解释,其实大可以直接看英文API嘛

MediaPlayer 常用方法介绍方法:create(Context context, Uri uri)
解释:静态方法,通过Uri创建一个多媒体播放器。
方法:create(Context context, int resid)
解释:静态方法,通过资源ID创建一个多媒体播放器
方法:create(Context context, Uri uri, SurfaceHolder holder)
解释:静态方法,通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器
方法: getCurrentPosition()
解释:返回 Int, 得到当前播放位置
方法: getDuration()
解释:返回 Int,得到文件的时间
方法:getVideoHeight()
解释:返回 Int ,得到视频的高度
方法:getVideoWidth()
解释:返回 Int,得到视频的宽度
方法:isLooping()
解释:返回 boolean ,是否循环播放
方法:isPlaying()
解释:返回 boolean,是否正在播放
方法:pause()
解释:无返回值 ,暂停
方法:prepare()
解释:无返回值,准备同步
方法:prepareAsync()
解释:无返回值,准备异步
方法:release()
解释:无返回值,释放 MediaPlayer  对象
方法:reset()
解释:无返回值,重置 MediaPlayer  对象
方法:seekTo(int msec)
解释:无返回值,指定播放的位置(以毫秒为单位的时间)
方法:setAudioStreamType(int streamtype)
解释:无返回值,指定流媒体的类型
方法:setDataSource(String path)
解释:无返回值,设置多媒体数据来源【根据 路径】
方法:setDataSource(FileDescriptor fd, long offset, long length)
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】
方法:setDataSource(FileDescriptor fd)
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】
方法:setDataSource(Context context, Uri uri)
解释:无返回值,设置多媒体数据来源【根据 Uri】
方法:setDisplay(SurfaceHolder sh)
解释:无返回值,设置用 SurfaceHolder 来显示多媒体
方法:setLooping(boolean looping)
解释:无返回值,设置是否循环播放
事件:setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)
解释:监听事件,网络流媒体的缓冲监听
事件:setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
解释:监听事件,网络流媒体播放结束监听
事件:setOnErrorListener(MediaPlayer.OnErrorListener listener)
解释:监听事件,设置错误信息监听
事件:setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)
解释:监听事件,视频尺寸监听
方法:setScreenOnWhilePlaying(boolean screenOn)
解释:无返回值,设置是否使用 SurfaceHolder 显示
方法:setVolume(float leftVolume, float rightVolume)
解释:无返回值,设置音量
方法:start()
解释:无返回值,开始播放
方法:stop()
解释:无返回值,停止播放

也就是说,使用mediaplayer需要传一个地址过去,这些信息在刚读取音频的方法里都有,直接使用就好了,使用一个service播放,新建一个service,不考虑其他,启动一个隐式的service,需要做一些修改,传一个地址过去先播放起来

在listview上添加监听器,怎么知道点击的音乐的地址,哈哈,有个position,可以定位到musiclist里具体的对象

musicListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {//点击播放音乐,不过需要判断一下当前是否有音乐在播放,需要关闭正在播放的//position 可以获取到点击的是哪一个,去 musicList 里寻找播放currentposition = position;player(currentposition);}});

新建service,修改AndroidManifest.xml 文件

<serviceandroid:name=".MusicPlayerService"android:enabled="true"android:exported="true"><intent-filter ><action android:name="player"></action></intent-filter></service>

启动service

intent.setAction("player");
intent.setPackage(getPackageName());
intent.putExtra("url", musicList.get(position).getUrl());
startService(intent);

再看看service端

@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand......3");// /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3if(intent != null){url = intent.getStringExtra("url");mediaPlayer.setDataSource(url);mediaPlayer.setLooping(true);//单曲循环mediaPlayer.prepare();mediaPlayer.start();}return super.onStartCommand(intent, flags, startId);}

这样就可以直接播放啦,虽然现在只能播放,但是毕竟可以播放了,下面继续播放控制部分逻辑

进度条怎么显示当前的播放进度,我一开始的想法是service使用静态的变量,activity里也是使用静态的变量,然后开一个线程,1s更新一次状态,在service里直接修改seekbar,我就直接上代码了

public class MusicPlayerService extends Service implements Runnable {private static final String TAG = "MusicPlayerService";private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台servicepublic static MediaPlayer mediaPlayer = null;private String url = null;private String MSG = null;private static int curposition;//第几首音乐private musicBinder musicbinder = null;private int currentPosition = 0;// 设置默认进度条当前位置public MusicPlayerService() {Log.i(TAG,"MusicPlayerService......1");musicbinder = new musicBinder();}//通过bind 返回一个IBinder对象,然后改对象调用里面的方法实现参数的传递@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG,"onBind......");return null;}@Overridepublic void onCreate() {Log.i(TAG, "onCreate......2");super.onCreate();if (mediaPlayer == null) {/* mediaPlayer.reset();mediaPlayer.release();mediaPlayer = null;*/mediaPlayer = new MediaPlayer();}// 监听播放是否完成mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {//我目前也不知道该干嘛}});}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand......3");// /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3if(intent != null){MSG = intent.getStringExtra("MSG");if(MSG.equals("0")){url = intent.getStringExtra("url");Log.i(TAG, url + "......." + Thread.currentThread().getName());palyer();}else if(MSG.equals("1")){mediaPlayer.pause();}else if(MSG.equals("2")){mediaPlayer.start();}}return super.onStartCommand(intent, flags, startId);}private void palyer() {Log.i(TAG,"palyer......");//如果正在播放,先停止再播放新的/* if(mediaPlayer.isPlaying()){Log.i(TAG,"palyer......running....");// 暂停mediaPlayer.pause();mediaPlayer.reset();}*///还有就是用户在暂停是点击其他的音乐,所以不管当前状态,都重置一下//下面这段代码可以实现简单的音乐播放try {
//            Log.i(TAG,"palyer......new....");mediaPlayer.reset();mediaPlayer.setDataSource(url);mediaPlayer.setLooping(true);
//            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.prepare();mediaPlayer.start();// 设置进度条最大值MusicActivity.audioSeekBar.setMax(mediaPlayer.getDuration());//开启新线程new Thread(this).start();} catch (IOException e) {e.printStackTrace();}}// 刷新进度条 ,时间@Overridepublic void run() {Log.i(TAG,Thread.currentThread().getName()+"......run...");int total = mediaPlayer.getDuration();// 总时长while (mediaPlayer != null && currentPosition < total) {try {Thread.sleep(1000);if (mediaPlayer != null) {currentPosition = mediaPlayer.getCurrentPosition();}} catch (InterruptedException e) {e.printStackTrace();}MusicActivity.audioSeekBar.setProgress(CurrentPosition);}}@Overridepublic void onDestroy() {Log.i(TAG,"onDestroy......");super.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}//关闭线程Thread.currentThread().interrupt();stopForeground(true);}public String toTime(int time){time /= 1000;int minute = time / 60;int hour = minute / 60;int second = time % 60;minute %= 60;return String.format("%02d:%02d", minute, second);}
}

这样子搞不是不可以,但是官方提供的onbind方法没有使用,所以想使用一下,调用onbind放回一个service对象,在activity的连接部分获取到这个返回值,然后在activity里直接使用该对象的方法获取想要的数据,再添加上前台service,完成后的代码

package com.cl.android.music;import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;import java.io.IOException;public class MusicPlayerService extends Service {//implements Runnable {private static final String TAG = "MusicPlayerService";private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台servicepublic static MediaPlayer mediaPlayer = null;private String url = null;private String MSG = null;private static int curposition;//第几首音乐private musicBinder musicbinder = null;private int currentPosition = 0;// 设置默认进度条当前位置public MusicPlayerService() {Log.i(TAG,"MusicPlayerService......1");musicbinder = new musicBinder();}//通过bind 返回一个IBinder对象,然后改对象调用里面的方法实现参数的传递@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG,"onBind......");return musicbinder;}/*** 自定义的 Binder对象*/public class musicBinder extends Binder {public MusicPlayerService getPlayInfo(){return MusicPlayerService.this;}}//得到当前播放位置public  int getCurrentPosition(){if(mediaPlayer != null){int total = mediaPlayer.getDuration();// 总时长if( currentPosition < total){currentPosition = mediaPlayer.getCurrentPosition();}}return currentPosition;}//得到当前播放位置public  int getDuration(){return mediaPlayer.getDuration();// 总时长}//得到 mediaPlayerpublic MediaPlayer getMediaPlayer(){
//        if(mediaPlayer != null){
//            return mediaPlayer;
//        }return mediaPlayer;}//得到 当前播放第几个音乐public int getCurposition(){return curposition;}@Overridepublic void onCreate() {Log.i(TAG, "onCreate......2");super.onCreate();if (mediaPlayer == null) {/* mediaPlayer.reset();mediaPlayer.release();mediaPlayer = null;*/mediaPlayer = new MediaPlayer();}// 监听播放是否完成mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {//我目前也不知道该干嘛}});}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand......3");// /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3if(intent != null){MSG = intent.getStringExtra("MSG");if(MSG.equals("0")){url = intent.getStringExtra("url");curposition = intent.getIntExtra("curposition",0);Log.i(TAG, url + "......." + Thread.currentThread().getName());palyer();}else if(MSG.equals("1")){mediaPlayer.pause();}else if(MSG.equals("2")){mediaPlayer.start();}String name = "Current: "+ url.substring(url.lastIndexOf("/") + 1 , url.lastIndexOf("."));Log.i(TAG,name);
//        //开启前台serviceNotification notification = null;if (Build.VERSION.SDK_INT < 16) {notification = new Notification.Builder(this).setContentTitle("Enter the MusicPlayer").setContentText(name).setSmallIcon(R.drawable.musicfile).getNotification();} else {Notification.Builder builder = new Notification.Builder(this);PendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, MusicActivity.class), 0);builder.setContentIntent(contentIntent);builder.setSmallIcon(R.drawable.musicfile);
//        builder.setTicker("Foreground Service Start");builder.setContentTitle("Enter the MusicPlayer");builder.setContentText(name);notification = builder.build();}startForeground(NOTIFICATION_ID, notification);}return super.onStartCommand(intent, flags, startId);}private void palyer() {Log.i(TAG,"palyer......");//如果正在播放,先停止再播放新的/* if(mediaPlayer.isPlaying()){Log.i(TAG,"palyer......running....");// 暂停mediaPlayer.pause();mediaPlayer.reset();}*///还有就是用户在暂停是点击其他的音乐,所以不管当前状态,都重置一下//下面这段代码可以实现简单的音乐播放try {
//            Log.i(TAG,"palyer......new....");mediaPlayer.reset();mediaPlayer.setDataSource(url);mediaPlayer.setLooping(true);
//            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.prepare();mediaPlayer.start();// 设置进度条最大值
//            MusicActivity.audioSeekBar.setMax(mediaPlayer.getDuration());//开启新线程
//            new Thread(this).start();} catch (IOException e) {e.printStackTrace();}}// 刷新进度条 ,时间/*@Overridepublic void run() {Log.i(TAG,Thread.currentThread().getName()+"......run...");int total = mediaPlayer.getDuration();// 总时长while (mediaPlayer != null && currentPosition < total) {try {Thread.sleep(1000);if (mediaPlayer != null) {currentPosition = mediaPlayer.getCurrentPosition();}} catch (InterruptedException e) {e.printStackTrace();}
//            MusicActivity.audioSeekBar.setProgress(CurrentPosition);}}
*/@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG,"onUnbind......");return super.onUnbind(intent);}@Overridepublic void onRebind(Intent intent) {super.onRebind(intent);Log.i(TAG, "onRebind......");}@Overridepublic void onDestroy() {Log.i(TAG,"onDestroy......");super.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}//关闭线程Thread.currentThread().interrupt();stopForeground(true);}public String toTime(int time){time /= 1000;int minute = time / 60;int hour = minute / 60;int second = time % 60;minute %= 60;return String.format("%02d:%02d", minute, second);}
}

activity那端,使用handler + runnable实现主线程的界面刷新,全部功能完成后的代码

package com.cl.android.music;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View.OnClickListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;public class MusicActivity extends AppCompatActivity {private ListView musicListView = null;private ImageView imageView = null;private ArrayList<Map<String, Object>> listems = null;//需要显示在listview里的信息private ArrayList<MusicMedia> musicList = null; //音乐信息列表
//    private ImageButton btn_previous = null,btn_play_pause = null,btn_next = null;private ImageView btn_play_pause = null;public static SeekBar audioSeekBar = null;//定义进度条public static TextView textView = null;private Intent intent = null;private int currentposition = -1;//当前播放列表里哪首音乐private boolean isplay = false;//音乐是否在播放private MusicPlayerService musicPlayerService = null;private MediaPlayer mediaPlayer = null;private Handler handler = null;//处理界面更新,seekbar ,textviewprivate boolean isservicerunning = false;//退出应用再进入时(点击app图标或者在通知栏点击service)使用,判断服务是否在启动private SingleMusicInfo singleMusicInfo = null;//音乐的详细信息private boolean isExit = false;//返回键@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.content_music);Log.i("MusicPlayerService", "MusicActivity...onCreate........." + Thread.currentThread().hashCode());
//        init();}private void init() {intent = new Intent();intent.setAction("player");intent.setPackage(getPackageName());handler = new Handler();imageView = (ImageView)findViewById(R.id.click_share);imageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent shareIntent = new Intent();shareIntent.setAction(Intent.ACTION_SEND);shareIntent.putExtra(Intent.EXTRA_TEXT,"我的博客地址:http://blog.csdn.net/i_do_can");shareIntent.setType("text/plain");//设置分享列表startActivity(Intent.createChooser(shareIntent,"分享到"));}});textView  = (TextView)findViewById(R.id.musicinfo);musicListView = (ListView)findViewById(R.id.musicListView);//        btn_previous = (ImageButton)findViewById(R.id.previous);//播放暂停时要切换图标
//        btn_play_pause = (ImageButton)findViewById(R.id.play_pause);btn_play_pause = (ImageView)findViewById(R.id.play_pause);
//        btn_next = (ImageButton)findViewById(R.id.next);musicListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {//点击播放音乐,不过需要判断一下当前是否有音乐在播放,需要关闭正在播放的//position 可以获取到点击的是哪一个,去 musicList 里寻找播放currentposition = position;player(currentposition);}});musicList  = scanAllAudioFiles();//这里其实可以直接在扫描时返回 ArrayList<Map<String, Object>>()listems = new ArrayList<Map<String, Object>>();for (Iterator iterator = musicList.iterator(); iterator.hasNext();) {Map<String, Object> map = new HashMap<String, Object>();MusicMedia mp3Info = (MusicMedia) iterator.next();
//            map.put("id",mp3Info.getId());map.put("title", mp3Info.getTitle());map.put("artist", mp3Info.getArtist());map.put("album", mp3Info.getAlbum());
//            map.put("albumid", mp3Info.getAlbumId());map.put("duration", mp3Info.getTime());map.put("size", mp3Info.getSize());map.put("url", mp3Info.getUrl());map.put("bitmap", R.drawable.musicfile);listems.add(map);}/*SimpleAdapter的参数说明* 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要* 第二个参数表示生成一个Map(String ,Object)列表选项* 第三个参数表示界面布局的id  表示该文件作为列表项的组件* 第四个参数表示该Map对象的哪些key对应value来生成列表项* 第五个参数表示来填充的组件 Map对象key对应的资源一依次填充组件 顺序有对应关系* 注意的是map对象可以key可以找不到 但组件的必须要有资源填充  因为 找不到key也会返回null 其实就相当于给了一个null资源* 下面的程序中如果 new String[] { "name", "head", "desc","name" } new int[] {R.id.name,R.id.head,R.id.desc,R.id.head}* 这个head的组件会被name资源覆盖* */SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,listems,R.layout.music_item,new String[] {"bitmap","title","artist", "size","duration"},new int[] {R.id.video_imageView,R.id.video_title,R.id.video_singer,R.id.video_size,R.id.video_duration});//listview里加载数据musicListView.setAdapter(mSimpleAdapter);//进度条audioSeekBar = (SeekBar) findViewById(R.id.seekBar);//退出后再次进去程序时,进度条保持持续更新if(MusicPlayerService.mediaPlayer!=null){reinit();//更新页面布局以及变量相关}//播放进度监 ,使用静态变量时别忘了Service里面还有个进度条刷新audioSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (currentposition == -1) {Log.i("MusicPlayerService", "MusicActivity...showInfo(请选择要播放的音乐);.........");//还没有选择要播放的音乐showInfo("请选择要播放的音乐");} else {//假设改变源于用户拖动if (fromUser) {//这里有个问题,如果播放时用户拖进度条还好说,但是如果是暂停时,拖完会自动播放,所以还需要把图标设置一下btn_play_pause.setBackgroundResource(R.drawable.pause);MusicPlayerService.mediaPlayer.seekTo(progress);// 当进度条的值改变时,音乐播放器从新的位置开始播放}}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {if (mediaPlayer != null) {mediaPlayer.pause();}//                MusicPlayerService.mediaPlayer.pause(); // 开始拖动进度条时,音乐暂停播放}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {if (mediaPlayer != null) {mediaPlayer.start();}
//                MusicPlayerService.mediaPlayer.start(); // 停止拖动进度条时,音乐开始播放}});//textView 点击弹出音乐的详细信息textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {
//                Log.i("MusicPlayerService", "MusicActivity...textView.setOnClickListener;.........");if (textView.getText().length() > 0) {singleMusicInfo = new SingleMusicInfo(MusicActivity.this,listems.get(currentposition));//显示窗口singleMusicInfo.showAtLocation(MusicActivity.this.findViewById(R.id.contentmusic), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置}}});Log.i("MusicPlayerService", "MusicActivity...init done;.........");}private void reinit() {//设置进度条最大值
//        audioSeekBar.setMax(MusicPlayerService.mediaPlayer.getDuration());
//        audioSeekBar.setProgress(MusicPlayerService.mediaPlayer.getCurrentPosition());
//        currentposition = MusicPlayerService.getCurposition();Log.i("MusicPlayerService","reinit.........");isservicerunning = true;//如果是正在播放if(MusicPlayerService.mediaPlayer.isPlaying()){isplay = true;btn_play_pause.setBackgroundResource(R.drawable.pause);}//重新绑定servicebindService(intent, conn, Context.BIND_AUTO_CREATE);}/*加载媒体库里的音频*/public ArrayList<MusicMedia> scanAllAudioFiles(){//生成动态数组,并且转载数据ArrayList<MusicMedia> mylist = new ArrayList<MusicMedia>();/*查询媒体数据库参数分别为(路径,要查询的列名,条件语句,条件参数,排序)视频:MediaStore.Video.Media.EXTERNAL_CONTENT_URI图片;MediaStore.Images.Media.EXTERNAL_CONTENT_URI*/Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);//遍历媒体数据库if(cursor.moveToFirst()){while (!cursor.isAfterLast()) {//歌曲编号int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));//歌曲标题String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));//歌曲的专辑名:MediaStore.Audio.Media.ALBUMString album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));//歌曲的歌手名: MediaStore.Audio.Media.ARTISTString artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));//歌曲文件的路径 :MediaStore.Audio.Media.DATAString url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));//歌曲的总播放时长 :MediaStore.Audio.Media.DURATIONint duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));//歌曲文件的大小 :MediaStore.Audio.Media.SIZELong size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));if (size >1024*800){//大于800KMusicMedia musicMedia = new MusicMedia();musicMedia.setId(id);musicMedia.setArtist(artist);musicMedia.setSize(size);musicMedia.setTitle(tilte);musicMedia.setTime(duration);musicMedia.setUrl(url);musicMedia.setAlbum(album);musicMedia.setAlbumId(albumId);mylist.add(musicMedia);}cursor.moveToNext();}}return mylist;}public void previous(View view) {previousMusic();}public void play_pause(View view) {Log.i("MusicPlayerService", "MusicActivity...play_pause........." +isplay);//当前是pause的图标,(使用图标来判断是否播放,就不需要再新定义变量为状态了,表示没能找到得到当前背景的图片的)实际上播放着的,暂停
//        if(btn_play_pause.getBackground().getCurrent().equals(R.drawable.play)){if(isservicerunning){//服务启动着,这里点击播放暂停按钮时只需要当前音乐暂停或者播放就好if (isplay) {pause();} else {//暂停--->继续播放player("2");}}else {if (isplay) {pause();} else {Log.i("MusicPlayerService", "MusicActivity...notplay.........");//当前是play的图标,是 暂停 着的//初始化时,没有点击列表,直接点击了播放按钮if (currentposition == -1) {showInfo("请选择要播放的音乐");} else {//暂停--->继续播放player("2");}}}}public void next(View view) {nextMusic();}private void player() {player(currentposition);}private void player(int position){textView.setText(musicList.get(position).getTitle()+"   playing...");intent.putExtra("curposition", position);//把位置传回去,方便再启动时调用intent.putExtra("url", musicList.get(position).getUrl());intent.putExtra("MSG","0");isplay = true;//播放时就改变btn_play_pause图标,下面这个过期了
//        btn_play_pause.setBackgroundDrawable(getResources().getDrawable(R.drawable.pause));btn_play_pause.setBackgroundResource(R.drawable.pause);startService(intent);bindService(intent, conn, Context.BIND_AUTO_CREATE);Log.i("MusicPlayerService","MusicActivity...bindService.......");}private ServiceConnection conn = new ServiceConnection() {/** 获取服务对象时的操作 */public void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubmusicPlayerService = ((MusicPlayerService.musicBinder)service).getPlayInfo();mediaPlayer = musicPlayerService.getMediaPlayer();Log.i("MusicPlayerService", "MusicActivity...onServiceConnected.......");currentposition = musicPlayerService.getCurposition();//设置进度条最大值audioSeekBar.setMax(mediaPlayer.getDuration());//这里开了一个线程处理进度条,这个方式官方貌似不推荐,说违背什么单线程什么鬼
//            new Thread(seekBarThread).start();//使用runnable + handlerhandler.post(seekBarHandler);}/** 无法获取到服务对象时的操作 */public void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubmusicPlayerService = null;}};//1s更新一次进度条Runnable seekBarThread = new Runnable() {@Overridepublic void run() {while (musicPlayerService != null) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
//                Log.i("MusicPlayerService", "seekBarThread run.......");audioSeekBar.setProgress(musicPlayerService.getCurrentPosition());}}};Runnable seekBarHandler = new Runnable() {@Overridepublic void run() {Log.i("MusicPlayerService", "MusicActivity...seekBarHandler run......."+Thread.currentThread().hashCode()+" "+handler.hashCode());audioSeekBar.setProgress(musicPlayerService.getCurrentPosition());textView.setText( "(Click Me)  "+ musicList.get(currentposition).getTitle() +"       " +musicPlayerService.toTime(musicPlayerService.getCurrentPosition()) +"  / " + musicPlayerService.toTime(musicPlayerService.getDuration() ));handler.postDelayed(seekBarHandler, 1000);}};private  void player(String info){intent.putExtra("MSG",info);isplay = true;btn_play_pause.setBackgroundResource(R.drawable.pause);startService(intent);}/** MSG :*  0  未播放--->播放*  1    播放--->暂停*  2    暂停--->继续播放** */private void pause() {intent.putExtra("MSG","1");isplay = false;btn_play_pause.setBackgroundResource(R.drawable.play);startService(intent);}private void previousMusic() {if(currentposition > 0){currentposition -= 1;player();}else{showInfo("已经是第一首音乐了");}}private void nextMusic() {if(currentposition < musicList.size()-2){currentposition += 1;player();}else{showInfo("已经是最后一首音乐了");}}private void showInfo(String info) {Toast.makeText(this,info,Toast.LENGTH_SHORT).show();}@Overrideprotected void onResume() {super.onResume();Log.i("MusicPlayerService", "MusicActivity...onResume........." + Thread.currentThread().hashCode());init();}@Overrideprotected void onPause() {super.onPause();Log.i("MusicPlayerService", "MusicActivity...onPause........." + Thread.currentThread().hashCode());//绑定服务了if(musicPlayerService != null){unbindService(conn);}handler.removeCallbacks(seekBarHandler);}@Overrideprotected void onDestroy() {super.onDestroy();
//        unbindService(conn);Log.i("MusicPlayerService", "MusicActivity...onDestroy........." + Thread.currentThread().hashCode());}private void exit(String info) {if(!isExit) {isExit = true;Toast.makeText(this, info, Toast.LENGTH_SHORT).show();new Timer().schedule(new TimerTask() {@Overridepublic void run() {isExit = false;}}, 2000);} else {finish();}}//按两次返回键退出@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK&& event.getRepeatCount() == 0) {//音乐服务启动了,隐藏至通知栏if(musicPlayerService != null){exit("再按一次隐藏至通知栏");}else{exit("再按一次退出程序");}}return false;}}

有个很奇怪的地方,完全不符合生命周期,按说应用不在界面上显示,再启动时,应该调用onRestart->onStart...

但是我测试时时直接OnCreate-onStart...好吧,很无奈,直接kill掉了,可能是我手机的问题,为了防止真的是手机的问题,我把初始化代码写在了onResume里

当前播放时间显示的部分,我添加了一个弹窗,点击可以显示当前播放歌曲的详细信息,弹窗继承PopupWindow,布局文件就一个TableLayout,就俩列,设置第二列内容自动换行

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><TableLayoutandroid:id="@+id/tablelayout"android:layout_width="match_parent"android:layout_height="wrap_content"android:shrinkColumns="1"></TableLayout></RelativeLayout>

弹窗点击非弹窗部分退出

package com.cl.android.music;import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.view.ViewGroup.LayoutParams;
import android.widget.SimpleAdapter;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;/*** Created by chenling on 2016/3/17.*/
public class SingleMusicInfo extends PopupWindow {private View view;private TableLayout tableLayout;public SingleMusicInfo(Context context,Map<String, Object> map) {super(context);LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);view = inflater.inflate(R.layout.singlemusicinfo, null);tableLayout = (TableLayout) view.findViewById(R.id.tablelayout);map.remove("bitmap");//移除图片那个键值对for(String keys : map.keySet()){TableRow tableRow = new TableRow(context);TextView key = new TextView(context);TextView value = new TextView(context);Log.i("MusicPlayerService", "SingleMusicInfo..........." + tableRow.hashCode());key.setText("   " + keys + "    ");value.setText(map.get(keys).toString());tableRow.addView(key);tableRow.addView(value);tableLayout.addView(tableRow);}//设置SingleMusicInfo的Viewthis.setContentView(view);//设置弹出窗体的宽this.setWidth(LayoutParams.MATCH_PARENT);//设置弹出窗体的高this.setHeight(LayoutParams.WRAP_CONTENT);//设置S弹出窗体可点击this.setFocusable(true);ColorDrawable dw = new ColorDrawable(Color.rgb(255,228,181));//设置弹出窗体的背景this.setBackgroundDrawable(dw);//view添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框view.setOnTouchListener(new OnTouchListener() {public boolean onTouch(View v, MotionEvent event) {int height = view.findViewById(R.id.tablelayout).getTop();int y=(int) event.getY();if(event.getAction()==MotionEvent.ACTION_UP){if(y<height){dismiss();}}return true;}});}
}

Ok ,原谅我代码逻辑没有讲详细,代码都有注释,注释的代码部分可以直接忽略,还有分享功能,大家果断分享一下吧,谢谢

附件:源码下载:http://download.csdn.net/detail/i_do_can/9464424

- - - - - - - - - -- - - - - - - -  - - - - - - - - - - - - - - - - - - 更新2016-04-09- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

新增列表上拉下滑时顶部和底部菜单栏消失

新增播放模式:单曲循环 随机播放 顺序播放

新增摇一摇根据当前播放模式切换歌曲

更新之后的apk:http://fir.im/5u9p

第一点,列表上拉下滑时顶部和底部菜单栏消失,关键是要监听onTouchLIstener,关键代码如下

private float mLastY = -1;// 标记上下滑动时上次滑动位置,滑动隐藏上下标题栏private RelativeLayout musictop,musicbotom;musictop = (RelativeLayout)findViewById(R.id.music_top);musicbotom = (RelativeLayout)findViewById(R.id.music_bottom);//上下滚动时musicListView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (mLastY == -1) {mLastY = event.getRawY();}switch (event.getAction()) {case MotionEvent.ACTION_MOVE://判断上滑还是下滑if (event.getRawY() > mLastY) {//下滑显示bottom,隐藏topmusictop.setVisibility(View.GONE);musicbotom.setVisibility(View.VISIBLE);} else if (event.getRawY() < mLastY) {//上滑,显示top,隐藏bottommusictop.setVisibility(View.VISIBLE);
//                            musicbotom.setVisibility(View.INVISIBLE);musicbotom.setVisibility(View.GONE);} else {// deltaY = 0.0 时musictop.setVisibility(View.VISIBLE);musicbotom.setVisibility(View.VISIBLE);mLastY = event.getRawY();return false;//返回false即可响应click事件}mLastY = event.getRawY();break;default:// resetmLastY = -1;musictop.setVisibility(View.VISIBLE);musicbotom.setVisibility(View.VISIBLE);break;}return false;}});

接着看看播放模式的改变,这个简单,用户看见的只是简单的图片的切换,我这里是使用了SharedPreferences 保存相关的信息,方便用户再次启动时更改显示图片,主要是保存当前的播放模式,主要代码如下:

public static SharedPreferences sharedPreferences;public static SharedPreferences.Editor editor;//保存播放模式private ImageView playMode ,playaccelerometer;private int[] modepic = {R.drawable.ic_shuffle_black_24dp,R.drawable.ic_repeat_black_24dp,R.drawable.ic_repeat_one_black_24dp};//默认随机播放playMode = (ImageView)findViewById(R.id.play_mode);sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);editor = sharedPreferences.edit();int playmode = sharedPreferences.getInt("play_mode", -1);if(playmode == -1){//没有设置模式,默认随机editor.putInt("play_mode",0).commit();}else{changeMode(playmode);}//修改播放模式  单曲循环 随机播放 顺序播放int clicktimes = 0;public void changeMode(View view) {switch (clicktimes){case 0://随机 --> 顺序clicktimes++;changeMode(clicktimes);break;case 1://顺序 --> 单曲clicktimes++;changeMode(clicktimes);break;case 2://单曲 --> 随机clicktimes = 0;changeMode(clicktimes);break;default:break;}}private void changeMode(int playmode) {editor.putInt("play_mode",playmode).commit();playMode.setBackgroundResource(modepic[playmode]);}

其实这里最关键的不是上面的代码,而是播放器里的控制,模式更改后,当前音乐播放完成后要根据用户选择的模式来播放新的音乐,需要设置监听 mediaPlayer.setOnCompletionListener,然后根据 SharedPreferences 里的模式来播放音乐,是顺序播放还是随机播放,我的services里没有音乐列表,所以需要从activity里先获取音乐列表,以及当前播放的哪首音乐,

单曲循环时播放器的url不需要更改,顺序播放时取得下一首位置:curposition = (++curposition) % musiclist.size()

随机播放时取得下一首位置:curposition = (new Random()).nextInt(musiclist.size());

关键代码如下

// 监听播放是否完成mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {//我目前也不知道该干嘛,下一首嘛playnew();}});private void playnew() {switch (MusicActivity.sharedPreferences.getInt("play_mode",-1)){case 0://随机curposition = (new Random()).nextInt(musiclist.size());url =  musiclist.get(curposition ).getUrl();palyer();break;case 1://顺序curposition = (++curposition) % musiclist.size();url =  musiclist.get(curposition ).getUrl();palyer();break;case 2://单曲url =  musiclist.get(curposition ).getUrl();palyer();break;default:break;}}

以上基本就可以实现自己控制播放模式了,
接着实现摇一摇切歌:这个功能我直接写在service里了,切歌时震动一下,需要在 AndroidManifest.xml 里添加权限

 <!--震动--><uses-permission android:name="android.permission.VIBRATE"/>

摇一摇需要用到加速传感器,传感器Android底层都给我们实现好了,直接实现接口implements SensorEventListener

主要代码:

private SensorManager sensorManager = null;//传感器
private Vibrator vibrator = null;//震动
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
//取得震动服务的句柄
vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
//加速度传感器(accelerometer)、陀螺仪(gyroscope)、环境光照传感器(light)、磁力传感器(magnetic field)、方向传感器(orientation)、压力传感器(pressure)、距离传感器(proximity)和温度传感器(temperature)。
// http://www.open-open.com/lib/view/open1378259498734.html
sensorManager.registerListener(this,sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);@Override
public void onSensorChanged(SensorEvent event) {if(MusicActivity.sharedPreferences.getInt("play_accelerometer",0) == 0){// 传感器报告新的值int sensorType = event.sensor.getType();//values[0]:X轴,values[1]:Y轴,values[2]:Z轴float[] values = event.values;if (sensorType == Sensor.TYPE_ACCELEROMETER){if ((Math.abs(values[0]) > 17 || Math.abs(values[1]) > 17 || Math.abs(values[2]) > 17)){Log.i("slack", "sensor x values[0] = " + values[0]);Log.i("slack", "sensor y values[1] = " + values[1]);Log.i("slack", "sensor z values[2] = " + values[2]);playnew();//摇动手机后,再伴随震动提示~~vibrator.vibrate(500);}}}
}@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {//传感器精度的改变
}

基本就完成了

附件:module源码下载:http://download.csdn.net/detail/i_do_can/9485662

git地址:https://github.com/CL-window/Music

Android之简单本地音乐播放器相关推荐

  1. android 存放音频文件夹里,Android 实现简单的音乐播放器效果(音频文件的三种存放)...

    Android 实现简单的音乐播放器效果(音频文件的三种存放).三种方法主要使用到的类 MediaPlayer.create() getAssets() new Mediaplayer() - 几个控 ...

  2. Android 编程案例-本地音乐播放器源码及使用注意事项

    说一下代码在用的时候注意事项以及在运行的时候可能遇到的问题: 首先代码可以在创建相应文件后直接复制,这个案例用到了RecyclerView,所以需要先添加依赖.添加下面两个: implementati ...

  3. Android 一个简单的音乐播放器

    前言: 这次算是第三次自己做音乐播放器了,一次比一次进步一些啦.不过感觉还是太简陋了,哈哈.技术差... 效果图: 电脑配置比较差,所以模拟器有些卡,效果图也看到有些卡顿. App主要就是分两部分:数 ...

  4. Android开发之本地音乐播放器(二)

    此次音乐播放器是针对上一个:https://blog.csdn.net/qq_43433255/article/details/88084420 开发出来的一个功能增强型,基本实现功能为: 通过列表管 ...

  5. Android 简单的本地音乐播放器Demo

    一个小小的本地音乐播放器,花了几个小时完成的,帮朋友做的毕业作业. 包含基本播放功能.进度条显示和拖拽.时间倒计.后台播放.一键刷新.收藏操作.单独播放收藏页的音乐.... 代码没有一定的模式和注释, ...

  6. Android开发做一个简单的音乐播放器

    Android开发如何做一个简单的音乐播放器,首先我们先要知道用到的知识点有哪些. 1.MediaPlayer:可以播放本地资源.sd卡内存资源以及网络uri资源,在这里我们播放sd卡上的音乐资源. ...

  7. android 简单的音乐播放器实现播放模式的切换

    以前写过一篇简单的音乐播放器,但是这个播放器没有实现播放模式的切换,在项目中要实现两个播放模式,循环播放和随机播放,经过这两天的努力搞定了,界面比较粗糙.可以先看一下前面的简单音乐播放器,详细的就不说 ...

  8. android 简单的音乐播放器

    在项目开发过程中需要一个简单的音频播放的功能,需求很简单,只需要能够播放一个指定文件夹的全部mp3和wav音频文件就可以,谷歌给我们提供了一套比较完整的API,使得我们可以很简单的写出一个简易的音乐播 ...

  9. [HTML5]简单网页本地音乐播放器

    既然HTML5提出与本地交互方便,就想写个HTML5的本地音乐播放器.一开始问题主要集中在怎么读取本地文件路径,我想肯定可以用JS实现去操作本地文件(因为node.js很容易实现读取本地文件,但是原生 ...

最新文章

  1. linux 目录说明
  2. as本地仓库更改_Android Studio 之 Gradle与Project Structure详解
  3. 图解python_图解Python深拷贝和浅拷贝
  4. 2月第3周国内域名商TOP10:爱名网排名升至第八
  5. 0909 学习操作系统
  6. 拓端tecdat|python使用MongoDB,Seaborn和Matplotlib文本分析和可视化API数据
  7. 【物理世界】Ψ的前世今生
  8. [李景山php] web 安全资料篇
  9. Java是什么,Java是什么意思
  10. Seventh season fifteenth episode,Joey got a new brain??????
  11. 180天如何突击高考-从400到550?
  12. 2022-渗透测试-xss小游戏通关
  13. 好友推荐(列转行,help_topic_id)
  14. ibm x服务器硬盘检测,IBM System x 服务器自带RAID1的故障恢复
  15. bmp文件数字水印c语言代码,图像数字水印+matlab程序文件.doc
  16. left join on左连接的使用
  17. Microsoft Office
  18. 关于学校毕业论文查重率的问题
  19. 【ACA认证】阿里云云计算助理工程师认证(ACA)
  20. 地理定位(高德地图官方文档)

热门文章

  1. AI智能车牌识别技术如何提升出行体验?
  2. C#中如何隐藏滚动条(ScrollBar)同时又具备自动滚动的功能
  3. R绘图 第十篇:绘制散点图(高级)
  4. linux系统性能监控--内存利用率
  5. LLDP 链路发现协议
  6. 【机器学习 - 8】:随机梯度下降法
  7. JMeter基础系列(八) JMeter断言之JSON断言
  8. 每日一题 No.4 男女搭配干活不累
  9. (详细)华为荣耀8X JSN-AL00的usb调试模式在哪里开启的教程
  10. 数组统计问题(统计各学生的优秀率及格率)C语言