如何刷新 Android 上的 MediaStore?

发布于 2024-09-10 18:36:41 字数 1995 浏览 5 评论 0 原文

这最初是 Android 论坛上的一个一般用户问题。然而,它必然成为一个编程问题。这是我的问题。

Android 有一个服务 - MediaScanner - 只要(我相信)SD 卡被卸载和重新安装,它就会在后台运行。该服务收集卡上所有媒体文件的数据,并提供可供音乐应用程序查询的 SQLite DB。大多数音乐应用程序都使用此服务,因为它可以节省与扫描 SD 卡相关的电池消耗。

自从我开始使用 android 以来,我一直遇到一个问题,即使从 SD 卡中删除,同步到设备的 M3U 播放列表仍然保留在这个 SQLite DB 中。现在我使用的任何音乐应用程序中都会显示大约 40 个播放列表,尽管卡上只有大约 10 个 m3u 文件。剩余的播放列表不会播放,并且是空的。我可以通过从音乐应用程序中删除它们来手动删除它们,但我厌倦了这样做。必须有更好的方法来删除这些幽灵播放列表。

Android Market 上有两个应用程序 - SDRescan 和 Music Sc​​anner,据说它们正是这样做的,但它们都不起作用。

我开始编写自己的应用程序来刷新或删除 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())));    
    }
}

This started out as a general user question on Android forums. However it's become, by necessity, a programming question. Here's my problem.

Android has a service - MediaScanner - which runs in the background any time (I believe) the SD card is un-mounted and re-mounted. This service collects data on all the media files on the card, and provides a SQLite DB which can be queried by music applications. Most music applications use this service as it saves on battery-drain associated with scanning the SD card.

Since I started using android, I've consistently had a problem whereby M3U playlists synchronised to the device remain in this SQLite DB even after being deleted from the SD Card. It's gotten to the point where I now have a collection of about 40 playlists showing up in any music app I use, despite there only being around 10 m3u files on the card. The remaining playlists do not play, and are empty. I can remove them manually by deleting them from the music app, but I'm sick of doing this. There has to be a better way to remove these ghost playlists.

There are two apps on the Android Market - SDRescan and Music Scanner, which supposedly do exactly this but neither of them work.

I set about writing my own app to refresh or delete the MediaStore database and start from scratch, but I'm not getting very far. I've got an android app which runs the following code :

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

I've found a few examples of this code online as a way to scan the SD Card but I'm not having any luck with it whatsoever. Any tips?

FULL CODE:

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())));    
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

三五鸿雁 2024-09-17 18:36:41

以下是一个易于使用的“基于单个文件”的解决方案:

添加文件

每当您添加文件时,通知MediaStore内容提供商使用:

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

删除文件:

同样,当您删除文件时,通知MediaStore内容提供商使用:

getContentResolver().delete(uri, null, null)  // (Credit goes to [DDSports][1])

Here is an easy to use 'single file based' solution:

Adding a file:

Whenever you add a file, inform MediaStore's Content Provider using:

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

Deleting a file:

Similarly, when you delete a file, inform MediaStore's Content Provider using:

getContentResolver().delete(uri, null, null)  // (Credit goes to [DDSports][1])
怂人 2024-09-17 18:36:41

好的,我已经做到了。

应用程序不会重新扫描卡,而是会迭代 mediastore 中的所有播放列表并检查 _data 字段的长度。我发现对于所有没有关联 M3U 文件的列表,该字段始终为空。然后,只需找到原始 Android 音乐应用程序的源代码,找到删除方法并使用它来删除长度为 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:4 月 9 日,星期二,2013 年,

我的博客通过这篇文章获得了大量流量,并且收到了大量感谢我的电子邮件。很高兴它有帮助!任何潜在用户都应该知道,我的蹩脚应用程序目前在运行时就会崩溃,但实际上却做了它应该做的事情!我一直打算回去修复这个崩溃行为并将其投放市场,希望 2013 年我会这样做。

Ok, I've done it.

Rather than rescan the card, the app iterates through all the playlists in mediastore and checks the length of the _data field. I discovered that for all the lists with no associated M3U file, this field was always empty. Then it was just a case of finding the source code for the original android music app, finding the delete method and using that to delete any playlists with a length of 0. I've renamed the app PlaylistPurge (since it doesn't 'rescan' anymore) and am posting the code below.

I'll probably also publish this somewhere, either on the Market or on my own site, 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;
    }
}

UPDATE:

Here's a link to a post on my blog about the app http://roryok.com/blog/index.php/2010/07/23/clearing-out-deleted-playlists-in-android/

UPDATE 2: Tuesday, April 9, 2013

I've gotten a lot of traffic to my blog from this post, and a huge number of emails from people thanking me for it. Glad it helped out! Any potential users should know that my crappy app currently crashes as soon as you run it, but actually does what it's supposed to do! I've always intended to go back and fix this crashing behaviour and put it on the market, hopefully 2013 will be the year I do that.

狠疯拽 2024-09-17 18:36:41

您可以使用以下代码请求重新扫描特定文件。

注意:传递的 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)
        {
        }
    });

You can request a rescan of specific files using the following code.

NOTE: The MIME TYPE passed is important. I noticed changes made to MP3 ID3 tags did not refresh properly in the SQLite if I used "*/*", however using "audio/mp3" worked

MediaScannerConnection.scanFile(
    context, 
    new String[]{ pathToFile1, pathToFile2 }, 
    new String[]{ "audio/mp3", "*/*" }, 
    new MediaScannerConnectionClient()
    {
        public void onMediaScannerConnected()
        {
        }
        public void onScanCompleted(String path, Uri uri)
        {
        }
    });
我为君王 2024-09-17 18:36:41

只需将其添加到您的活动中:

Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

 MediaScannerConnection.scanFile(
            this, new String[]{"/storage/emulated/0"}, null,
            new MediaScannerConnection.OnScanCompletedListener() {
                public void onScanCompleted(String path, Uri uri) {
                    Log.i("231","onScanCompleted");
                }
            });

just add this in your activity :

Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

 MediaScannerConnection.scanFile(
            this, new String[]{"/storage/emulated/0"}, null,
            new MediaScannerConnection.OnScanCompletedListener() {
                public void onScanCompleted(String path, Uri uri) {
                    Log.i("231","onScanCompleted");
                }
            });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文