观察Audio.Media.EXTERNAL_CONTENT_URI的Android内容观察者的更改

时间:2013-04-09 10:08:07

标签: android android-sdcard contentobserver android-mediascanner fileobserver

我正在开发一个Android应用程序,我必须在其中检测Android SD卡中音频文件的更改,文件名,文件路径和对其执行的操作。例如,如果我在SD卡中添加文件,那么我想知道

  1. 添加的文件的名称
  2. 文件路径
  3. 操作 - 添加
  4. 以前我曾尝试过文件观察器但是为此,我必须在每个目录上应用它。所以我搜索了一些其他解决方案,并获得了有关 Audio.Media.EXTERNAL_CONTENT_URI 的信息。然后我创建了一个像这样的内容观察者

    UriObserver.java - 内容观察员

    class UriObserver extends ContentObserver {
    
        public UriObserver(Handler handler) {
            super(handler);
            // TODO Auto-generated constructor stub
        }
    
        @Override
        public void onChange(boolean selfChange) {
            // TODO Auto-generated method stub
            super.onChange(selfChange);
    
            Log.d("INSTANT", "GETTING CHANGES");
        }
    
    }
    

    这是注册的代码

    UriObserver observer = new UriObserver(new Handler());
    
    Log.d("INSTANT", "registered content observer");
    
    this.getApplicationContext()
        .getContentResolver()
        .registerContentObserver(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false,
        observer);
    
    Log.d("INSTANT", "registered content observer");
    

    它让我知道在与音频文件相关的SD卡中发生了一些变化。但它没有提供有关添加,编辑或删除哪个文件的任何信息。

    然后我搜索了解决方案并得到了这个帖子

    Android: How to detect a change in MediaStore when connected over MTP

    在这篇文章中,一些代码由 Bh​​iefer 作为答案提供,我认为它可以起作用,所以我试图实现它,但我无法这样做。

    我能为此做些什么?

    更新

    我可以查询Audio.Media.EXTERNAL_CONTENT_URI以获取最新更改吗?这段代码:

    mCursor = context.getContentResolver().query(
                        Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, "_id");
    
    mCursor.moveToLast();
    

    未提供最新更改。有没有其他方法可以获得最新的更改?

2 个答案:

答案 0 :(得分:9)

让我试着放松

<强> ContentObserver

它没有提供有关已更改内容的信息

这是每个设计。 documentation中没有任何内容表明它会向您提供此信息。

FileObserver

这不是递归的

是。知道issue。迭代所有目录和设置观察者有什么问题?根据我的理解,默认情况下不应该有很多(比方说十几个)。

Android:如何通过MTP连接时检测MediaStore中的更改

您找到的代码只是包含在UriObserver中的ContentObserver。

它做了几件事

  • 他获取了一个内容提供的光标(在他的情况下,我相信它是来自MediaStore的图像)

  • 他为此

  • 注册观察员
  • 一旦发生某些变化,它就会将此更改转发给外部侦听器

但是,此解决方案有两个限制:

  • 它继承了ContentObserver的问题,它没有报告数据发生了什么。

  • 我相信它只会报告在此MediaStore内容提供商中注册的文件的更改。我相信系统只扫描SD卡上的特殊目录来检查图像等等。因此,如果文件将放在另一个目录中,则此解决方案将无法看到它。

那么,你对他的代码有什么疑问?

<强>摘要

在这种情况下,如果你想知道scdard上所有文件的确切更改类型,我认为你找不到比FileObserver更好的东西

更新1

结合更多可能不适合您的想法。如果您可以根设备,那么您可以选择为文件系统编写过滤器驱动程序,因此每次更改某些内容时都会调用您的驱动程序。

您可以查看以下链接: http://www.gossamer-threads.com/lists/linux/kernel/355190

或者您可以重用一些现有的Linux更改通知系统。例如,看看这个: http://stefan.buettcher.org/cs/fschange/。但是,FileObserver可能完全基于它。

无论如何,这两种方法都是低水平的,需要更多的时间来弄清楚。

答案 1 :(得分:1)

您可以通过查询DATE_ADDED和DATE_MODIFIED列获取最新的添加/修改,但不会获得删除

我是这样做的:

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
long lastDatabaseUpdateTime = preferences.getLong("lastDatabaseUpdateTime", 0);
long newDatabaseUpdateTime = (new Date()).getTime();

String[] cols = new String[] {MediaStore.Audio.Media._ID /* and other columns */};

String where = "("+MediaStore.MediaColumns.DATE_ADDED + ">" + (lastDatabaseUpdateTime/1000);
where += " or " + MediaStore.MediaColumns.DATE_MODIFIED + ">" + (lastDatabaseUpdateTime/1000);
where += ") and "+MediaStore.Audio.AudioColumns.IS_MUSIC+"==1 ";

Cursor cursor = MusicUtils.query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, cols, where, null, null);

/* Do my work on the cursor and close the cursor */

//If no exceptions, then save the new timestamp
SharedPreferences.Editor editor = preferences.edit();
editor.putLong("lastDatabaseUpdateTime", newDatabaseUpdateTime);
editor.commit();