我想阻止我的音乐播放器应用程序每次应用程序启动时扫描目录中的音频文件。我怎样才能做到这一点?

时间:2016-10-15 04:56:15

标签: android audio android-mediaplayer audio-player

我想阻止我的音乐播放器应用在每次应用启动时扫描目录中的音频文件。我怎么能这样做?

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

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卡,那么它将花费太多时间来启动应用程序。请帮帮我

3 个答案:

答案 0 :(得分:1)

无需将所有歌曲保留在本地应用列表中。

要显示mp3list,您可以使用带限制的内容提供者光标列表适配器查询(逐页滚动查询)

直接搜索使用contentprovider查询方法。

只在本地数据库上保留一个指向mp3 uri的播放列表。

此链接可能会帮助您: How to update listview whose data was queried from database through SimpleCursorAdapter?

答案 1 :(得分: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
}

答案 2 :(得分:1)

我认为@royrok answer可以帮助您,@ royrok检查mediastore中的播放列表而不是重新扫描SD卡。下面我包括@royrok回答。

该应用程序不是重新扫描卡片,而是遍历MediaStore中的所有播放列表并检查_data字段的长度。我发现对于没有关联M3U文件的所有列表,此字段始终为空。然后,它只是找到原始Android音乐应用程序的源代码,找到删除方法并使用它删除任何长度为0的播放列表的情况。我已重命名应用程序PlaylistPurge(因为它没有&#39 ; t&#39;重新扫描&#39;再发布以下代码:

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/

的帖子的链接

更新

我发现了一篇关于Querying And Removing Media From The 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进行删除。第二种也是更简单的方法是在delete语句中指定谓词。在此示例中,我将根据文件名和路径删除音频文件,但您可以根据任何已知信息(例如视频持续时间或图像尺寸)轻松删除任何类型的媒体)。

在查询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()的第一个参数指定了我们想要返回的列,在这种情况下只有&#34; _ID&#34;。第二个参数指定我们要查看存储在外部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()方法有3个参数:要删除的Uri,谓词和谓词参数。我们通过将我们通过查询MediaStore发现的ID附加到外部存储上的音频文件的Uri来形成Uri。由于我们确切地知道要删除哪一行,因此我们不需要指定谓词或谓词的参数。

从MediaStore中删除内容的第二种方法利用了查询和删除内容的几乎相同的事实。

context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 
        MediaStore.MediaColumns.DATA + "='" + path + "'", null);

我们可以使用delete()方法的谓词来准确指定我们想要删除的内容,而不必事先查询它。虽然这种方法更有效(没有额外的查询,没有游标可以处理),但它有一些陷阱。您无法明确确认您要删除的内容。您还无法使用此方法执行高级查询,例如,如果您要删除最近添加的内容(您可以通过根据DATE_ADDED列排序查询来执行此操作)。但是,两种方式都可以为您提供一种方法来确认您已删除的内容,因为delete()方法返回它作为整数删除的行数。