我想防止我的音乐播放器应用程序在每次启动时扫描目录以查找音频文件。我该怎么做?

7

我希望我的音乐播放器应用程序在每次启动时都不会扫描目录以寻找音频文件。我该怎么做?

我一直在使用以下代码来扫描音频文件。

public void getSongList() {

  ContentResolver contentResolver=getContentResolver();
  Uri musicUri=android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  Cursor musicCursor = contentResolver.query(musicUri, null, null, null, null);
  if(musicCursor!=null && musicCursor.moveToFirst()) {
    //get columns
    int titleColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media._ID);
    int artistColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media.ARTIST);

    int albumIDColumn = musicCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);

    //add songs to list
    do {
       long thisId = musicCursor.getLong(idColumn);
       String thisTitle = musicCursor.getString(titleColumn);
       String thisArtist = musicCursor.getString(artistColumn);
       long thisAlbumID=musicCursor.getLong(albumIDColumn);
       Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
       Bitmap albumArtBitMap=null;
       Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, thisAlbumID);
       try {
         albumArtBitMap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), albumArtUri);
         Matrix m = new Matrix();
         m.setRectToRect(new RectF(0, 0, albumArtBitMap.getWidth(), albumArtBitMap.getHeight()), new RectF(0, 0, 300, 300), Matrix.ScaleToFit.CENTER);
         albumArtBitMap = Bitmap.createBitmap(albumArtBitMap, 0, 0, albumArtBitMap.getWidth(), albumArtBitMap.getHeight(), m, true);
       } catch (IOException e) {
         e.printStackTrace();
       }
       songList.add(new Song(thisId, thisTitle, thisArtist,albumArtBitMap));
    }
    while (musicCursor.moveToNext());
  }
}

我希望这个应用只在有新文件时扫描。因为如果每次都扫描整个SD卡,那么启动应用程序需要太长时间。请帮助我实现这个功能。


我不是很明白你的意思!你什么时候调用了getSongList()方法? - Radhey
可能存在其他问题,我这样认为。因为如果你不想扫描一个列表,请停止调用此方法。但是你想要防止扫描。可以分享一下场景吗? - Bhavdip Sagar
1
目前,每次启动应用程序时我都会调用此方法。但是我希望等待一段时间,只有在添加新文件时才扫描音频文件。 - Purvil Bambharolia
3个回答

1
不需要在本地应用程序列表中保留所有歌曲。
要显示mp3列表,可以使用内容提供程序游标列表适配器查询限制(按滚动一页一页地查询)。
要搜索,请直接使用contentprovider查询方法。
只需在本地数据库上保留指向mp3 uri的播放列表。
这个链接可能会帮助你: 如何通过SimpleCursorAdapter从数据库查询数据更新listview?

1
每次启动应用程序时,查看您的设备上有多少可用空间。
File path = Environment.getDataDirectory();
megaBytesAvailable(path)

public static float megaBytesAvailable(File file) {
        StatFs stat = new StatFs(file.getPath());
        long bytesAvailable = (long)stat.getBlockSizeLong() * (long)stat.getAvailableBlocksLong();
        return bytesAvailable / (1024.f * 1024.f);
    }

将其保存为应用程序缓存中的变量,并在每次启动应用程序时进行比较,如果它更大,则知道需要扫描。

if(comparedVariable < megaBytesAvailable(music_directory_path)){
    getSongList();
    //Save it again to compare next time if more storage is used
    comparedVariable = megaBytesAvailable(music_directory_path);
    //Save it to SharedPrefs for next boot up comparison
}

1

我认为@royrok 的回答可以帮助你,其中@royrok检查媒体库中的播放列表而不是重新扫描SD卡。以下是@royrok的回答。


相比重新扫描卡片,该应用程序遍历MediaStore中的所有播放列表并检查_data字段的长度。我发现对于所有没有关联M3U文件的列表,该字段始终为空。然后只需要找到原始android音乐应用程序的源代码,找到删除方法并使用它来删除任何长度为0的播放列表。我将该应用程序重命名为PlaylistPurge(因为它不再“重新扫描”),并在下面发布代码:
package com.roryok.PlaylistPurge;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.content.ContentUris;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;

public class PlaylistPurge extends ListActivity {
    
    private List<String> list = new ArrayList<String>();
    private final String [] STAR= {"*"};
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        ListAdapter adapter = createAdapter();
        setListAdapter(adapter);
    }
 
    /**
     * Creates and returns a list adapter for the current list activity
     * @return
     */
    protected ListAdapter createAdapter()
    {
        // return play-lists
        Uri playlist_uri= MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;    
        Cursor cursor= managedQuery(playlist_uri, STAR, null,null,null);
        cursor.moveToFirst();
        for(int r= 0; r<cursor.getCount(); r++, cursor.moveToNext()){
            int i = cursor.getInt(0);
            int l = cursor.getString(1).length();
            if(l>0){
                // keep any playlists with a valid data field, and let me know
                list.add("Keeping : " + cursor.getString(2) + " : id(" + i + ")");
            }else{
                // delete any play-lists with a data length of '0'
                Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, i);
                getContentResolver().delete(uri, null, null);
                list.add("Deleted : " + cursor.getString(2) + " : id(" + i + ")");
            }
        }       
        cursor.close();
        // publish list of retained / deleted playlists
        ListAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
 
        return adapter;
    }
}

