Android Open Source - webimageloader Disk Loader






From Project

Back to project page webimageloader.

License

The source code is released under:

Apache License

If you think the Android project webimageloader listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.webimageloader.loader;
//from  w w  w.j ava  2  s. c o m
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.graphics.Bitmap;
import android.os.Process;
import android.util.Log;

import com.jakewharton.disklrucache.DiskLruCache;
import com.jakewharton.disklrucache.DiskLruCache.Editor;
import com.jakewharton.disklrucache.DiskLruCache.Snapshot;
import com.webimageloader.Constants;
import com.webimageloader.ImageLoader.Logger;
import com.webimageloader.util.ListenerFuture;
import com.webimageloader.util.BitmapUtils;
import com.webimageloader.util.Hasher;
import com.webimageloader.util.IOUtil;
import com.webimageloader.util.InputSupplier;

import static com.webimageloader.Request.Flag.IGNORE_CACHE;
import static com.webimageloader.Request.Flag.NO_CACHE;
import static com.webimageloader.Request.Flag.SKIP_DISK_CACHE;

public class DiskLoader extends SimpleBackgroundLoader implements Closeable {
    private static final String TAG = "DiskLoader";

    private static final int APP_VERSION = 2;

    private static final int BUFFER_SIZE = 8192;

    private static final int INPUT_IMAGE = 0;
    private static final int INPUT_METADATA = 1;
    private static final int VALUE_COUNT = 2;

    private DiskLruCache cache;
    private final Hasher hasher;

