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

问题描述 投票:7回答:3

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

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

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

android audio android-mediaplayer audio-player
3个回答
1
投票

我认为@royrok answer可以帮助你,@ 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/的帖子的链接


UPDATE

我发现了一篇关于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()的第一个参数指定了我们想要返回的列,在这种情况下只有“_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()方法有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()方法返回以整数形式删除的行数,因此两种方式都可以为您提供确认删除内容的方法。

© www.soinside.com 2019 - 2024. All rights reserved.