迷你播放器--第一阶段(1)

检索音乐并添加到List播放列表--媒体库的检索以及list列表使用

本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/article/details/38345805

查看项目源代码请前往:迷你播放器-综述

请注意,该项目为android项目,如果已经学习过这一节请阅读下一篇。

先上效果图

本节只是简单的实现一个播放器界面,功能简单,仅包含一个播放列表。

主要处理三个问题

    • 列表适配器
    • 内存卡音乐扫描
    • 播放器播放完成监听

1、列表适配器

ListView是手机系统上用的很广泛的一种组件,它可以以垂直列表的形式显示所有列表项。如果我们想要对ListView的外观、行为等进行定制,那么就得把ListView作为AdapterView使用,通过Adapter控制每个列表项的外观和行为。
Adapter本身只是一个接口,它派生了ListAdapter和SpinnerAdapter两个子接口,更多资料请自行在站内搜索。Adapter常用的实现类如下
→ArrayAdapter:简单易用,通常用于显示数组或者List集合的多个值包装成得多个列表项;
→SimpleAdapter:不简单呵,功能非常强大,用于将List集合的多个对象包装成多个列表项;
→SimpleCursorAdapter:和SimpleAdapter基恩类似,作用对象不一样,为Cursor;
→BaseAdapter:通常用于扩展,能够实现最大限度的定制。因为播放器也是基于BaseAdapter进行扩展。
先制作一个用于显示每个item的view,每个item我们希望包含歌曲名字,艺术家,播放时间,播放状态,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="fill_parent"android:layout_height="fill_parent"android:minHeight="50dp"android:orientation="vertical"android:padding="5dp" ><RelativeLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_weight="1"android:descendantFocusability="blocksDescendants" ><TextViewandroid:id="@+id/musiclistPos"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:textColor="#ffffff"android:textStyle="bold" /><TextViewandroid:id="@+id/musicTime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginLeft="5dp"android:singleLine="true"android:textColor="#ffffff"android:textStyle="bold" /><TextViewandroid:id="@+id/musicName"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_toLeftOf="@id/musicTime"android:layout_toRightOf="@id/musiclistPos"android:singleLine="true"android:textColor="#ffffff"android:textStyle="bold" /></RelativeLayout><RelativeLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_weight="1"android:orientation="horizontal" ><TextViewandroid:id="@+id/musicAritst"android:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:textColor="#cccccc" /><ImageViewandroid:id="@+id/musicplaystate"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:background="@drawable/ic_pause"android:visibility="visible"tools:ignore="ContentDescription" ></ImageView></RelativeLayout></LinearLayout>
然后基于这一个view进行扩展BaseAdapter(主要在getView部分)。在这一部分我们要注意的是,如果convertView为非空的话就无需再新建了,直接读取使用,是需要修改显示即可。因为不需要新建view,程序的执行效率能够得到提升,另外还能防止内存泄露。
package com.liangrensheng.music_player.adapter;import java.util.List;import com.liangrensheng.music_player.R;
import com.liangrensheng.music_player.player.MusicData;
import com.liangrensheng.music_player.player.MusicPlayState;import android.view.View;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;/*** 音乐播放列表的Adapter,继承于BaseAdapter* * @author 梁仁生*/
public class ListViewAdapter extends BaseAdapter {private List<MusicData> mFileList;private LayoutInflater mLayoutInflater;private int mCurPlayMusicIndex;private int mPlayState;public ListViewAdapter(Context context, List<MusicData> FileList) {mFileList = FileList;mLayoutInflater = LayoutInflater.from(context);mCurPlayMusicIndex = -1;mPlayState = MusicPlayState.S_PREPARE;}public void refreshAdapter(List<MusicData> FileList) {// 更新Adapter列表内容mFileList = FileList;notifyDataSetChanged();// 用于提醒UI更新}public void setPlayState(int playIndex, int playState) {// 播放状态改变时,刷新列表mCurPlayMusicIndex = playIndex;mPlayState = playState;notifyDataSetChanged();}public int getCurPlayIndex() {return mCurPlayMusicIndex;}public int getCurPlayState() {return mPlayState;}@Overridepublic int getCount() {return mFileList.size();}@Overridepublic Object getItem(int position) {return position;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 加载列表单元if (convertView == null) {// 如果存在则不在构造,可以防止内存泄露,还可提高加载速度convertView = mLayoutInflater.inflate(R.layout.listview_item, null);}// 播放状态showPlayStateIcon(convertView, position);// 曲目序号TextView posTextView = (TextView) convertView.findViewById(R.id.musiclistPos);String strPosString = String.valueOf(position + 1) + ".";posTextView.setText(strPosString);// 歌名TextView nametTextView = (TextView) convertView.findViewById(R.id.musicName);nametTextView.setText(mFileList.get(position).mMusicName);// 播放时间TextView timeTextView = (TextView) convertView.findViewById(R.id.musicTime);int time = mFileList.get(position).mMusicTime;timeTextView.setText(formatTime(time));// 艺术家TextView pathTextView = (TextView) convertView.findViewById(R.id.musicAritst);pathTextView.setText(mFileList.get(position).mMusicAritst);return convertView;}private void showPlayStateIcon(View view, int position) {ImageView imageView = (ImageView) view.findViewById(R.id.musicplaystate);if (position != mCurPlayMusicIndex) {imageView.setVisibility(View.GONE);return;}imageView.setVisibility(View.VISIBLE);if (mPlayState != MusicPlayState.S_PLAYING) {// 非播放状态都显示为暂停imageView.setBackgroundResource(R.drawable.ic_pause);} else {imageView.setBackgroundResource(R.drawable.ic_play);}}private static String formatTime(int time) {int min = time / (1000 * 60);String sec = time % (1000 * 60) + "";if (sec.length() < 2) {sec += "000";}return min + ":" + sec.trim().substring(0, 2);}}
另外,我们还得在activity里设置点击操作,具体如下。这里主要实现的功能是播放选中的项目,需要在类声明implementation一个OnCompletionListener。
    /*** 点击了列表里的第position项进行的操作* * @param position*/@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {playIndex(position);// 播放这一首音乐}/*** 播放第index首音乐*/private void playIndex(int index) {if (mListViewAdapter.getCurPlayIndex() == index) {// 如果曲目相同if (mListViewAdapter.getCurPlayState() == MusicPlayState.S_PLAYING) {mplayer.pause();// 正在播放则暂停,否则播放mListViewAdapter.setPlayState(index, MusicPlayState.S_PAUSE);} else {mplayer.start();// 我们还要更新列表显示播放状态~mListViewAdapter.setPlayState(index, MusicPlayState.S_PLAYING);}} else {// 重新缓冲曲目try {mplayer.reset();String currentMusic = m_MusicFileList.get(index).mMusicPath;mplayer.setDataSource(currentMusic);mplayer.prepare();mplayer.start();mListViewAdapter.setPlayState(index, MusicPlayState.S_PLAYING);} catch (Exception e) {System.out.println("歌曲不存在或权限不足");}}}

2、内存卡扫描

客官真不会自己去扫描内存卡里面的媒体文件吧,,,真得这么做的话,如果代码弄不好,说不定程序得跑扫描很长时间才行,还会造成UI的卡顿。其实,Android是很强大的,如果知道怎么调用android的api的话,什么事都好办。当手机或模拟器开机时,android会调用MediaScanner,扫描SD卡和内存里的文件然后保存在contentProvider下。认真看一下eclipse的locat,是不是发现类似的 DEBUG/MediaScannerService(349): getDefaultLocale =zh_CN ,哈哈^_^,这就对了,我们直接调用api去检索就行了,怎么弄呢,上代码
    /*** 获取歌曲列表*/private List<MusicData> getMusicFileList() {List<MusicData> list = new ArrayList<MusicData>();// 用于保存检索结果的字符串数组String[] projection = new String[] { BaseColumns._ID,MediaColumns.TITLE, AudioColumns.DURATION, MediaColumns.DATA,AudioColumns.ARTIST };Cursor cursor = getContentResolver().query(Media.EXTERNAL_CONTENT_URI,projection, null, null, null);if (cursor != null) {cursor.moveToFirst();int colNameIndex = cursor.getColumnIndex(MediaColumns.TITLE);int colTimeIndex = cursor.getColumnIndex(AudioColumns.DURATION);int colPathIndex = cursor.getColumnIndex(MediaColumns.DATA);int colArtistIndex = cursor.getColumnIndex(AudioColumns.ARTIST);int fileNum = cursor.getCount();for (int counter = 0; counter < fileNum; counter++) {// 保存cursor获取的信息,记录入musicData类中MusicData data = new MusicData();data.mMusicName = cursor.getString(colNameIndex);data.mMusicTime = cursor.getInt(colTimeIndex);data.mMusicPath = cursor.getString(colPathIndex);data.mMusicAritst = cursor.getString(colArtistIndex);if (data.mMusicTime > 50)// 过滤音乐,大于0.05秒 才放入列表显示list.add(data);cursor.moveToNext();}cursor.close();// 关闭cursor}return list;}

3、播放器播放完成监听

播放完成事件监听其实是蛮容易实现的,只有implement一个OnCompletionListener,然后再重写事件public void onCompletion(MediaPlayer mp)即可。通过监听完成时间我们可以实现播放器的播放模式,比如单曲循环,顺序播放,列表循环,随机播放等
    /*** 当前音乐播放完毕执行的操作,为了简便,我这里暂时设为列表循环播放*/@Overridepublic void onCompletion(MediaPlayer mp) {if (mListViewAdapter.getCurPlayIndex() == mListViewAdapter.getCount() - 1) {// 若已经是最后一首,则播放第一首playIndex(0);} else {playIndex(mListViewAdapter.getCurPlayIndex() + 1);}}

→这是本节播放器播放内容activity对应的全部代码

package com.liangrensheng.music_player.activity;import java.util.ArrayList;
import java.util.List;import com.liangrensheng.music_player.R;
import com.liangrensheng.music_player.adapter.ListViewAdapter;
import com.liangrensheng.music_player.player.MusicData;
import com.liangrensheng.music_player.player.MusicPlayState;import android.app.Activity;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.MediaStore.Audio.AudioColumns;
import android.provider.MediaStore.Audio.Media;
import android.provider.MediaStore.MediaColumns;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;public class MyMusic extends Activity implements OnCompletionListener,OnItemClickListener {private MediaPlayer mplayer;// 媒体播放器private List<MusicData> m_MusicFileList; // 音乐列表private ListViewAdapter mListViewAdapter;// 列表适配器@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mplayer = new MediaPlayer();// 新建一个媒体播放器mplayer.setOnCompletionListener(this);// 播放完成监听器m_MusicFileList = getMusicFileList();// 扫描本地音乐获取音乐播放列表mListViewAdapter = new ListViewAdapter(this, m_MusicFileList);ListView mListView = (ListView) findViewById(R.id.listView);// 显示音乐mListView.setAdapter(mListViewAdapter);mListView.setOnItemClickListener(this);}/*** 播放第index首音乐*/private void playIndex(int index) {if (mListViewAdapter.getCurPlayIndex() == index) {// 如果曲目相同if (mListViewAdapter.getCurPlayState() == MusicPlayState.S_PLAYING) {mplayer.pause();// 正在播放则暂停,否则播放mListViewAdapter.setPlayState(index, MusicPlayState.S_PAUSE);} else {mplayer.start();// 我们还要更新列表显示播放状态~mListViewAdapter.setPlayState(index, MusicPlayState.S_PLAYING);}} else {// 重新缓冲曲目try {mplayer.reset();String currentMusic = m_MusicFileList.get(index).mMusicPath;mplayer.setDataSource(currentMusic);mplayer.prepare();mplayer.start();mListViewAdapter.setPlayState(index, MusicPlayState.S_PLAYING);} catch (Exception e) {System.out.println("歌曲不存在或权限不足");}}}/*** 获取歌曲列表*/private List<MusicData> getMusicFileList() {List<MusicData> list = new ArrayList<MusicData>();// 用于保存检索结果的字符串数组String[] projection = new String[] { BaseColumns._ID,MediaColumns.TITLE, AudioColumns.DURATION, MediaColumns.DATA,AudioColumns.ARTIST };Cursor cursor = getContentResolver().query(Media.EXTERNAL_CONTENT_URI,projection, null, null, null);if (cursor != null) {cursor.moveToFirst();int colNameIndex = cursor.getColumnIndex(MediaColumns.TITLE);int colTimeIndex = cursor.getColumnIndex(AudioColumns.DURATION);int colPathIndex = cursor.getColumnIndex(MediaColumns.DATA);int colArtistIndex = cursor.getColumnIndex(AudioColumns.ARTIST);int fileNum = cursor.getCount();for (int counter = 0; counter < fileNum; counter++) {// 保存cursor获取的信息,记录入musicData类中MusicData data = new MusicData();data.mMusicName = cursor.getString(colNameIndex);data.mMusicTime = cursor.getInt(colTimeIndex);data.mMusicPath = cursor.getString(colPathIndex);data.mMusicAritst = cursor.getString(colArtistIndex);if (data.mMusicTime > 50)// 过滤音乐,大于0.05秒 才放入列表显示list.add(data);cursor.moveToNext();}cursor.close();// 关闭cursor}return list;}/*** 点击了列表里的第position项进行的操作* * @param position*/@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {playIndex(position);// 播放这一首音乐}/*** 当前音乐播放完毕执行的操作,为了简便,我这里暂时设为列表循环播放*/@Overridepublic void onCompletion(MediaPlayer mp) {if (mListViewAdapter.getCurPlayIndex() == mListViewAdapter.getCount() - 1) {// 若已经是最后一首,则播放第一首playIndex(0);} else {playIndex(mListViewAdapter.getCurPlayIndex() + 1);}}/*** 暂时没有弄好service,设为退出即关闭播放器*/@Overrideprotected void onDestroy() {android.os.Process.killProcess(android.os.Process.myPid());}}

本小节源代码下载 : http://download.csdn.net/detail/lrs0304/7730235

迷你播放器--第一阶段(1)--检索媒体音乐并添加到List播放列表相关推荐

  1. 迷你播放器--第一阶段(4)--内存卡检索不到音乐的错误处理--程序内部空间管理

    迷你播放器--第一阶段(4) 内存卡检索不到音乐的错误处理--程序内部空间管理 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/article/de ...

  2. 迷你播放器--第一阶段(7)--安全攻防第一战--对抗反编译,代码混淆和对抗动态调试

    迷你播放器--第一阶段(7) 安全攻防第一战--对抗反编译,代码混淆和对抗动态调试; 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/article ...

  3. 迷你播放器--第一阶段(6)--添加搜索定位功能(进阶)-使用filter过滤以及对汉语拼音的排序匹配

    迷你播放器--第一阶段(6) 添加搜索定位功能(进阶)-使用filter过滤以及对汉语拼音的排序匹配; 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs030 ...

  4. 迷你播放器--第一阶段(3)--MediaPlayer的封装

    迷你播放器--第一阶段(3) MediaPlayer的封装--利用intent实现消息传递 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/arti ...

  5. 迷你播放器--第一阶段(5)--添加搜索功能--autoCompleteBox的使用

    迷你播放器--第一阶段(5) 添加搜索功能--autoCompleteBox的使用; 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/article ...

  6. 迷你播放器--第一阶段(2)--退出时自动最小化(不是关闭),增加当前播放曲目的跑马灯效果

    迷你播放器--第一阶段(2) 退出时自动最小化(不是关闭),增加当前播放曲目的跑马灯效果 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs0304/artic ...

  7. 做一个迷你播放器放在桌面

    效果如图 功能 随意选取歌曲,循环播放,有音谱效果,音量控制,显示歌曲名,歌曲控制(播放与暂停.下一首和上一首) 操作 将下面文件下载解压后放在MP3音乐文件夹内(该文件用FLASHPACKER打包) ...

  8. (十八)用JAVA编写MP3解码器——迷你播放器

    2019独角兽企业重金招聘Python工程师标准>>> 1.定义解码一帧的接口   ILayer123 Layer1.Layer2和Layer3这三个类都实现了ILayer123的d ...

  9. “安装centOS7.0出现‘你没有创建加载器第一阶段设备,你没有创建可引导分区’,并提示可用空间不足”的解决方案

    前两天花费了很大力气安装CentOS7,终于安装成功了,现在把过程中遇到的问题和大家分享一下,希望能对大家有帮助. 具体问题如下: 1.已经留出足够的未分配磁盘空间,在CentOS7安装界面却显示&q ...

最新文章

  1. 为Windows git 配置比较工具为beyond compare
  2. java 泛型机制_java中的泛型机制
  3. 《C++游戏编程入门(第4版)》——1.11 问题讨论
  4. c++中类型用new和不用new的区别
  5. android蓝牙通信_使用Arduino构建OLED显示屏与Android手机接口的智能手表
  6. [转载] 使用openpyxl模块向Excel中插入图片
  7. JavaSE基础——代码块、继承、方法重写和final关键字
  8. 4g网络切换软件_游戏掉线坑队友?OPPO Reno网络切换超快,上分吃鸡更稳
  9. 购入计算机主机怎么入账,出纳记账软件更换主机电脑时如何备份附件资料?
  10. 百度智能云金融安全计算平台有多强?安排!
  11. 安卓仿苹果键盘输入法_iphone输入法安卓版下载
  12. 读史可以明智_在开发中明智思考的5种方法
  13. Codeforces Round #741 (Div. 2) A. The Miracle and the Sleeper
  14. 噩梦射手(SurvivalShooter)教程(八)
  15. MYSQL JDBC快速查询响应的方法,快速返回机制的实现
  16. xampp php5.6,XAMPP for Linux
  17. 2021年昆明师专附中高考成绩查询,云南省昆明市云南师范大学附属中学2020-2021学年高三高考适应性月考卷(一)语文试题...
  18. 中华PDF开天裁决传奇这个该死的东西怎么删除?
  19. Vue--》超详细教程——vue-cli脚手架的搭建与使用
  20. java——ZZULIOJ_1047: 对数表

热门文章

  1. javascript全笔记-基础版(尚硅谷视频李立超老师)
  2. 线性基(线性无关的基底)
  3. Linux-无密码访问、远程拷贝、无密码登录
  4. 全球及中国公共安全记录管理系统行业发展现状及前景趋势预测报告(2022-2027)
  5. Android 深入Http(4)从OkHttp源码来看Http,音视频开发工程师前景
  6. 基本题型记录-二叉树中序遍历
  7. 【初赛】初赛提纲 错题本(to be countinue)
  8. 【表白程序】盛开的玫瑰代码
  9. 策划的权限、视野与产品的最终高度
  10. 此pl2303驱动程序不支持win11、非旺玖原装PL2303驱动解决办法