androidcontentobserver

ContentObserver onChange() method gets called many times


I have requirement to track any new image file of type .jpg created on device. I have done this using ContentObserver on MediaStore using below class MediaStoreObserver and, registering the same in one of my service.

I have noticed that onChange() method gets called many times for a single file creation. I understand that media file created gets updated in many tables of MediaStore hence onChange() gets called many times.

My question: How to register to MediaStore for ONLY image file create/edit operation ?

-Thanks in advance, Manju

    private class MediaStoreObserver extends ContentObserver {
    public MediaStoreObserver() {
        super(null);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);

        //check image file changes in MediaStore
        readFromMediaStore(_context,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    }
}

//register for external media changes for image files
if(mediaStoreObserver!=null){
  _context.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        false,mediaStoreObserver);

Solution

  • Short answer: You can't, it's the provider which sends notifyChange (received with observers onChange) whenever something is: updated/inserted/deleted

    Longer answer: This is what would've done to achieve what you want (How to register to MediaStore for ONLY image file create/edit operation ?):

    Read image table from MediaStore upon start and store the _data column (file paths), in a sorted collection, a sorted collection with paths (strings). And whenever you receive an onChange call make a new collection of the above sort, then loop over the new collection and search the original collection you created , with binary search (since the collection is sorted and we want to keep the time complexity low). This would lead to a quite effective implementation with running time of O(n*logn).

    Or in pseudo code:

    1. Read current image columns from media store (the `_data column as projection)
    2. Store result in a collection, with string type
    3. Sort collection
    4. Upon `onChange` is received, make a new collection as step 1-3
    5. Loop over collection created in 4 and search each string you take out with 
    binary search in the sorted collection you got from step 3, if item is not found 
    then the item is new
    6. Make the collection in 4 the current cached version of mediastore 
    7. Time complexity is O(n*log n) for the above algorithm 
    

    Edit for the updated file part i would read the date modified field from MediaStore whenever my search in step 5 hits, that would mean that you should actually store both file (uri) and date modified in a data class, but as search lookup use file path. Whenever file is found you should check if the modified dates match, if not then it's an updated file.