    public static DiskLoader open(File directory, long maxSize, int threadCount) throws IOException {
        return new DiskLoader(DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize), threadCount);
    }

    private DiskLoader(DiskLruCache cache, int threadCount) {
        super("Disk", Process.THREAD_PRIORITY_BACKGROUND, threadCount);

        this.cache = cache;
        hasher = new Hasher();
    }

    @Override
    public void close() {
        super.close();

        IOUtil.closeQuietly(cache);
    }

    @Override
    public void load(LoaderWork.Manager manager, LoaderRequest request) {
        if (request.hasFlag(IGNORE_CACHE) || request.hasFlag(SKIP_DISK_CACHE)) {
            manager.next(request, new NextListener(request, manager));
            return;
        }

        super.load(manager, request);
    }

    @Override
    protected void loadInBackground(LoaderWork.Manager manager, LoaderRequest request) throws IOException {
        Snapshot snapshot = getSnapshot(request);
        if (snapshot != null) {
            try {
                if (Logger.VERBOSE) Log.v(TAG, "Loaded " + request + " from disk");

                Metadata metadata = readMetadata(snapshot);
                DiskInputSupplier input = new DiskInputSupplier(request, snapshot);

                manager.deliverStream(input, metadata);

                long expires = metadata.getExpires();
                if (expires != Metadata.NEVER_EXPIRES && System.currentTimeMillis() > expires) {
                    // Cache has expired
                    if (Logger.VERBOSE) Log.v(TAG, request + " has expired, updating");
                    manager.next(request.withMetadata(metadata), new NextListener(request, manager));
                }
            } finally {
                snapshot.close();
            }
        } else {
            // We need to add the next loader
            manager.next(request, new NextListener(request, manager));
        }
    }

    private Metadata readMetadata(Snapshot snapshot) throws IOException {
        // Use a small buffer as the metadata itself is small
        InputStream is = new BufferedInputStream(snapshot.getInputStream(INPUT_METADATA), 1024);
        try {
            return Metadata.from(is);
        } finally {
            is.close();
        }
    }

    private Snapshot getSnapshot(LoaderRequest request) throws IOException {
        String key = hashKeyForDisk(request);
        return cache.get(key);
    }

    private Editor getEditor(LoaderRequest request) throws IOException {
        String key = hashKeyForDisk(request);

        Editor editor = cache.edit(key);
        if (editor == null) {
            throw new IOException("File is already being edited");
        }

        return editor;
    }

    /**
     * A hashing method that changes a string (like a URL) into a hash suitable
     * for using as a disk filename.
     */
    private String hashKeyForDisk(LoaderRequest request) {
        String key = request.getCacheKey();

        // We don't except to have a lot of threads
        // so it's okay to synchronize access
        synchronized (hasher) {
            return hasher.hash(key);
        }
    }

    private class NextListener implements Listener {
        private LoaderRequest request;
        private LoaderWork.Manager manager;

        public NextListener(LoaderRequest request, LoaderWork.Manager manager) {
            this.request = request;
            this.manager = manager;
        }

        @Override
        public void onStreamLoaded(InputSupplier input, final Metadata metadata) {
            if (request.hasFlag(NO_CACHE) || request.hasFlag(SKIP_DISK_CACHE)) {
                manager.deliverStream(input, metadata);
                return;
            }

            try {
                Editor editor = getEditor(request);

                OutputStream os = new BufferedOutputStream(editor.newOutputStream(INPUT_IMAGE), BUFFER_SIZE);
                try {
                    try {
                        copy(input, os);
                    } finally {
                        os.close();
                    }

                    writeMetadata(editor, metadata);

                    editor.commit();

                    // Read back the file we just saved
                    run(manager, new ListenerFuture.Task() {
                        @Override
                        public void run() throws Exception {
                            DiskInputSupplier input = new DiskInputSupplier(request);
                            manager.deliverStream(input, metadata);
                        }
                    });
                } catch (IOException e) {
                    // We failed writing to the cache, we can't really do
                    // anything to clean this up
                    editor.abort();
                    manager.deliverError(e);
                }
            } catch (IOException e) {
                // We failed opening the cache, this
                // means that the InputStream is still untouched.
                // Pass it trough to the listener without caching.
                Log.e(TAG, "Failed opening cache", e);
                manager.deliverStream(input, metadata);
            }
        }

        public void copy(InputSupplier input, OutputStream output) throws IOException {
            long length = input.getLength();
            InputStream is = new BufferedInputStream(input.getInput(), BUFFER_SIZE);

            try {
                copy(is, output, length);
            } finally {
                is.close();
            }
        }

        public void copy(InputStream input, OutputStream output, long length) throws IOException {
            byte[] buffer = new byte[BUFFER_SIZE];

            if (length != -1) {
                manager.publishProgress(0f);

                long progress = 0;
                int i;
                while ((i = input.read(buffer)) != -1) {
                    output.write(buffer, 0, i);
                    progress += i;
                    manager.publishProgress(Math.min(1f, (float) progress / length));
                }
            } else {
                int i;
                while ((i = input.read(buffer)) != -1) {
                    output.write(buffer, 0, i);
                }
            }
        }

        @Override
        public void onBitmapLoaded(Bitmap b, Metadata metadata) {
            try {
                Editor editor = getEditor(request);

                try {
                    Bitmap.CompressFormat format = BitmapUtils.getCompressFormat(metadata.getContentType());
                    writeBitmap(editor, b, format);
                    writeMetadata(editor, metadata);

                    editor.commit();
                } finally {
                    editor.abortUnlessCommitted();
                }
            } catch (IOException e) {
                Log.e(TAG, "Failed saving bitmap to cache", e);
            }

            // We can always pass on the bitmap we got, even if
            // we didn't manage to write it to cache
            manager.deliverBitmap(b, metadata);
        }

        @Override
        public void onNotModified(Metadata metadata) {
            try {
                Editor editor = getEditor(request);

                try {
                    writeMetadata(editor, metadata);

                    editor.commit();
                } finally {
                    editor.abortUnlessCommitted();
                }
            } catch (IOException e) {
                Log.e(TAG, "Failed to update metadata", e);
            }

            manager.deliverNotMotified(metadata);
        }

        @Override
        public void onError(Throwable t) {
            manager.deliverError(t);
        }

        private void writeMetadata(Editor editor, Metadata metadata) throws IOException {
            OutputStream os = new BufferedOutputStream(editor.newOutputStream(INPUT_METADATA), BUFFER_SIZE);
            try {
                metadata.writeTo(os);
            } finally {
                IOUtil.closeQuietly(os);
            }
        }

        private void writeBitmap(Editor editor, Bitmap b, Bitmap.CompressFormat format) throws IOException {
            OutputStream os = new BufferedOutputStream(editor.newOutputStream(INPUT_IMAGE), BUFFER_SIZE);
            try {
                b.compress(format, Constants.DEFAULT_COMPRESS_QUALITY, os);
            } finally {
                IOUtil.closeQuietly(os);
            }
        }
    }

    private class DiskInputSupplier implements InputSupplier {
        private String key;
        private Snapshot snapshot;

        public DiskInputSupplier(LoaderRequest request) {
            this(request, null);
        }

        public DiskInputSupplier(LoaderRequest request, Snapshot snapshot) {
            this.key = hashKeyForDisk(request);
            this.snapshot = snapshot;
        }

        @Override
        public long getLength() throws IOException {
            return cache.get(key).getLength(INPUT_IMAGE);
        }

        @Override
        public InputStream getInput() throws IOException {
            if (snapshot == null) {
                snapshot = cache.get(key);

                if (snapshot == null) {
                    throw new IOException("Snapshot not available");
                }
            }

            // Wrap input stream so we can close the snapshot
            return new FilterInputStream(snapshot.getInputStream(INPUT_IMAGE)) {
                @Override
                public void close() throws IOException {
                    super.close();

                    snapshot.close();
                    snapshot = null;
                }
            };
        }
    }
}