这是一篇关于应用程序的博客文章链接http://roryok.com/blog/index.php/2010/07/23/clearing-out-deleted-playlists-in-android/

更新

我找到了一篇关于查询和删除Android MediaStore中的媒体的文章,下面是其中的内容。 。

Android提供了一种注册不同类型的媒体(如音频、视频和图像)以供任何应用程序使用的方法。如果你的应用程序是一个音乐播放器或图像编辑器,那么这非常方便。Android的MediaStore是这个元数据的提供者,并包括有关媒体的信息,如标题、艺术家、大小和位置。

如果您的应用程序进行任何形式的媒体内容创建,例如图像编辑或从外部网站下载音频,则通常希望使该内容可以从任何其他可以使用它的应用程序中访问。当您创建文件时,可以使用MediaScannerConnection将文件及其元数据添加到MediaStore中。

如果您从文件系统中删除文件,则元数据将保留在MediaStore中,直到Android扫描新媒体的系统为止,这通常发生在系统首次启动时或可以显式调用方式:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
    Uri.parse("file://" + Environment.getExternalStorageDirectory() )));

虽然这种方法可行,但它需要时间和资源,因为基本上整个文件系统都必须重新扫描。另一种选择是从MediaStore中显式删除文件。我们将讨论两种方法来实现此操作。第一种是基于某些谓词查询内容的MediaStore,并根据MediaStore标识其唯一ID进行删除。第二种更简单的方法是在删除语句中只指定谓词。在此示例中,我将根据音频文件的文件名和路径进行删除,但您可以轻松使用此方法根据任何已知信息(例如视频持续时间或图像尺寸)删除任何类型的媒体。
在查询MediaStore时,您应将其视为SQL数据库。您需要通过指定表(MediaStore的外部内容表),您需要的列(内容的ID)和where子句(如何标识内容)来形成查询。要执行实际查询,我们将使用ContentResolver的query()方法。
String[] retCol = { MediaStore.Audio.Media._ID };
Cursor cur = context.getContentResolver().query(
    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
    retCol, 
    MediaStore.MediaColumns.DATA + "='" + filePath + "'", null, null);
if (cur.getCount() == 0) {
    return;
}
cur.moveToFirst();
int id = cur.getInt(cur.getColumnIndex(MediaStore.MediaColumns._ID));
cur.close();

query()的第一个参数指定我们要返回的列,这里只有“_ID”。第二个参数指定我们要查看存储在外部SD卡上的媒体(对于没有SD卡的设备来说,这将是内部存储)。第三个参数是谓词,它指定我们要查找的内容。在这种情况下,我通过文件系统中的路径来标识文件(这是存储在MediaColumns.DATA列中的内容)。第四和第五列是谓词的参数和排序方式。我将我的谓词参数包含在谓词本身中,因此不需要额外提供,如果你只想查找一个内容,并且你的谓词足够具体以仅返回一行,则排序无关紧要。
非常重要的是使谓词足够具体,以确保您得到您要查找的确切ID。在我的情况下,我知道特定位置只能有一个文件,但您可以使用任何列的组合(例如标题、艺术家和专辑)来查找内容。请查看MediaColumns以获取所有可能性。
一旦执行了实际查询,您需要检查MediaStore是否实际包含您要删除的内容。如果您没有以某种方式处理此问题,则在尝试遍历游标时,应用程序将崩溃。一旦确认查询返回了一些数据,请通过将游标移动到其第一个位置,读取“_ID”列并关闭游标来获取ID。非常重要的是,您记得在使用完它后关闭游标。您的应用程序不会崩溃,但您会收到LogCat中的内存泄漏和投诉。
现在我们有了MediaStore与我们的内容关联的ID,我们可以调用ContentResolver的delete()方法,类似于我们调用其query()方法。
Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
    id);
context.getContentResolver().delete(uri, null, null);

delete()方法接受三个参数:要删除的Uri、谓词和谓词参数。我们通过将查询MediaStore所发现的ID附加到外部存储中音频文件的Uri来形成Uri。由于我们知道要删除的确切行,因此不需要指定谓词或谓词参数。
从MediaStore中删除内容的第二种方法利用了查询和删除之间几乎相同的事实。
context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
        MediaStore.MediaColumns.DATA + "='" + path + "'", null);

我们可以使用delete()方法的谓词来指定要删除的内容,而不必事先查询。虽然这种方法更有效率(没有额外的查询,没有游标需要处理),但它也有一些缺点。你无法明确确认你正在删除什么。你也不能使用此方法进行高级查询,例如如果您想删除最近添加的内容(可以通过根据DATE_ADDED列排序的查询来完成)。但是,两种方法都提供了一种确认已删除内容的方法,因为delete()方法返回删除的行数作为整数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接