博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于媒体库音乐播放器
阅读量:3971 次
发布时间:2019-05-24

本文共 24404 字,大约阅读时间需要 81 分钟。

文章目录

创建安卓项目

在这里插入图片描述

创建ui,service,entity,dal,bll,app,adapter子目录

在这里插入图片描述

将图片素材放入drawable中

在这里插入图片描述

创建按钮背景图片选择器

在这里插入图片描述

  • next_button_selector.xml
  • play_button_selector.xml
  • previous_button_selector.xml
  • pause_button_selector.xml

编写custom_border.xml

在这里插入图片描述

创建anim包里面创建animator.xml

在这里插入图片描述

创建menu包里面创建main.xml

在这里插入图片描述

编写布局文件activity_splash_screen.xml

在这里插入图片描述

字符串资源文件strings.xml

基于媒体库音乐播放器V1.0
基于媒体库音乐播放器
Version 1.0
泸职院信息系·华卫
默认排序
按标题排序
按时长排序
播放模式:
顺序
单曲循环
随机

编写音乐名列表项模板music_list_item.xml

在这里插入图片描述

编写主布局文件activity_main.xml

在这里插入图片描述

编写ui子包里的SplashScreenActivity(启动画面)

在这里插入图片描述

package com.zjs.ms_music_player_v01.ui;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.widget.ImageView;import com.zjs.ms_music_player_v01.R;/** * 启动界面类 * */public class SplashScreenActivity extends Activity {    /**     * 动画对象     */    private Animation animation;    /**     * 音乐图标图像控件     */    private ImageView ivMusicIcon;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 利用布局资源文件设置用户界面        setContentView(R.layout.activity_splash_screen);        // 通过资源标识获得控件实例        ivMusicIcon = findViewById(R.id.iv_music_icon);        // 加载动画资源文件,创建动画对象        animation = AnimationUtils.loadAnimation(this, R.anim.animator);        // 让音乐图标图像控件启动动画        ivMusicIcon.startAnimation(animation);        // 给动画对象设置监听器        animation.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                // 启动主界面                startActivity(new Intent(SplashScreenActivity.this, MainActivity.class));                // 关闭启动界面                finish();            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });    }}

在app子包里面创建音乐播放器应用程序类 - MusicPlayerApplication

在这里插入图片描述

package com.zjs.ms_music_player_v01.service;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.media.MediaPlayer;import android.os.IBinder;import com.zjs.ms_music_player_v01.R;import com.zjs.ms_music_player_v01.app.AppConstants;import com.zjs.ms_music_player_v01.app.MusicPlayerApplication;import com.zjs.ms_music_player_v01.entity.Music;import java.io.IOException;import java.util.List;import java.util.Random;/** * 音乐服务类 */public class MusicPlayService extends Service implements AppConstants {    /**     * 媒体播放器     */    private MediaPlayer mp;    /**     * 音乐列表(数据源)     */    private List
musicList; /** * 音乐文件名 */ private String musicName; /** * 更新音乐播放进度的线程 */ private Thread thread; /** * 线程循环控制变量 */ private boolean isRunning; /** * 音乐播放器应用程序 */ private MusicPlayerApplication app; /** * 音乐广播接收器 */ private MusicReceiver receiver; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); // 获取获得音乐播放器应用程序对象 app = (MusicPlayerApplication) getApplication(); // 获取音乐列表(数据源) musicList = app.getMusicList(); // 创建媒体播放器 mp = new MediaPlayer(); // 给媒体播放器起注册完成监听器 mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // 切换到下一首音乐 nextMusic(); } }); // 设置线程循环控制变量为真 isRunning = true; // 创建线程更新播放进度 thread = new Thread(new Runnable() { @Override public void run() { while (isRunning) { // 判断音乐是否在播放 if (mp.isPlaying()) { // 设置音乐当前播放位置 app.setCurrentPosition(mp.getCurrentPosition()); // 创建意图 Intent intent = new Intent(); // 设置广播频道:更新播放进度 intent.setAction(INTENT_ACTION_UPDATE_PROGRESS); // 让意图携带播放时长 intent.putExtra(DURATION, mp.getDuration()); // 让意图携带控制图标(暂停图标) intent.putExtra(CONTROL_ICON, R.drawable.pause_button_selector); // 按意图发送广播 sendBroadcast(intent); } // 让线程睡眠500毫秒 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }); // 启动线程 thread.start(); // 创建音乐广播接收者 receiver = new MusicReceiver(); // 创建意图过滤器 IntentFilter filter = new IntentFilter(); // 通过意图过滤器添加广播频道 filter.addAction(INTENT_ACTION_PLAY_OR_PAUSE); filter.addAction(INTENT_ACTION_PLAY); filter.addAction(INTENT_ACTION_PREVIOUS); filter.addAction(INTENT_ACTION_NEXT); filter.addAction(INTENT_ACTION_USER_CHANGE_PROGRESS); // 注册广播接收者 registerReceiver(receiver, filter); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 返回非粘性服务 return Service.START_NOT_STICKY; } /** * 上一首音乐 */ private void previousMusic() { // 更新音乐索引 if (app.getCurrentMusicIndex() > 0) { app.setCurrentMusicIndex(app.getCurrentMusicIndex() - 1); } else { app.setCurrentMusicIndex(musicList.size() - 1); } // 当前播放位置归零 app.setCurrentPosition(0); // 调用播放方法 play(); } /** * 下一首音乐 */ private void nextMusic() { // 根据播放模式来更新音乐索引 switch (app.getPlayMode()) { // 顺序播放模式 case PLAY_MODE_ORDER: if (app.getCurrentMusicIndex() < musicList.size() - 1) { app.setCurrentMusicIndex(app.getCurrentMusicIndex() + 1); } else { app.setCurrentMusicIndex(0); } break; // 随机播放模式 case PLAY_MODE_RANDOM: // 随机设置索引 app.setCurrentMusicIndex(new Random().nextInt(app.getMusicList().size())); break; // 单曲循环模式 case PLAY_MODE_LOOP: // 音乐索引保持不变 break; } // 当前播放位置归零 app.setCurrentPosition(0); // 调用播放方法 play(); } /** * 播放方法 */ private void play() { try { // 重置播放器 mp.reset(); // 获取当前播放的音乐名 musicName = musicList.get(app.getCurrentMusicIndex()).getData(); // 设置播放源 mp.setDataSource(musicName); // 缓冲播放源,加载到内存 mp.prepare(); // 定位到暂停时的播放位置 mp.seekTo(app.getCurrentPosition()); // 启动音乐的播放 mp.start(); } catch (IOException e) { e.printStackTrace(); } } /** * 暂停方法 */ private void pause() { // 暂停播放 mp.pause(); // 保存当前音乐播放位置 app.setCurrentPosition(mp.getCurrentPosition()); /* 发送广播给前台MainActivity,更改图标、更改播放进度 */ // 创建意图 Intent intent = new Intent(); // 设置广播频道:更新播放进度 intent.setAction(INTENT_ACTION_UPDATE_PROGRESS); // 让意图携带播放时长 intent.putExtra(DURATION, mp.getDuration()); // 让意图携带控制图标(播放图标) intent.putExtra(CONTROL_ICON, R.drawable.play_button_selector); // 按意图发送广播 sendBroadcast(intent); } /** * 音乐广播接收者 */ private class MusicReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 获取意图动作(广播频道) String action = intent.getAction(); // 当广播频道非空时进行判断 if (action != null) { // 根据不同广播频道执行不同的操作 switch (action) { case INTENT_ACTION_PLAY: // 播放进度值归零 app.setCurrentPosition(0); // 调用播放方法 play(); break; case INTENT_ACTION_PLAY_OR_PAUSE: // 判断音乐是否在播放 if (mp.isPlaying()) { pause(); } else { play(); } break; case INTENT_ACTION_PREVIOUS: // 切换到上一首音乐 previousMusic(); break; case INTENT_ACTION_NEXT: // 切换到下一首音乐 nextMusic(); break; case INTENT_ACTION_USER_CHANGE_PROGRESS: // 根据拖拽条的进度值计算当前播放位置 app.setCurrentPosition(app.getProgressChangedByUser() * mp.getDuration() / 100); // 根据音乐当前播放位置开始播放音乐 play(); break; } } } } /** * 销毁回调方法 */ @Override public void onDestroy() { super.onDestroy(); // 释放媒体播放器 if (mp != null) { mp.release(); mp = null; } // 注销广播接收者 unregisterReceiver(receiver); // 设置线程循环控制变量 isRunning = false; // 销毁子线程 thread = null; }}

在entity子包里面创建音乐实体类 - Music

在这里插入图片描述

package com.zjs.ms_music_player_v01.entity;/** * 音乐实体类 */public class Music {    /**     * 标识符     */    private long id;    /**     * 音乐数据(完整文件名)     */    private String data;    /**     * 音乐显示名称     */    private String displayName;    /**     * 音乐标题     */    private String title;    /**     * 音乐播放时长     */    private int duration;    /**     * 音乐图标键值     */    private String albumKey;    /**     * 演唱者或演奏者     */    private String artist;    public long getId() {        return id;    }    public void setId(long id) {        this.id = id;    }    public String getData() {        return data;    }    public void setData(String data) {        this.data = data;    }    public String getDisplayName() {        return displayName;    }    public void setDisplayName(String displayName) {        this.displayName = displayName;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public int getDuration() {        return duration;    }    public void setDuration(int duration) {        this.duration = duration;    }    public String getAlbumKey() {        return albumKey;    }    public void setAlbumKey(String albumKey) {        this.albumKey = albumKey;    }    public String getArtist() {        return artist;    }    public void setArtist(String artist) {        this.artist = artist;    }    @Override    public String toString() {        return "Music{" +                "id=" + id +                ", data='" + data + '\'' +                ", displayName='" + displayName + '\'' +                ", title='" + title + '\'' +                ", duration=" + duration +                ", albumKey='" + albumKey + '\'' +                ", artist='" + artist + '\'' +                '}';    }}

编写音乐数据访问对象musicdao.java

在这里插入图片描述

package com.zjs.ms_music_player_v01.dal;import android.content.ContentResolver;import android.content.Context;import android.database.Cursor;import android.provider.MediaStore;import com.zjs.ms_music_player_v01.entity.Music;import java.util.ArrayList;import java.util.List;/** * 音乐数据访问对象 */public class MusicDao {    /**     * 上下文环境     */    private Context context;    /**     * 构造方法:指定使用该MusicDao的上下文环境     *     * @param context     */    public MusicDao(Context context) {        this.context = context;    }    /**     * 获取音乐数据列表     *     * @return     */    public List
getMusicList() { /* 1. 访问媒体库,获取音频游标对象 */ // 获取内容解析者,对媒体库这个内容提供者进行操作 ContentResolver resolver = context.getContentResolver(); // 实现查询(筛选播放时长不低于1分钟的音频),获取游标对象,作为数据源 Cursor cursor = resolver.query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, // 参数1:查询目标 new String[]{MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.ALBUM_KEY, MediaStore.Audio.Media.ARTIST}, // 参数2:查询字段列表 MediaStore.Audio.Media.DURATION + " >= ?", // 参数3:查询条件,包含占位符 new String[]{"60000"}, // 参数4:占位符对应的值列表 null // 参数:排序字段 ); /* 2. 将游标对象转换成音乐列表 */ List
musicList = null; if (cursor.getCount() > 0) { musicList = new ArrayList<>(); while (cursor.moveToNext()) { // 实例化音乐对象 Music music = new Music(); // 设置音乐对象属性 music.setId(cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID))); music.setData(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))); music.setDisplayName(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))); music.setTitle(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE))); music.setDuration(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))); music.setAlbumKey(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_KEY))); music.setArtist(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))); // 将音乐对象添加到音乐列表 musicList.add(music); } } // 关闭游标 if (cursor != null && !cursor.isClosed()) { cursor.close(); } // 返回音乐列表 return musicList; }}

编写音乐业务类musicbiz.java

在这里插入图片描述

package com.zjs.ms_music_player_v01.bll;import android.content.Context;import com.zjs.ms_music_player_v01.dal.MusicDao;import com.zjs.ms_music_player_v01.entity.Music;import java.util.List;/** * 音乐业务类 */public class MusicBiz {    /**     * 上下文环境     */    private Context context;    public MusicBiz(Context context) {        this.context = context;    }    /**     * 获取音乐列表     *     * @return     */    public List
getMusicList() { return new MusicDao(context).getMusicList(); }}

编写音乐播放器应用程序类musicplayerapplication.java

在这里插入图片描述

package com.zjs.ms_music_player_v01.app;import android.app.Application;import android.content.SharedPreferences;import com.zjs.ms_music_player_v01.bll.MusicBiz;import com.zjs.ms_music_player_v01.entity.Music;import java.text.SimpleDateFormat;import java.util.Collections;import java.util.Comparator;import java.util.List;/** * 音乐播放器应用程序类 */public class MusicPlayerApplication extends Application implements AppConstants{    /**     * 简单日期格式     */    private SimpleDateFormat sdf;    /**     * 音乐列表(播放数据源)     */    private List
musicList; /** * 当前音乐索引 */ private int currentMusicIndex; /** * 音乐当前播放位置 */ private int currentPosition; /** * 播放模式 */ private int playMode; /** * 用户修改的播放进度 */ private int progressChangedByUser; @Override public void onCreate() { super.onCreate(); // 实例化简单日期对象 sdf = new SimpleDateFormat("mm:ss"); // 获得音乐列表(数据源) musicList = new MusicBiz(this).getMusicList(); // 读取排序设置 SharedPreferences sp = getSharedPreferences(USER_CONFIG, MODE_PRIVATE); String orderBy = sp.getString("order-by", "default"); if (orderBy.equals("default")) { // 默认排序 Collections.sort(musicList, new Comparator
() { @Override public int compare(Music lhs, Music rhs) { return (int) (lhs.getId() - rhs.getId()); } }); } else if (orderBy.equals("title")) { // 按标题排序 Collections.sort(musicList, new Comparator
() { @Override public int compare(Music lhs, Music rhs) { return lhs.getTitle().compareTo(rhs.getTitle()); } }); } else if (orderBy.equals("duration")) { // 按音乐时长排序 Collections.sort(musicList, new Comparator
() { @Override public int compare(Music lhs, Music rhs) { return lhs.getDuration() - rhs.getDuration(); } }); } } public int getCurrentMusicIndex() { return currentMusicIndex; } public void setCurrentMusicIndex(int currentMusicIndex) { this.currentMusicIndex = currentMusicIndex; } public int getCurrentPosition() { return currentPosition; } public void setCurrentPosition(int currentPosition) { this.currentPosition = currentPosition; } public int getPlayMode() { return playMode; } public void setPlayMode(int playMode) { this.playMode = playMode; } public int getProgressChangedByUser() { return progressChangedByUser; } public void setProgressChangedByUser(int progressChangedByUser) { this.progressChangedByUser = progressChangedByUser; } /** * 获取格式化时间 * * @param time 单位是毫秒 * @return mm:ss格式的时间 */ public String getFormatTime(int time) { return sdf.format(time); } /** * 获取音乐列表 * * @return */ public List
getMusicList() { // 返回音乐里列表 return musicList; }}

在app子包里面创建常见应用程序常量接口 - AppConstants

在这里插入图片描述

package com.zjs.ms_music_player_v01.app;/** * 应用程序常量接口 */public interface AppConstants {    /**     * 应用程序标记     */    String TAG  = "net.hw.ms_music_player";    /**     * 广播频道常量:播放上一首     */    String INTENT_ACTION_PREVIOUS = TAG + ".intent.action.PREVIOUS";    /**     * 广播频道常量:播放下一首     */    String INTENT_ACTION_NEXT = TAG + ".intent.action.NEXT";    /**     * 广播频道常量:播放或暂停     */    String INTENT_ACTION_PLAY_OR_PAUSE = TAG + ".intent.action.PLAY_OR_PAUSE";    /**     * 广播频道常量:播放     */    String INTENT_ACTION_PLAY = TAG + ".intent.action.PLAY";    /**     * 广播频道常量:更新播放进度     */    String INTENT_ACTION_UPDATE_PROGRESS = TAG + ".intent.action.UPDATE_PROGRESS";    /**     * 广播频道常量:用户改变播放进度     */    String INTENT_ACTION_USER_CHANGE_PROGRESS = TAG + ".intent.action.USER_CHANGE_PROGRESS";    /**     * 控制图标常量:播放或暂停     */    String CONTROL_ICON = "control_icon";    /**     * 播放时长常量     */    String DURATION = "duration";    /**     * 播放模式:顺序播放     */    int PLAY_MODE_ORDER = 0;    /**     * 播放模式:随机播放     */    int PLAY_MODE_RANDOM = 1;    /**     * 播放模式:单曲循环     */    int PLAY_MODE_LOOP = 2;    /**     * 用户配置文件名     */    String USER_CONFIG = "user-config";}

编写项目清单文件

在这里插入图片描述

在adapter子包里面创建音乐适配器 - MusicAdapter

在这里插入图片描述

package com.zjs.ms_music_player_v01.adapter;import android.app.Activity;import android.content.ContentResolver;import android.content.Context;import android.database.Cursor;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.provider.MediaStore;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import com.zjs.ms_music_player_v01.R;import com.zjs.ms_music_player_v01.app.MusicPlayerApplication;import com.zjs.ms_music_player_v01.entity.Music;import java.util.ArrayList;import java.util.List;/** * 音乐适配器 * * Created by howard on 2018/1/22. */public class MusicAdapter extends BaseAdapter {    /**     * 上下文环境     */    private Context context;    /**     * 音乐列表     */    private List
musicList; /** * 音乐播放器应用程序 */ private MusicPlayerApplication app; /** * 构造方法 * * @param context * @param musicList */ public MusicAdapter(Context context, List
musicList) { this.context = context; if (musicList == null) { musicList = new ArrayList<>(); } this.musicList = musicList; // 获取应用程序对象 app = (MusicPlayerApplication) ((Activity)context).getApplication(); } /** * 获取列表项个数 * * @return */ @Override public int getCount() { return musicList.size(); } /** * 获取列表项对象 * * @param position * @return */ @Override public Object getItem(int position) { return musicList.get(position); } /** * 获取列表项标识符 * * @param position * @return */ @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // 声明视图容器 ViewHolder holder; // 判断转换视图是否为空 if (convertView == null) { // 通过布局填充器将列表项模板映射成转换视图 convertView = LayoutInflater.from(context).inflate(R.layout.music_list_item, null); // 实例化视图容器 holder = new ViewHolder(); // 获取视图容器里控件实例 holder.ivImage = convertView.findViewById(R.id.iv_image); holder.tvArtist = convertView.findViewById(R.id.tv_artist); holder.tvDisplayName = convertView.findViewById(R.id.tv_display_name); holder.tvDuration = convertView.findViewById(R.id.tv_duration); // 将视图容器附加到转换视图 convertView.setTag(holder); } else { // 从转换视图里获取视图容器 holder = (ViewHolder) convertView.getTag(); } // 获取音乐数据 final Music music = musicList.get(position); /* 设置视图容器里控件属性 */ // 设置专辑封面图片 Bitmap cover = getAlbumCover(music.getAlbumKey()); if (cover != null) { holder.ivImage.setImageBitmap(cover); } else { holder.ivImage.setImageResource(R.drawable.music); } // 设置演唱者 holder.tvArtist.setText(music.getArtist()); // 设置显示名 holder.tvDisplayName.setText(music.getDisplayName().substring(0, music.getDisplayName().lastIndexOf("."))); // 设置播放时长 holder.tvDuration.setText(app.getFormatTime(music.getDuration())); // 返回转换视图 return convertView; } /** * 视图容器 */ private static class ViewHolder { ImageView ivImage; // 音乐专辑图片 TextView tvArtist; // 演唱者标签 TextView tvDuration; // 音乐时长标签 TextView tvDisplayName; // 音乐显示名标签 } /** * 按专辑键获取专辑图片 * * @param albumKey * @return */ private Bitmap getAlbumCover(String albumKey) { // 声明位图对象 Bitmap bitmap = null; // 获取内容解析者 ContentResolver resolver = context.getContentResolver(); // 按albumKey查询 Cursor cursor = resolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, // 查询目标 new String[] { MediaStore.Audio.Albums.ALBUM_ART }, // 投影字段 MediaStore.Audio.Albums.ALBUM_KEY + " = ?", // 筛选条件 new String[] { albumKey }, // 条件参数 null // 排序字段 ); // 移到第一条记录 if (cursor.moveToFirst()) { // 获取专辑封面图片路径 String albumPath = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART)); // 解析生成位图对象 bitmap = BitmapFactory.decodeFile(albumPath); } // 返回位图对象 return bitmap; }}

转载地址:http://ijtki.baihongyu.com/

你可能感兴趣的文章
Linux如何查询内存真实利用率
查看>>
Groovy 集合
查看>>
帮助软件开发者提高效率的10个小窍门
查看>>
如何进行有效的代码检查
查看>>
ORA-01502:索引或这类索引的分区处于不可用状态
查看>>
oracle 一次诊断和解决CPU利用率高的问题分析
查看>>
解决MyEclipse吃内存,让MyEclipse飞起来,MyEclipse速度
查看>>
Available Memory is low
查看>>
读v_JULY_v整理笔试题博客有感,整理些答案。
查看>>
第一范式,第二范式,第三范式
查看>>
JS及java验证 IPV6,IPV4地址的 正则表达式
查看>>
fastjson深度源码解析- 序列化(一) - 序列化基础类型解析
查看>>
自己动手编译JDK
查看>>
fastjson深度源码解析- 序列化(二) - 序列化字节和字符串解析
查看>>
fastjson深度源码解析- 序列化(三) - 序列化字段属性键值对
查看>>
fastjson深度源码解析- 序列化(四) - json序列化实现解析
查看>>
fastjson深度源码解析- 序列化(五) - json内部注册序列化解析
查看>>
fastjson深度源码解析- 序列化(六) - json特定序列化实现解析
查看>>
fastjson深度源码解析- 词法和语法解析(一) - token定义解析
查看>>
fastjson深度源码解析- 词法和语法解析(二) - 基础类型实现解析
查看>>