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

3

6

I have big problems with MediaStore. I need to handle events when MediaStore is changed over MTP. I already have a receiver for android.intent.action.MEDIA_SCANNER_FINISHED action, but it is useful only for Universal Mass Storage(UMS). The scanner is not launched over MTP, because the MTP changes the MediaStore database directly.

Please would you be so kind and help me how to detect this events. Thank you very much for any help!

Quantum answered 22/9, 2012 at 19:21 Comment(0)
Q
12

I finally found a solution. I tried to use FileObserver but when you use it for all directories...it is quite memory consuming. So now I am using ContentObserver and it is working well:

public static class UriObserver
{
    private final Cursor mCursor;
    private final ContentObserver mObserver;
    private boolean mRunning = true;

    private class ObserverWithListener extends ContentObserver
    {
        private final OnChangeListener mListener;

        public ObserverWithListener(OnChangeListener listener)
        {
            super(new Handler());

            mListener = listener;
        }

        @Override
        public void onChange(boolean selfChange)
        {
            if (mRunning)
            {
                log.d("Change triggered");
                mListener.onChange();
            }
        }
    };

    public static UriObserver getInstance(ContentResolver contentResolver, Uri uri, OnChangeListener listener)
    {
        Cursor c = contentResolver.query(uri, new String[] { "*" }, null, null, null);

        if ((c = Dao.moveToFirst(c)) == null)
        {
            log.e("Cannot start observer for uri: " + uri);
            return null;
        }

        return new UriObserver(c, listener);
    }

    public UriObserver(Cursor c, final OnChangeListener listener)
    {
        mCursor = c;
        mObserver = new ObserverWithListener(listener);
        mCursor.registerContentObserver(mObserver);
    }

    public void stop()
    {
        mCursor.unregisterContentObserver(mObserver);
        Dao.closeCursor(mCursor);
        mRunning = false;
    }

    public interface OnChangeListener
    {
        public void onChange();
    }
}

The flag mRunning has to be there for some reason because onChange was sometimes called even if unregisterContentObserver() had been called before.

This code I am using with Uris that I want to observe, i.e. MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ...

Quantum answered 12/10, 2012 at 18:6 Comment(2)
This answer works great for detecting file deletion/file replace, but adding new files throught MTP does not trigger Observer changes, at least for me on Nexus 7Euell
Hmm, it works for me for any operation on this cursor (i.e. MTP). This uri works only with audio files, maybe you should specify another URI.Quantum
C
4

Create a content observer class

class MyObserver extends ContentObserver {
    public MyObserver(Handler handler) {

        super(handler);
    }

    @Override
    public void onChange(boolean selfChange) {
        this.onChange(selfChange, null);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
     doYourWorkHere();
    }
}

Register the observer in your activity

Handler handler;
    MyObserver observer;
handler = new Handler();
observer = new MyObserver(handler);
        this.getContentResolver().
                registerContentObserver(
                        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        true,
                        observer);

Don't forget to unregister the observer in onDestroy() function

 this.getContentResolver().unregisterContentObserver(observer);
Cellobiose answered 17/8, 2015 at 14:45 Comment(0)
T
0

The accepted solution doesn't work on android version 10 whether you have opted out of scoped storage or not (but works perfectly for all other versions)

And the solution given by @sujith-s-manjavana also doesn't work for android version 10, if you have forgot to add ACCESS_MEDIA_LOCATION permission in manifest as (but works for all other android versions):

<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>

I was unable to add comments nor upvote thus adding this as an answer, so that if anyone face the same issue on Android 10, gets the solution on this page without the need of searching on internet.

Telangiectasis answered 24/4 at 13:18 Comment(3)
It sounds like you need to raise a new question, referring back to this question and explaining what the new problem with Android 10 is.Breakdown
If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From ReviewBreakdown
Okay I can raise the new question with a reference to this question, But I had an issue which I have solved it myself, now all I wanted is to share my findings that solved the issue with android 10, so, should I also raise a new question in such case?? and then answer it myself?Telangiectasis

© 2022 - 2024 — McMap. All rights reserved.