1 /* 2 * Copyright (C) 2011 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.ex.photo.loaders; 19 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.graphics.Bitmap; 23 import android.net.Uri; 24 import android.support.v4.content.AsyncTaskLoader; 25 import android.util.DisplayMetrics; 26 27 import com.android.ex.photo.fragments.PhotoViewFragment; 28 import com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult; 29 import com.android.ex.photo.util.ImageUtils; 30 31 /** 32 * Loader for the bitmap of a photo. 33 */ 34 public class PhotoBitmapLoader extends AsyncTaskLoader<BitmapResult> 35 implements PhotoBitmapLoaderInterface { 36 private String mPhotoUri; 37 private Bitmap mBitmap; 38 39 public PhotoBitmapLoader(Context context, String photoUri) { 40 super(context); 41 mPhotoUri = photoUri; 42 } 43 44 @Override 45 public void setPhotoUri(String photoUri) { 46 mPhotoUri = photoUri; 47 } 48 49 @Override 50 public BitmapResult loadInBackground() { 51 BitmapResult result = new BitmapResult(); 52 Context context = getContext(); 53 if (context != null && mPhotoUri != null) { 54 final ContentResolver resolver = context.getContentResolver(); 55 try { 56 result = ImageUtils.createLocalBitmap(resolver, Uri.parse(mPhotoUri), 57 PhotoViewFragment.sPhotoSize); 58 if (result.bitmap != null) { 59 result.bitmap.setDensity(DisplayMetrics.DENSITY_MEDIUM); 60 } 61 } catch (UnsupportedOperationException ex) { 62 // We got image bytes, but unable to decode to a Bitmap 63 result.status = BitmapResult.STATUS_EXCEPTION; 64 } 65 } 66 67 return result; 68 } 69 70 /** 71 * Called when there is new data to deliver to the client. The 72 * super class will take care of delivering it; the implementation 73 * here just adds a little more logic. 74 */ 75 @Override 76 public void deliverResult(BitmapResult result) { 77 Bitmap bitmap = result != null ? result.bitmap : null; 78 if (isReset()) { 79 // An async query came in while the loader is stopped. We 80 // don't need the result. 81 if (bitmap != null) { 82 onReleaseResources(bitmap); 83 } 84 return; 85 } 86 Bitmap oldBitmap = mBitmap; 87 mBitmap = bitmap; 88 89 if (isStarted()) { 90 // If the Loader is currently started, we can immediately 91 // deliver its results. 92 super.deliverResult(result); 93 } 94 95 // At this point we can release the resources associated with 96 // 'oldBitmap' if needed; now that the new result is delivered we 97 // know that it is no longer in use. 98 if (oldBitmap != null && oldBitmap != bitmap && !oldBitmap.isRecycled()) { 99 onReleaseResources(oldBitmap); 100 } 101 } 102 103 /** 104 * Handles a request to start the Loader. 105 */ 106 @Override 107 protected void onStartLoading() { 108 if (mBitmap != null) { 109 // If we currently have a result available, deliver it 110 // immediately. 111 BitmapResult result = new BitmapResult(); 112 result.status = BitmapResult.STATUS_SUCCESS; 113 result.bitmap = mBitmap; 114 deliverResult(result); 115 } 116 117 if (takeContentChanged() || mBitmap == null) { 118 // If the data has changed since the last time it was loaded 119 // or is not currently available, start a load. 120 forceLoad(); 121 } 122 } 123 124 /** 125 * Handles a request to stop the Loader. 126 */ 127 @Override protected void onStopLoading() { 128 // Attempt to cancel the current load task if possible. 129 cancelLoad(); 130 } 131 132 /** 133 * Handles a request to cancel a load. 134 */ 135 @Override 136 public void onCanceled(BitmapResult result) { 137 super.onCanceled(result); 138 139 // At this point we can release the resources associated with 'bitmap' 140 // if needed. 141 if (result != null) { 142 onReleaseResources(result.bitmap); 143 } 144 } 145 146 /** 147 * Handles a request to completely reset the Loader. 148 */ 149 @Override 150 protected void onReset() { 151 super.onReset(); 152 153 // Ensure the loader is stopped 154 onStopLoading(); 155 156 // At this point we can release the resources associated with 'bitmap' 157 // if needed. 158 if (mBitmap != null) { 159 onReleaseResources(mBitmap); 160 mBitmap = null; 161 } 162 } 163 164 /** 165 * Helper function to take care of releasing resources associated 166 * with an actively loaded data set. 167 */ 168 protected void onReleaseResources(Bitmap bitmap) { 169 if (bitmap != null && !bitmap.isRecycled()) { 170 bitmap.recycle(); 171 } 172 } 173 } 174