1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

Wiedermal ein Thumbnailproblem...

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von Unicate, 24.10.2011.

  1. Unicate, 24.10.2011 #1
    Unicate

    Unicate Threadstarter Android-Experte

    Beiträge:
    473
    Erhaltene Danke:
    57
    Registriert seit:
    09.08.2010
    Hallo alle zusammen!

    Ich zeige in einer Applikation alle Ordner die Bilder enthalten an.
    Problem sind wie immer die Thumbnails. Speziell, wenn der Benutzer die sd-karte mountet, Bilder löscht und andere Bilder neu draufkopiert kommt es sehr häufig vor, das falsche Thumbnails angezeigt werden.

    Hat jemand eine Idee, wie ich das gefixt bekomme?

    Einfachste Reproduzierung:

    * kleines Bild erstellen (zB. mit Paint ) von 4 Pixeln
    * auf die sdkarte kopieren
    * von der Galerie auf dem Gerät anzeigen lassen
    * sdkarte erneut auf dem PC mounten und die farbe der 4 pixel ändern und speichern
    * sdkarte auf dem Gerät mounten und versuchen anzeigen zu lassen

    Die Galerie kann feststellen ob sie das Bild geändert hat oder nicht und erstellt die Thumbnail neu.
    Wie muss ich das machen? Bei mir wird immer eine alte Thumbnail angezeigt.


    Fehlgeschlagene Versuche:


    • /mnt/sdcard/DCIM/.thumbnails Verzeichnis löschen
      • nicht alle Geräte haben dieses Thumbnailverzeichnis
      • selbst wenn der Ordner gelöscht wird, werden die Bilder nicht richtig aktualisiert
      • Code:
                    File dir = new File("/mnt/sdcard/DCIM/.thumbnails");
                    if(dir.exists() && dir.isDirectory()) {
                        for(File file : dir.listFiles()) {
                            if(file.delete()) {
                                Debug.e(TAG, file.getAbsolutePath()+" deleted!");
                            }
                        }
                        if(dir.delete()) {
                            Debug.e(TAG, dir.getAbsolutePath()+" deleted!");
                        }
                    };
    [Edit:]
    Das Verzeicnis löschen scheint doch zu funktionieren, allerdings muss ich die App neu starten damit er die Änderungen erkennt.
     
    Zuletzt bearbeitet: 24.10.2011
  2. Unicate, 25.10.2011 #2
    Unicate

    Unicate Threadstarter Android-Experte

    Beiträge:
    473
    Erhaltene Danke:
    57
    Registriert seit:
    09.08.2010
    Also mein jetziger und bisher sauberster Ansatz ist:

    Den Intent "Intent.ACTION_MEDIA_SCANNER_FINISHED" mit einem Broadcastreceiver zu catchen. D.h. falls es Änderungen auf der SD-Karte gegeben hat, dann möchte ich das wissen.

    Die Frage ist nun: Wie muss ich darauf reagieren?

    Ich habe das bei der 3D Galery in der Catlog gesehen. Wenn ich die SD-Karte am PC mounte während die App offen ist, dann eine Image bearbeite und die Karte wieder im Gerät mounte, wird dieser Intent abgefangen und die Thumbnail aktualisiert.
    Wie wird die Thumbnail aktualisiert? Automatisch passiert das nicht.
     
  3. Unicate, 25.10.2011 #3
    Unicate

    Unicate Threadstarter Android-Experte

    Beiträge:
    473
    Erhaltene Danke:
    57
    Registriert seit:
    09.08.2010
    Ok, hier mal was zum reproduzieren.

    PHP:
    package de.unicate.android.thumbnailtest;

    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.database.Cursor;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ImageView;

    public class 
    ThumbnailTestActivity extends Activity {
        
        private 
    ImageView _image;
        private 
    long _id;
        
    /** Called when the activity is first created. */
        
    @Override
        
    public void onCreate(Bundle savedInstanceState) {
            
    super.onCreate(savedInstanceState);
            
    setContentView(R.layout.main);
            
            
    _image = ((ImageView)findViewById(R.id.imageTest));
            
            
    _image.setOnClickListener(new OnClickListener() {
                
                @
    Override
                
    public void onClick(View v) {
                    
    _image.setImageBitmap(BitmapFactory.decodeFile("/mnt/sdcard/tmp/srgg.jpg"));
                    
    _image.invalidate();
                }
            });
            
            
    _id getIdByPath("/mnt/sdcard/tmp/srgg.jpg");
            
            ((
    Button)findViewById(R.id.buttonUpdate)).setOnClickListener(new OnClickListener() {
                
                @
    Override
                
    public void onClick(View v) {
                    
    // we want to receive if the mediascanner finished scanning the sdcard
                    
    IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
                    
    // after the mediascanner finished scanning files
                    
    intentFilter.addDataScheme("file");
                    
    // registering the receiver
                    
    registerReceiver(_receiverintentFilter);
                    
    //
                    
    sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTEDUri.parse("file://" Environment.getExternalStorageDirectory())));
                    
                }
            });
            
            
    showImage(_id);
            
        }
        
        public 
    long getIdByPath(String path) {
            
    String[] projection = { MediaStore.Images.ImageColumns._ID,
                                    
    MediaStore.Images.ImageColumns.DATA
                    
    };

            
    long id = -1;
            
    Cursor cursor getContentResolver().query(
                    
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    
    projection
                    
    MediaStore.Images.ImageColumns.DATA " = ?"
                    new 
    String[]{path}, null);
            if(
    null != cursor && cursor.getCount() > 0) {
                if(
    cursor.moveToFirst()) {
                    
    id cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID));
                }
                
    cursor.close();
            }
            return 
    id;
        }
        
        
        public 
    void showImage(long id) {
            if(
    id 0) {
                    
    _image.setImageBitmap(MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(),id ,MediaStore.Images.Thumbnails.MICRO_KIND,null));
                
    _image.invalidate();
            }
        }
        private 
    BroadcastReceiver _receiver = new BroadcastReceiver() {
            @
    Override
            
    public void onReceive(Context contextIntent intent) {
                
    showImage(_id);
                
    unregisterReceiver(this);
                
            }
            
        };
    }
    • Projekt erstellen
    • Activity im Projekt erstellen und den o.a. code reinkopieren
    • Pfad der Image anpassen
    • main.xml mit einer ImageView und einem Button versehen (ids: imageTest, buttonUpdate)
    • IntentFilter im Manifest anpassen
      • Code:
                    <intent-filter >
                        <action android:name="android.intent.action.MEDIA_MOUNTED" />
                        <data android:scheme="file" />
                    </intent-filter>
    • App einmal starten (damit eine Thumbnail erstellt wird)
    • SD-Karte am dem PC mounten und im die im Code angegebene Bilddatei z.B. rot färben
    • SD-Karte wieder am Gerät mounten
    • Die App erneut starten
    Nun sollte die alte Thumbnail zusehen sein.
    Wieso?

    [Edit:]
    Scheint ein geräteabhängiges Problem zu sein.
    Auf dem Samsung Galaxy S2 funktioniert das.

    Aber
    * Desire HD nicht
    * Milestone 1 nicht

    Ich brauche einen Workaround!
     
    Zuletzt bearbeitet: 25.10.2011
  4. Unicate, 26.10.2011 #4
    Unicate

    Unicate Threadstarter Android-Experte

    Beiträge:
    473
    Erhaltene Danke:
    57
    Registriert seit:
    09.08.2010
    Die Lösung(ACHTUNG NUR SDK API >=8):

    Problem ist wie im Edit oben beschrieben. Ich habe es so gelösst, das ich mir eine Methode gebaut habe, welche es mir ermöglicht, die Microthumbnails zu refreshen.

    Dazu musste ich mich von etwas Code aus dem ANDROID SDK 2.3.5 bedienen. sollte aber bis zur API 8 abwärtskompatibel sein.

    1. MiniThumbFile
    Diese Datei konnte ich im normalen SDK nicht einbinden also habe ich sie mir aus einem Git repository gezogen und per Hand eingebunden und um eine Methode erweitert. "createNewMicroThumbnail"

    PHP:
    package de.unicate.android.thumbnailtest;
    /*
     * Copyright (C) 2009 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileLock;
    import java.util.Hashtable;

    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Environment;
    import android.util.Log;

    /**
     * This class handles the mini-thumb file. A mini-thumb file consists
     * of blocks, indexed by id. Each block has BYTES_PER_MINTHUMB bytes in the
     * following format:
     *
     * 1 byte status (0 = empty, 1 = mini-thumb available)
     * 8 bytes magic (a magic number to match what's in the database)
     * 4 bytes data length (LEN)
     * LEN bytes jpeg data
     * (the remaining bytes are unused)
     *
     * @hide This file is shared between MediaStore and MediaProvider and should remained internal use
     *       only.
     */
    public class MiniThumbFile {
        private static final 
    String TAG "MiniThumbFile";
        private static final 
    int MINI_THUMB_DATA_FILE_VERSION 3;
        public static final 
    int BYTES_PER_MINTHUMB 10000;
        private static final 
    int HEADER_SIZE 4;
        private 
    Uri mUri;
        private 
    RandomAccessFile mMiniThumbFile;
        private 
    FileChannel mChannel;
        private 
    ByteBuffer mBuffer;
        private static 
    Hashtable<StringMiniThumbFilesThumbFiles =
            new 
    Hashtable<StringMiniThumbFile>();

        
    /**
         * We store different types of thumbnails in different files. To remain backward compatibility,
         * we should hashcode of content://media/external/images/media remains the same.
         */
        
    public static synchronized void reset() {
            for (
    MiniThumbFile file sThumbFiles.values()) {
                
    file.deactivate();
            }
            
    sThumbFiles.clear();
        }

        public static 
    synchronized MiniThumbFile instance(Uri uri) {
            
    String type uri.getPathSegments().get(1);
            
    MiniThumbFile file sThumbFiles.get(type);
            
    // Log.v(TAG, "get minithumbfile for type: "+type);
            
    if (file == null) {
                
    file = new MiniThumbFile(
                        
    Uri.parse("content://media/external/" type "/media"));
                
    sThumbFiles.put(typefile);
            }

            return 
    file;
        }

        private 
    String randomAccessFilePath(int version) {
            
    String directoryName =
                    
    Environment.getExternalStorageDirectory().toString()
                    + 
    "/DCIM/.thumbnails";
            return 
    directoryName "/.thumbdata" version "-" mUri.hashCode();
        }

        private 
    void removeOldFile() {
            
    String oldPath randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION 1);
            
    File oldFile = new File(oldPath);
            if (
    oldFile.exists()) {
                try {
                    
    oldFile.delete();
                } catch (
    SecurityException ex) {
                    
    // ignore
                
    }
            }
        }

        private 
    RandomAccessFile miniThumbDataFile() {
            if (
    mMiniThumbFile == null) {
                
    removeOldFile();
                
    String path randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION);
                
    File directory = new File(path).getParentFile();
                if (!
    directory.isDirectory()) {
                    if (!
    directory.mkdirs()) {
                        
    Log.e(TAG"Unable to create .thumbnails directory "
                                
    directory.toString());
                    }
                }
                
    File f = new File(path);
                try {
                    
    mMiniThumbFile = new RandomAccessFile(f"rw");
                } catch (
    IOException ex) {
                    
    // Open as read-only so we can at least read the existing
                    // thumbnails.
                    
    ex.printStackTrace();
                    try {
                        
    mMiniThumbFile = new RandomAccessFile(f"r");
                    } catch (
    IOException ex2) {
                        
    // ignore exception
                    
    }
                }
                if (
    mMiniThumbFile != null) {
                    
    mChannel mMiniThumbFile.getChannel();
                }
            }
            return 
    mMiniThumbFile;
        }

        public 
    MiniThumbFile(Uri uri) {
            
    mUri uri;
            
    mBuffer ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
        }

        public 
    synchronized void deactivate() {
            if (
    mMiniThumbFile != null) {
                try {
                    
    mMiniThumbFile.close();
                    
    mMiniThumbFile null;
                } catch (
    IOException ex) {
                    
    // ignore exception
                
    }
            }
        }

        
    // Get the magic number for the specified id in the mini-thumb file.
        // Returns 0 if the magic is not available.
        
    public synchronized long getMagic(long id) {
            
    // check the mini thumb file for the right data.  Right is
            // defined as having the right magic number at the offset
            // reserved for this "id".
            
    RandomAccessFile r miniThumbDataFile();
            if (
    != null) {
                
    long pos id BYTES_PER_MINTHUMB;
                
    FileLock lock null;
                try {
                    
    mBuffer.clear();
                    
    mBuffer.limit(8);

                    
    lock mChannel.lock(pos8true);
                    
    // check that we can read the following 9 bytes
                    // (1 for the "status" and 8 for the long)
                    
    if (mChannel.read(mBufferpos) == 9) {
                        
    mBuffer.position(0);
                        if (
    mBuffer.get() == 1) {
                            return 
    mBuffer.getLong();
                        }
                    }
                } catch (
    IOException ex) {
                    
    Log.v(TAG"Got exception checking file magic: "ex);
                } catch (
    RuntimeException ex) {
                    
    // Other NIO related exception like disk full, read only channel..etc
                    
    Log.e(TAG"Got exception when reading magic, id = " id +
                            
    ", disk full or mount read-only? " ex.getClass());
                } finally {
                    try {
                        if (
    lock != nulllock.release();
                    }
                    catch (
    IOException ex) {
                        
    // ignore it.
                    
    }
                }
            }
            return 
    0;
        }

        public 
    synchronized void saveMiniThumbToFile(byte[] datalong idlong magic)
                
    throws IOException {
            
    RandomAccessFile r miniThumbDataFile();
            if (
    == null) return;

            
    long pos id BYTES_PER_MINTHUMB;
            
    FileLock lock null;
            try {
                if (
    data != null) {
                    if (
    data.length BYTES_PER_MINTHUMB HEADER_SIZE) {
                        
    // not enough space to store it.
                        
    return;
                    }
                    
    mBuffer.clear();
                    
    mBuffer.put((byte1);
                    
    mBuffer.putLong(magic);
                    
    mBuffer.putInt(data.length);
                    
    mBuffer.put(data);
                    
    mBuffer.flip();

                    
    lock mChannel.lock(posBYTES_PER_MINTHUMBfalse);
                    
    mChannel.write(mBufferpos);
                }
            } catch (
    IOException ex) {
                
    Log.e(TAG"couldn't save mini thumbnail data for "
                        
    id "; "ex);
                throw 
    ex;
            } catch (
    RuntimeException ex) {
                
    // Other NIO related exception like disk full, read only channel..etc
                
    Log.e(TAG"couldn't save mini thumbnail data for "
                        
    id "; disk full or mount read-only? " ex.getClass());
            } finally {
                try {
                    if (
    lock != nulllock.release();
                }
                catch (
    IOException ex) {
                    
    // ignore it.
                
    }
            }
        }

        
    /**
         * Gallery app can use this method to retrieve mini-thumbnail. Full size
         * images share the same IDs with their corresponding thumbnails.
         *
         * @param id the ID of the image (same of full size image).
         * @param data the buffer to store mini-thumbnail.
         */
        
    public synchronized byte [] getMiniThumbFromFile(long idbyte [] data) {
            
    RandomAccessFile r miniThumbDataFile();
            if (
    == null) return null;

            
    long pos id BYTES_PER_MINTHUMB;
            
    FileLock lock null;
            try {
                
    mBuffer.clear();
                
    lock mChannel.lock(posBYTES_PER_MINTHUMBtrue);
                
    int size mChannel.read(mBufferpos);
                if (
    size 4) { // flag, magic, length
                    
    mBuffer.position(0);
                    
    byte flag mBuffer.get();
                    
    long magic mBuffer.getLong();
                    
    int length mBuffer.getInt();

                    if (
    size >= length && data.length >= length) {
                        
    mBuffer.get(data0length);
                        return 
    data;
                    }
                }
            } catch (
    IOException ex) {
                
    Log.w(TAG"got exception when reading thumbnail id=" id ", exception: " ex);
            } catch (
    RuntimeException ex) {
                
    // Other NIO related exception like disk full, read only channel..etc
                
    Log.e(TAG"Got exception when reading thumbnail, id = " id +
                        
    ", disk full or mount read-only? " ex.getClass());
            } finally {
                try {
                    if (
    lock != nulllock.release();
                }
                catch (
    IOException ex) {
                    
    // ignore it.
                
    }
            }
            return 
    null;
        }

        public 
    void createNewMicroThumbnail(Bitmap bitmaplong origIdthrows IOException {
            
    long magic getMagic(origId);
            
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
            
    bitmap.compress(Bitmap.CompressFormat.PNG100baos); //bm is the bitmap object 
            
    byte[] baos.toByteArray();
            
    saveMiniThumbToFile(borigIdmagic);
        }
    }
    Diese Methode erstellt mir aus einer Bitmap eine neue Microthumbnail zur passenden Image.
    Man beachte hierbei, das es beim aufruf dieser Methode ein Thumbnailfile geben sollte, sonst wird getMagic(origId) eine Exception werfen.

    2. ThumbnailUtils erweitern
    Dann habe ich die Klasse ThumbnailUtils erweitert, da (aus welchen Gründen auch immer, wenn das jemand weiß, dann immer raus damit) die Methode "createImageThumbnail" nicht im SDK verfügbar ist.

    PHP:
    package de.unicate.android.thumbnailtest;

    import java.io.FileDescriptor;
    import java.io.FileInputStream;
    import java.io.IOException;

    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.provider.MediaStore.Images;
    import android.util.Log;

    public class 
    ThumbnailUtils extends android.media.ThumbnailUtils {
        
        private static final 
    String TAG "ThumbnailUtils";

        
    /* Maximum pixels size for created bitmap. */
        
    private static final int MAX_NUM_PIXELS_THUMBNAIL 512 384;
        private static final 
    int MAX_NUM_PIXELS_MICRO_THUMBNAIL 128 128;
        private static final 
    int UNCONSTRAINED = -1;


        
    /**
         * Constant used to indicate we should recycle the input in
         * {@link #extractThumbnail(Bitmap, int, int, int)} unless the output is the input.
         */
        
    public static final int OPTIONS_RECYCLE_INPUT 0x2;

        
    /**
         * Constant used to indicate the dimension of mini thumbnail.
         * @hide Only used by media framework and media provider internally.
         */
        
    public static final int TARGET_SIZE_MINI_THUMBNAIL 320;

        
    /**
         * Constant used to indicate the dimension of micro thumbnail.
         * @hide Only used by media framework and media provider internally.
         */
        
    public static final int TARGET_SIZE_MICRO_THUMBNAIL 96;

        
    /**
         * This method first examines if the thumbnail embedded in EXIF is bigger than our target
         * size. If not, then it'll create a thumbnail from original image. Due to efficiency
         * consideration, we want to let MediaThumbRequest avoid calling this method twice for
         * both kinds, so it only requests for MICRO_KIND and set saveImage to true.
         *
         * This method always returns a "square thumbnail" for MICRO_KIND thumbnail.
         *
         * @param filePath the path of image file
         * @param kind could be MINI_KIND or MICRO_KIND
         * @return Bitmap
         *
         * @hide This method is only used by media framework and media provider internally.
         */
        
    public static Bitmap createImageThumbnail(String filePathint kind) {
            
    boolean wantMini = (kind == Images.Thumbnails.MINI_KIND);
            
    int targetSize wantMini
                    
    TARGET_SIZE_MINI_THUMBNAIL
                    
    TARGET_SIZE_MICRO_THUMBNAIL;
            
    int maxPixels wantMini
                    
    MAX_NUM_PIXELS_THUMBNAIL
                    
    MAX_NUM_PIXELS_MICRO_THUMBNAIL;
            
    Bitmap bitmap null;
            if (
    bitmap == null) {
                try {
                    
    FileDescriptor fd = new FileInputStream(filePath).getFD();
                    
    BitmapFactory.Options options = new BitmapFactory.Options();
                    
    options.inSampleSize 1;
                    
    options.inJustDecodeBounds true;
                    
    BitmapFactory.decodeFileDescriptor(fdnulloptions);
                    if (
    options.mCancel || options.outWidth == -1
                            
    || options.outHeight == -1) {
                        return 
    null;
                    }
                    
    options.inSampleSize computeSampleSize(
                            
    optionstargetSizemaxPixels);
                    
    options.inJustDecodeBounds false;

                    
    options.inDither false;
                    
    options.inPreferredConfig Bitmap.Config.ARGB_8888;
                    
    bitmap BitmapFactory.decodeFileDescriptor(fdnulloptions);
                } catch (
    IOException ex) {
                    
    Log.e(TAG""ex);
                }
            }

            if (
    kind == Images.Thumbnails.MICRO_KIND) {
                
    // now we make it a "square thumbnail" for MICRO_KIND thumbnail
                
    bitmap extractThumbnail(bitmap,
                        
    TARGET_SIZE_MICRO_THUMBNAIL,
                        
    TARGET_SIZE_MICRO_THUMBNAILOPTIONS_RECYCLE_INPUT);
            }
            return 
    bitmap;
        }




        
    /*
         * Compute the sample size as a function of minSideLength
         * and maxNumOfPixels.
         * minSideLength is used to specify that minimal width or height of a
         * bitmap.
         * maxNumOfPixels is used to specify the maximal size in pixels that is
         * tolerable in terms of memory usage.
         *
         * The function returns a sample size based on the constraints.
         * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED,
         * which indicates no care of the corresponding constraint.
         * The functions prefers returning a sample size that
         * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED.
         *
         * Also, the function rounds up the sample size to a power of 2 or multiple
         * of 8 because BitmapFactory only honors sample size this way.
         * For example, BitmapFactory downsamples an image by 2 even though the
         * request is 3. So we round up the sample size to avoid OOM.
         */
        
    private static int computeSampleSize(BitmapFactory.Options options,
                
    int minSideLengthint maxNumOfPixels) {
            
    int initialSize computeInitialSampleSize(optionsminSideLength,
                    
    maxNumOfPixels);

            
    int roundedSize;
            if (
    initialSize <= ) {
                
    roundedSize 1;
                while (
    roundedSize initialSize) {
                    
    roundedSize <<= 1;
                }
            } else {
                
    roundedSize = (initialSize 7) / 8;
            }

            return 
    roundedSize;
        }

        private static 
    int computeInitialSampleSize(BitmapFactory.Options options,
                
    int minSideLengthint maxNumOfPixels) {
            
    double w options.outWidth;
            
    double h options.outHeight;

            
    int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? :
                    (int) 
    Math.ceil(Math.sqrt(maxNumOfPixels));
            
    int upperBound = (minSideLength == UNCONSTRAINED) ? 128 :
                    (int) 
    Math.min(Math.floor(minSideLength),
                    
    Math.floor(minSideLength));

            if (
    upperBound lowerBound) {
                
    // return the larger one when there is no overlapping zone.
                
    return lowerBound;
            }

            if ((
    maxNumOfPixels == UNCONSTRAINED) &&
                    (
    minSideLength == UNCONSTRAINED)) {
                return 
    1;
            } else if (
    minSideLength == UNCONSTRAINED) {
                return 
    lowerBound;
            } else {
                return 
    upperBound;
            }
        }


    }

    Zu guter Letzt muss noch eine Methode her die mir die Thumbnails refreshed.

    PHP:
    package de.unicate.android.thumbnailtest;

    import android.content.ContentResolver;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.provider.MediaStore;
    import android.util.Log;

    public class 
    BitmapUtilities {
        
        private static final 
    String TAG BitmapUtilities.class.getSimpleName();
        
        public static 
    void refreshMicroThumbnails(ContentResolver crlong[] thumbnails2Refresh) {
            final 
    String[] PROJECTION = new String[] {MediaStore.Images.Media._IDMediaStore.Images.Media.DATA};        
            
    MiniThumbFile thumbFile MiniThumbFile.instance(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI);
            for(
    long origId thumbnails2Refresh) {
                
    Cursor c null;
                try {
                    
    Uri uri Uri.parse(
                            
    MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI.buildUpon().appendPath(String.valueOf(origId))
                                    .
    toString().replaceFirst("thumbnails""media"));
                    
    cr.query(uriPROJECTIONnullnullnull);
                    if (
    == null || !c.moveToFirst()) {
                        
    Log.e(TAG"cannot find thumbnailpath!");
                        return;
                    }
                    
    String filePath c.getString(1);
                    
    Bitmap bitmap ThumbnailUtils.createImageThumbnail(filePathMediaStore.Images.Thumbnails.MICRO_KIND);
                    
    thumbFile.createNewMicroThumbnail(bitmaporigId);
                } catch (
    Exception e) {
                    
    e.printStackTrace();
                } finally {
                    if(
    c!=null)c.close();
                }            
            }
        }
    }
    In einer Activity z.B. kann das ganze dann folgendermaßen aufgerufen werden:
    PHP:
    private Bitmap getThumbnail(long idint kindboolean forceRefresh) {
            if(
    forceRefresh)
                
    BitmapUtilities.refreshMicroThumbnails(getContentResolver(), new long[]{id});
            return 
    MediaStore.Images.Thumbnails.getThumbnail(this.getContentResolver(), idkindnull);
        }

    Ich hoffe ich kann damit noch jemandem helfen, da dieses Problem mich zum Wahnsinn getrieben hat.
     

Diese Seite empfehlen