web-dev-qa-db-ja.com

AndroidでMediaStoreを更新するにはどうすればよいですか?

これは、Androidフォーラムの一般的なユーザーの質問から始まりました。しかし、必然的にプログラミングの質問になります。ここに私の問題があります。

Androidには、MediaScannerというサービスがあります。このサービスは、SDカードがマウント解除され、再マウントされるといつでもバックグラウンドで実行されます(おそらくそうです)。このサービスは、カード上のすべてのメディアファイルのデータを収集し、音楽アプリケーションが照会できるSQLite DBを提供します。ほとんどの音楽アプリケーションは、SDカードのスキャンに関連するバッテリー消費を節約するため、このサービスを使用します。

Androidを使い始めてから、デバイスに同期されたM3UプレイリストがSDカードから削除された後もこのSQLite DBに残るという問題が常にありました。カードには約10 m3uのファイルしかありませんが、使用する音楽アプリに約40のプレイリストのコレクションが表示されるようになりました。残りのプレイリストは再生されず、空です。音楽アプリから削除することで手動で削除できますが、これにはうんざりです。これらのゴーストプレイリストを削除するには、より良い方法が必要です。

Android Market-SDRescanとMusic Sc​​annerの2つのアプリがあります。これらはまさにこれを行うはずですが、どちらも機能しません。

MediaStoreデータベースを更新または削除し、ゼロから開始するために独自のアプリを作成することを設定しましたが、それほど遠くはありません。私はAndroid以下のコードを実行するアプリを持っています:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
        Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 

SDカードをスキャンする方法として、このコードの例をいくつかオンラインで見つけましたが、まったく運がありません。任意のヒント?

完全なコード:

package com.roryok.MediaRescan;

import Android.app.Activity;
import Android.content.Intent;
import Android.content.IntentFilter;
import Android.net.Uri;
import Android.os.Bundle;
import Android.os.Environment;

public class MediaRescan extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
                Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 
        setContentView(R.layout.main);
    }

    //Rescan the sdcard after copy the file
    private void rescanSdcard() throws Exception{     
      Intent scanIntent = new Intent(Intent.ACTION_MEDIA_MOUNTED, 
                Uri.parse("file://" + Environment.getExternalStorageDirectory()));   
      IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
      intentFilter.addDataScheme("file");     
      sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, 
                Uri.parse("file://" + Environment.getExternalStorageDirectory())));    
    }
}
48
roryok

わかりました、できました。

カードを再スキャンするのではなく、アプリはメディアストア内のすべてのプレイリストを反復処理し、_dataフィールドの長さをチェックします。 M3Uファイルが関連付けられていないすべてのリストで、このフィールドは常に空であることを発見しました。次に、元のAndroid音楽アプリのソースコードを検索し、deleteメソッドを検索し、それを使用して長さ0のプレイリストを削除するだけのケースでした。アプリの名前を変更しましたPlaylistPurge(もう「再スキャン」しないため)と以下のコードを投稿しています。

私はおそらくこれをどこかで、市場か自分のサイトのどちらかで公開するでしょう http://roryok.com

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 /

更新2:2013年4月9日火曜日

私はこの投稿からブログに多くのトラフィックを獲得し、それに対して感謝する人々からの膨大な数のメールを受け取りました。喜んで助けてくれました!潜在的なユーザーは、私のくだらないアプリを実行するとすぐにクラッシュすることを知っている必要がありますが、実際にはそれがすべきことをしています!私は常にこのクラッシュ動作を修正して市場に投入するつもりでしたが、2013年がその年になることを願っています。

17
roryok

簡単な「単一ファイルベースのソリューション」を次に示します。

ファイルを追加するたびにadd、MediaStore Content Providerにそのことを知らせる

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAdded)));

deletionの場合:getContentResolver()。delete(uri、null、null)を使用します(クレジットは DDSports に移動します)

47
Pascal

次のコードを使用して、特定のファイルの再スキャンを要求できます。

注:渡されたMIMEタイプは重要です。 "*/*"を使用すると、MP3 ID3タグに加えた変更がSQLiteで適切に更新されないことに気付きましたが、 "audio/mp3"を使用すると動作しました

MediaScannerConnection.scanFile(
    context, 
    new String[]{ pathToFile1, pathToFile2 }, 
    new String[]{ "audio/mp3", "*/*" }, 
    new MediaScannerConnectionClient()
    {
        public void onMediaScannerConnected()
        {
        }
        public void onScanCompleted(String path, Uri uri)
        {
        }
    });
12
Michael