Java Source Code List

com.webimageloader.ConnectionFactory.java
com.webimageloader.ConnectionHandler.java
com.webimageloader.Constants.java
com.webimageloader.ImageLoaderImpl.java
com.webimageloader.ImageLoader.java
com.webimageloader.Request.java
com.webimageloader.content.ContentURLConnection.java
com.webimageloader.content.ContentURLStreamHandler.java
com.webimageloader.ext.ImageHelper.java
com.webimageloader.ext.ImageLoaderApplication.java
com.webimageloader.loader.BackgroundLoader.java
com.webimageloader.loader.DiskLoader.java
com.webimageloader.loader.LoaderManager.java
com.webimageloader.loader.LoaderRequest.java
com.webimageloader.loader.LoaderWork.java
com.webimageloader.loader.Loader.java
com.webimageloader.loader.MemoryCache.java
com.webimageloader.loader.MemoryLoader.java
com.webimageloader.loader.Metadata.java
com.webimageloader.loader.NetworkLoader.java
com.webimageloader.loader.PendingRequests.java
com.webimageloader.loader.SimpleBackgroundLoader.java
com.webimageloader.loader.TransformingLoader.java
com.webimageloader.sample.AsyncLoader.java
com.webimageloader.sample.ExampleApplication.java
com.webimageloader.sample.FastImageView.java
com.webimageloader.sample.MainActivity.java
com.webimageloader.sample.numbers.NumberDetailsActivity.java
com.webimageloader.sample.numbers.NumbersActivity.java
com.webimageloader.sample.patterns.PatternDetailsActivity.java
com.webimageloader.sample.patterns.PatternsActivity.java
com.webimageloader.sample.patterns.PatternsListFragment.java
com.webimageloader.sample.progress.ProgressActivity.java
com.webimageloader.transformation.ScaleTransformation.java
com.webimageloader.transformation.SimpleTransformation.java
com.webimageloader.transformation.Transformation.java
com.webimageloader.util.AbstractImageLoader.java
com.webimageloader.util.Android.java
com.webimageloader.util.BitmapUtils.java
com.webimageloader.util.FlushedInputStream.java
com.webimageloader.util.Hasher.java
com.webimageloader.util.HeaderParser.java
com.webimageloader.util.IOUtil.java
com.webimageloader.util.InputSupplier.java
com.webimageloader.util.ListenerFuture.java
com.webimageloader.util.LruCache.java
com.webimageloader.util.PriorityThreadFactory.java
com.webimageloader.util.WaitFuture.java