Skip to content

Most visited

Recently visited

navigation
MediaBrowserService / src / com.example.android.mediabrowserservice /

AlbumArtCache.java

1
/*
2
 * Copyright (C) 2014 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.mediabrowserservice;
18
 
19
import android.graphics.Bitmap;
20
import android.os.AsyncTask;
21
import android.util.LruCache;
22
 
23
import com.example.android.mediabrowserservice.utils.BitmapHelper;
24
import com.example.android.mediabrowserservice.utils.LogHelper;
25
 
26
import java.io.IOException;
27
 
28
/**
29
 * Implements a basic cache of album arts, with async loading support.
30
 */
31
public final class AlbumArtCache {
32
    private static final String TAG = LogHelper.makeLogTag(AlbumArtCache.class);
33
 
34
    private static final int MAX_ALBUM_ART_CACHE_SIZE = 12*1024*1024;  // 12 MB
35
    private static final int MAX_ART_WIDTH = 800;  // pixels
36
    private static final int MAX_ART_HEIGHT = 480;  // pixels
37
 
38
    // Resolution reasonable for carrying around as an icon (generally in
39
    // MediaDescription.getIconBitmap). This should not be bigger than necessary, because
40
    // the MediaDescription object should be lightweight. If you set it too high and try to
41
    // serialize the MediaDescription, you may get FAILED BINDER TRANSACTION errors.
42
    private static final int MAX_ART_WIDTH_ICON = 128;  // pixels
43
    private static final int MAX_ART_HEIGHT_ICON = 128;  // pixels
44
 
45
    private static final int BIG_BITMAP_INDEX = 0;
46
    private static final int ICON_BITMAP_INDEX = 1;
47
 
48
    private final LruCache<String, Bitmap[]> mCache;
49
 
50
    private static final AlbumArtCache sInstance = new AlbumArtCache();
51
 
52
    public static AlbumArtCache getInstance() {
53
        return sInstance;
54
    }
55
 
56
    private AlbumArtCache() {
57
        // Holds no more than MAX_ALBUM_ART_CACHE_SIZE bytes, bounded by maxmemory/4 and
58
        // Integer.MAX_VALUE:
59
        int maxSize = Math.min(MAX_ALBUM_ART_CACHE_SIZE,
60
            (int) (Math.min(Integer.MAX_VALUE, Runtime.getRuntime().maxMemory()/4)));
61
        mCache = new LruCache<String, Bitmap[]>(maxSize) {
62
            @Override
63
            protected int sizeOf(String key, Bitmap[] value) {
64
                return value[BIG_BITMAP_INDEX].getByteCount()
65
                    + value[ICON_BITMAP_INDEX].getByteCount();
66
            }
67
        };
68
    }
69
 
70
    public Bitmap getBigImage(String artUrl) {
71
        Bitmap[] result = mCache.get(artUrl);
72
        return result == null ? null : result[BIG_BITMAP_INDEX];
73
    }
74
 
75
    public Bitmap getIconImage(String artUrl) {
76
        Bitmap[] result = mCache.get(artUrl);
77
        return result == null ? null : result[ICON_BITMAP_INDEX];
78
    }
79
 
80
    public void fetch(final String artUrl, final FetchListener listener) {
81
        // WARNING: for the sake of simplicity, simultaneous multi-thread fetch requests
82
        // are not handled properly: they may cause redundant costly operations, like HTTP
83
        // requests and bitmap rescales. For production-level apps, we recommend you use
84
        // a proper image loading library, like Glide.
85
        Bitmap[] bitmap = mCache.get(artUrl);
86
        if (bitmap != null) {
87
            LogHelper.d(TAG, "getOrFetch: album art is in cache, using it", artUrl);
88
            listener.onFetched(artUrl, bitmap[BIG_BITMAP_INDEX], bitmap[ICON_BITMAP_INDEX]);
89
            return;
90
        }
91
        LogHelper.d(TAG, "getOrFetch: starting asynctask to fetch ", artUrl);
92
 
93
        new AsyncTask<Void, Void, Bitmap[]>() {
94
            @Override
95
            protected Bitmap[] doInBackground(Void[] objects) {
96
                Bitmap[] bitmaps;
97
                try {
98
                    Bitmap bitmap = BitmapHelper.fetchAndRescaleBitmap(artUrl,
99
                        MAX_ART_WIDTH, MAX_ART_HEIGHT);
100
                    Bitmap icon = BitmapHelper.scaleBitmap(bitmap,
101
                        MAX_ART_WIDTH_ICON, MAX_ART_HEIGHT_ICON);
102
                    bitmaps = new Bitmap[] {bitmap, icon};
103
                    mCache.put(artUrl, bitmaps);
104
                } catch (IOException e) {
105
                    return null;
106
                }
107
                LogHelper.d(TAG, "doInBackground: putting bitmap in cache. cache size=" +
108
                    mCache.size());
109
                return bitmaps;
110
            }
111
 
112
            @Override
113
            protected void onPostExecute(Bitmap[] bitmaps) {
114
                if (bitmaps == null) {
115
                    listener.onError(artUrl, new IllegalArgumentException("got null bitmaps"));
116
                } else {
117
                    listener.onFetched(artUrl,
118
                        bitmaps[BIG_BITMAP_INDEX], bitmaps[ICON_BITMAP_INDEX]);
119
                }
120
            }
121
        }.execute();
122
    }
123
 
124
    public static abstract class FetchListener {
125
        public abstract void onFetched(String artUrl, Bitmap bigImage, Bitmap iconImage);
126
        public void onError(String artUrl, Exception e) {
127
            LogHelper.e(TAG, e, "AlbumArtFetchListener: error while downloading " + artUrl);
128
        }
129
    }
130
}
This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.