音频文件的查找
既然是音乐播放器,就必须要面对一个问题:把你本地的音乐文件找出来,才能播放出来。但是每次播放都去找一次未免会浪费很多时间,所以就是第一次运行的时候扫描一次存储器,把音频文件找出来,并且把路径和相关信息保存到我们APP的数据库中。
数据库的创建
首先从数据库出发,Android用的是SQLite数据库,而且还有一个DataBaseHelper类来帮助我们获取数据库:
public class DatabaseHelper extends SQLiteOpenHelper
{
private static SQLiteDatabase mdb;
private static DatabaseHelper mHelper;
private static final int DB_VERSION = 3;
private static final String DB_NAME="musicstore_new";
private static final String TABLE_ALBUM = "album_info";
private static final String TABLE_ARTIST = "artist_info";
private static final String TABLE_MUSIC = "music_info";
private static final String TABLE_FOLDER = "folder_info";
private static final String TABLE_FAVORITE = "favorite_info";
//获取Helper中的数据库
public static SQLiteDatabase getInstance(Context context)
{
if(mdb==null)
{
mdb=getHelper(context).getWritableDatabase();
}
return mdb;
}
//获取Helper本身
public static DatabaseHelper getHelper(Context context)
{
if(mHelper==null)
{
mHelper=new DatabaseHelper(context);
}
return mHelper;
}
//包装一下的构造函数
public DatabaseHelper(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}
//第一次运行getWritableDatabase()时获取不到数据库文件,就会创建一个在data/data/<package name>/文件夹中,并回调该函数
@Override
public void onCreate(SQLiteDatabase arg0)
{
// TODO Auto-generated method stub
arg0.execSQL("create table "
+ TABLE_MUSIC
+ " (_id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " songid integer, albumid integer, duration integer, musicname varchar(10), "
+ "artist char, data char, folder char, musicnamekey char, artistkey char, favorite integer)");
arg0.execSQL("create table "
+ TABLE_ALBUM
+ "(_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "album_name char, album_id integer, number_of_songs integer, album_art char)");
arg0.execSQL("create table "
+ TABLE_ARTIST
+ "(_id INTEGER PRIMARY KEY AUTOINCREMENT, artist_name char, number_of_tracks integer)");
arg0.execSQL("create table "
+ TABLE_FOLDER
+ "(_id INTEGER PRIMARY KEY AUTOINCREMENT, folder_name char, folder_path char)");
arg0.execSQL("create table "
+ TABLE_FAVORITE
+ " (_id integer,"
+ " songid integer, albumid integer, duration integer, musicname varchar(10), "
+ "artist char, data char, folder char, musicnamekey char, artistkey char, favorite integer)");
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2)
{
// TODO Auto-generated method stub
if(arg2>arg1)
{
arg0.execSQL("DROP TABLE IF EXISTS " + TABLE_ARTIST);
arg0.execSQL("DROP TABLE IF EXISTS " + TABLE_ALBUM);
arg0.execSQL("DROP TABLE IF EXISTS " + TABLE_MUSIC);
arg0.execSQL("DROP TABLE IF EXISTS " + TABLE_FOLDER);
onCreate(arg0);
}
}
public void clearTable()
{
SQLiteDatabase db=this.getWritableDatabase();
db.delete(TABLE_ALBUM, null, null);
db.delete(TABLE_ARTIST, null, null);
db.delete(TABLE_FAVORITE, null, null);
db.delete(TABLE_FOLDER, null, null);
db.delete(TABLE_MUSIC, null, null);
}
}
这里用到了设计模式中的单例模式,每次获取的都是static的那个一开始创建的database,第一次调用getInstance时会创建Helper本身,然后利用Helper.getWritableDatabase();来获取可以写的数据库,getWritableDatabase()运行时会看看数据库存不存在,不存在就会去创建一个新的数据库,执行onCeate()函数,顺带创建了各张表,然后返回给用户使用。数据库表中的各个属性就是要从Android系统中获取并且写进表中。
利用ContentReslover来获取Android数据
- 查找音乐文件的ID,专辑ID,持续时间,音乐名,歌手,所在路径(与音乐文件相关信息去URI=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
private static String[] proj_music={MediaStore.Audio.Media._ID,MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.DURATION,MediaStore.Audio.Media.TITLE,MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DATA};
cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj_music, null, null, MediaStore.Audio.Media.ALBUM_KEY)
cr.query返回的是Cursor,我们要遍历浮标:
public static List<MusicInfo> getMusicList(Cursor cursor)
{
if(cursor==null)
{
return null;
}
List<MusicInfo> list=new ArrayList<>();
while(cursor.moveToNext())
{
MusicInfo info=new MusicInfo();
info.songid=cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
info.albumid=cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
info.duration=cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
info.musicname=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
info.artist=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String filepath=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
info.data=filepath;
info.folder=filepath.substring(0, filepath.lastIndexOf(File.separator));
list.add(info);
}
cursor.close();
return list;
}
2.找专辑相关信息
Alubms->android.provider.MediaStore.Audio.Albums;
private static String[] proj_album = new String[] { Albums.ALBUM,
Albums.NUMBER_OF_SONGS, Albums._ID, Albums.ALBUM_ART };
getAlbumList(cr.query(Albums.EXTERNAL_CONTENT_URI, proj_album, null, null, Media.ALBUM_KEY));
3.找作者相关信息
private static String[] proj_artist = new String[] {
MediaStore.Audio.Artists.ARTIST,
MediaStore.Audio.Artists.NUMBER_OF_TRACKS };
getArtistList(cr.query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, proj_artist, null, null, MediaStore.Audio.Artists.NUMBER_OF_TRACKS+" desc"));
4.寻找音频文件所在文件夹位置
ContentResolver cr=context.getContentResolver();
Uri uri=MediaStore.Files.getContentUri("external");
StringBuilder mSelection = new StringBuilder(FileColumns.MEDIA_TYPE
+ " = " + FileColumns.MEDIA_TYPE_AUDIO + " and " + "("
+ FileColumns.DATA + " like'%.mp3' or " + Media.DATA
+ " like'%.wma')");
mSelection.append(") group by ( " + FileColumns.PARENT);//这句把同目录的所有音频文件合并了
List<FolderInfo> list=getFolderList(cr.query(uri, proj_folder, mSelection.toString(), null, null));
系统级ContentProvider深入探究
学习ContentProvider的时候我们知道要在Manifest.xml里面声明其URI,然后ContentReslover就能利用该URI找到这个ContentProvider,利用其重写的增改删除操作数据库,上面就涉及到了好几个URI:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI
MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI
MediaStore.Files.getContentUri(“external”);
它们所对应的ContentProvider应该分别处理不同的,一个或多个数据库表。下面就来看看这些数据库的表到底是怎样情况的,怎样实现查找到一首歌的歌名之类。
这些ContentProvider对应的数据库存在哪里?Android是基于Linux内核,文件系统和Linux类似,平时手机的内部存储都是位于/目录下面的,而SD卡的目录则是在/mnt/sdcard下面
而/data/data/里面有好多应用的数据,存放着系统里面有哪些音乐文件,相关信息的数据库就在这个里面
我们可以用adb调试工具来看看里面的情况
里面有好多张表,其中有的表就存着我们要查找的数据了,例如我想找当前系统有哪些文件,可以先用sqlite的命令看看该表的列属性,我用红线画了一些常用的属性列
也可以用select语句把信息取出来看看
目前系统外存中所有的音频文件就找出来了