安卓系统媒体库
扫描存储设备上的公有媒体文件,并使用SQLite数据库记录下相关的信息:
一般情况下,系统开机时会发出媒体扫描的广播,通知扫描程序进行扫描;
开发者开发的应用程序也可以调用扫描器实时扫描;
扫描到的媒体除了会在数据库中记录媒体文件的路径意外,还会记录下其他的相关信息,例如入库的时间、修改时间、图片详情、歌曲时长等;
Android系统使用的ContentProvider以使得设备上的其他应用程序可以随时访问这些媒体数据。
访问媒体库:系统中包名为com.android.providers.media的应用程序提供了媒体库的ContentProvider;
如何访问媒体库中的图片信息
方法:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ContentResolver cr = getContentResolver();
Uri uri = Media.EXTERNAL_CONTENT_URI;
Cursor cursor = cr.query(uri, null, null, null, null);
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
String path,display;
long date;
int size,width,height;
path = cursor.getString(cursor.getColumnIndex(Media.DATA));
display = cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME));
date = cursor.getLong(cursor.getColumnIndex(Media.DATE_TAKEN));
size = cursor.getInt(cursor.getColumnIndex(Media.SIZE));
width = cursor.getInt(cursor.getColumnIndex("width"));
height = cursor.getInt(cursor.getColumnIndex("height"));
System.out.println("--------------------------");
System.out.println("path = " + path);
System.out.println("display = " + display);
System.out.println("date = " + new Date(date));
System.out.println("size = " + size);
System.out.println("width = " + width);
System.out.println("height = " + height);
}
}
}
显示媒体库中的图片
在显示媒体库中的图片时,容易因为图片大小不一致而引发一下OOM的错误
OOM解决方案
在一次性加载(无视是在主线程或子线程)大量数据时容易导致OOM(Out if Memory Error);
在加载图片时出现OOM,可以试着使用以下的解决方法:
在使用BitmapFactory类decode图片时,设置Options参数,将图片缩小显示;
使用Thumbnails生成缩略图的Bitmap对象在显示;
核心代码:
Image:
public class Image {
private String path;
private String display;
private long date;
private int size;
private int width;
private int height;
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
ImageAdapter:
public class ImageAdapter extends BaseAdapter {
private List<Image> images;
public ImageAdapter(List<Image> images) {
setImages(images);
}
private void setImages(List<Image> images) {
if (images == null) {
images = new ArrayList<Image>();
}
this.images = images;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return images.size();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.lv_item, null);
holder.image = (ImageView)convertView.findViewById(R.id.iv_image);
holder.path = (TextView)convertView.findViewById(R.id.tv_item_path);
holder.display = (TextView)convertView.findViewById(R.id.tv_item_name);
holder.px = (TextView)convertView.findViewById(R.id.tv_item_px);
holder.size = (TextView)convertView.findViewById(R.id.tv_item_size);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
Image img = images.get(position);
//容易导致OOM问题,Bitmap对象太大
//Bitmap bm = BitmapFactory.decodeFile(img.getPath());
Bitmap bm;
// 方法一:自定义方法获取Bitmap
// bm = decodeFile(img);
// 方法二:使用Thumbnails
bm = Thumbnails.getThumbnail(parent.getContext().getContentResolver(), img.getId(), Thumbnails.MICRO_KIND, null);
holder.display.setText(img.getDisplay());
holder.size.setText(img.getSize() / 1024+ "KB");
holder.path.setText(img.getPath());
holder.px.setText(img.getWidth() + " x " + img.getHeight() + "px");
holder.image.setImageBitmap(bm);
return convertView;
}
static final int MAX_WIDTH = 80;
static final int MAX_HEIGHT = 80;
private Bitmap decodeFile(Image img){
Bitmap bm = null;
Options opts = new Options();
int rate;
// 未知图片的宽与高时的做法:
opts.inJustDecodeBounds = true;
bm = BitmapFactory.decodeFile(img.getPath(),opts);
int width = opts.outWidth;
int height = opts.outHeight;
if(width >height){
rate = height / MAX_HEIGHT - 1;
}else{
rate = width / MAX_WIDTH - 1;
}
opts.inJustDecodeBounds = false;
// 当已知图片的宽与高时,可以使用以下的方法
// if(img.getWidth() > img.getHeight()){
// rate = img.getWidth() / MAX_WIDTH - 1;
// }else{
// rate = img.getHeight() / MAX_HEIGHT - 1;
// }
opts.inSampleSize = rate;
bm = BitmapFactory.decodeFile(img.getPath(),opts);
return bm;
}
private class ViewHolder {
ImageView image;
TextView path, display, px, size;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
MainActivity:
public class MainActivity extends Activity {
private List<Image> images = new ArrayList<Image>();
private ListView listView;
private ImageAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadImages();
listView = (ListView) findViewById(R.id.lv_images);
adapter = new ImageAdapter(images);
listView.setAdapter(adapter);
}
private void loadImages(){
ContentResolver cr = getContentResolver();
Uri uri = Media.EXTERNAL_CONTENT_URI;
Cursor cursor = cr.query(uri, null, null, null, null);
// Image image = new Image();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
Image image = new Image();
image.setId(cursor.getLong(cursor.getColumnIndex(Media._ID)));
image.setPath(cursor.getString(cursor.getColumnIndex(Media.DATA)));
image.setDisplay(cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME)));
image.setDate(cursor.getLong(cursor.getColumnIndex(Media.DATE_TAKEN)));
image.setSize(cursor.getInt(cursor.getColumnIndex(Media.SIZE)));
image.setWidth(cursor.getInt(cursor.getColumnIndex("width")));
image.setHeight(cursor.getInt(cursor.getColumnIndex("height")));
images.add(image);
}
cursor.close();
}
}
布局:
activity_main:
<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:orientation="vertical" >
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv_images"></ListView>
</LinearLayout>
item布局:
<?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:orientation="vertical" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_launcher"/>
<RelativeLayout
android:id="@+id/rl_item"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv_image">
<TextView
android:id="@+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="20dp"
android:textSize="16sp"
android:gravity="left|center"
android:textStyle="bold"
android:singleLine="true"
android:text="im01.jpg"/>
<TextView
android:id="@+id/tv_item_px"
android:textSize="12sp"
android:textColor="#666666"
android:gravity="left|center"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="1200 X 345px "
android:singleLine="true"
android:layout_below="@+id/tv_item_name"
/>
<TextView
android:id="@+id/tv_item_size"
android:layout_width="match_parent"
android:layout_height="20dp"
android:textSize="12sp"
android:gravity="left|center"
android:textColor="#666666"
android:text="234kb"
android:singleLine="true"
android:layout_toRightOf="@+id/tv_item_px"
android:layout_alignTop="@+id/tv_item_px"/>
<TextView
android:id="@+id/tv_item_path"
android:layout_width="match_parent"
android:layout_height="20dp"
android:textSize="12sp"
android:textColor="#666666"
android:gravity="left|center"
android:singleLine="true"
android:layout_below="@+id/tv_item_px"
android:text="D:world/nicai/nicaii/zaicai.png"/>
</RelativeLayout>
</RelativeLayout>
访问媒体库中的音频 代码:
package com.example.lianxi;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Audio.Media;
import android.widget.ListView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 媒体库中的音频所具有的部分字段:
// _id _data titile_size duration album_artist album album_key
// ContentResolver Uri
ContentResolver cr = getContentResolver();
Uri uri = Media.EXTERNAL_CONTENT_URI;
Cursor cursor = cr.query(uri, null, null, null, null);
List<Music> musics = new ArrayList<Music>();
Music music;
for (cursor.moveToFirst(); cursor.isAfterLast(); cursor.moveToNext()) {
music = new Music();
music.setId(cursor.getLong(cursor.getColumnIndex(Media._ID)));
music.setData(cursor.getString(cursor.getColumnIndex(Media.DATA)));
music.setTitle(cursor.getString(cursor.getColumnIndex(Media.TITLE)));
music.setArtist(cursor.getString(cursor
.getColumnIndex(Media.ARTIST)));
music.setAlbum(cursor.getString(cursor.getColumnIndex(Media.ALBUM)));
music.setAlbumkey(cursor.getString(cursor
.getColumnIndex(Media.ALBUM_KEY)));
music.setSize(cursor.getInt(cursor.getColumnIndex(Media.SIZE)));
music.setDuration(cursor.getInt(cursor
.getColumnIndex(Media.DURATION)));
musics.add(music);
System.out.println(music.toString());
}
cursor.close();
}
}
测试结果:
01-01 13:41:27.514: I/System.out(11445): Music [id=15, data=/storage/emulated/0/Music/Groove Coverage - She.mp3, title=Groove Coverage - She, size=3664535, duration=229033, artist=<unknown>, album=Music]
01-01 13:41:27.518: I/System.out(11445): Music [id=16, data=/storage/emulated/0/Music/number2.mp3, title=number2, size=3664535, duration=229033, artist=<unknown>, album=Music]
01-01 13:41:27.530: I/System.out(11445): Music [id=17, data=/storage/emulated/0/Music/number3.mp3, title=Can't Get You Out Of My Head, size=3681031, duration=230016, artist=Kylie Minogue, album=Can't Get You Out of My Head [UK CD]]
01-01 13:41:27.530: I/System.out(11445): Music [id=18, data=/storage/emulated/0/Music/number1.mp3, title=number1, size=4727537, duration=295471, artist=<unknown>, album=Music]
使用媒体库做出的获取音乐信息
与获取图片类似
MusicAdapter:
public class MusicAdapter extends BaseAdapter{
private List<Music> musics;
public MusicAdapter(List<Music> musics){
setMusics(musics);
}
public void setMusics(List<Music> musics){
if(musics == null){
musics = new ArrayList<Music>();
}
this.musics = musics;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return musics.size();
}
private class ViewHolder{
ImageView image;
TextView title,duration,artist,album;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
if(convertView == null){
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.lv_item, null);
holder = new ViewHolder();
holder.image = (ImageView) convertView.findViewById(R.id.iv_image);
holder.title = (TextView) convertView.findViewById(R.id.tv_item_title);
holder.duration = (TextView) convertView.findViewById(R.id.tv_item_time);
holder.artist = (TextView) convertView.findViewById(R.id.tv_item_artist);
holder.album = (TextView) convertView.findViewById(R.id.tv_item_name);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
Music music = musics.get(position);
holder.title.setText(music.getTitle());
holder.duration.setText(formatDuration(music.getDuration()));
holder.artist.setText(music.getArtist());
holder.album.setText(music.getAlbum());
if(music.getImagePath() == null){
}else{
holder.image.setImageBitmap(BitmapFactory.decodeFile(music.getImagePath()));
}
return convertView;
}
private String formatDuration(int duration){
return new SimpleDateFormat("mm:ss",Locale.CHINA).format(new Date(duration));
}
}
Music:
public class Music {
private long id;
private String data;
private String title;
private int size;
private int duration;
private String artist;
private String album;
private String albumkey;
private String imagePath;
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = 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 getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getAlbumkey() {
return albumkey;
}
public void setAlbumkey(String albumkey) {
this.albumkey = albumkey;
}
@Override
public String toString() {
return "Music [id=" + id + ", data=" + data + ", title=" + title
+ ", size=" + size + ", duration=" + duration + ", artist="
+ artist + ", album=" + album + "]";
}
}
MainActivity:
public class MainActivity extends Activity {
private List<Music> musics;
private ListView listView;
private MusicAdapter adapter;
private Uri uri;
private Cursor cursor;
private ContentResolver cr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadMusic();
listView = (ListView) findViewById(R.id.lv_images);
adapter = new MusicAdapter(musics);
listView.setAdapter(adapter);
}
private void loadMusic(){
cr = getContentResolver();
uri = Media.EXTERNAL_CONTENT_URI;
cursor = cr.query(uri, null, null, null, null);
musics = new ArrayList<Music>();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
Music music = new Music();
music.setId(cursor.getLong(cursor.getColumnIndex(Media._ID)));
music.setData(cursor.getString(cursor.getColumnIndex(Media.DATA)));
music.setTitle(cursor.getString(cursor.getColumnIndex(Media.TITLE)));
music.setArtist(cursor.getString(cursor.getColumnIndex(Media.ARTIST)));
music.setAlbum(cursor.getString(cursor.getColumnIndex(Media.ALBUM)));
music.setAlbumkey(cursor.getString(cursor.getColumnIndex(Media.ALBUM_KEY)));
music.setSize(cursor.getInt(cursor.getColumnIndex(Media.SIZE)));
music.setDuration(cursor.getInt(cursor.getColumnIndex(Media.DURATION)));
System.out.println(music.toString());
Uri imageUri = Albums.EXTERNAL_CONTENT_URI;
String[] projection = new String[] {Albums.ALBUM_ART};
String selection = Albums.ALBUM_KEY + "=?";
String[] selectionArgs = new String[] {music.getAlbumkey()};
Cursor imageCursor = cr.query(imageUri, projection, selection, selectionArgs, null);
if(imageCursor.moveToFirst()){
music.setImagePath(imageCursor.getString(0));
}
musics.add(music);
}
cursor.close();
}
}
布局与获取照片信息布局类似,这里不再贴出代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理