我正在开发一个安卓应用程序。我已经使用延迟加载概念在我的应用程序中解析了文本和图像。它直到最后几天都可以正常工作,但今天它给出了错误
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
我有一堂课,我在其中使用bitmap
概念
package com.example.shareslab;
public final class UrlImageViewHelper {
private static final String LOGTAG = "UrlImageViewHelper";
public static int copyStream(InputStream input, OutputStream output) throws IOException
{
byte[] stuff = new byte[1024];
int read = 0;
int total = 0;
while ((read = input.read(stuff)) != -1)
{
output.write(stuff, 0, read);
total += read;
}
return total;
}
static Resources mResources;
static DisplayMetrics mMetrics;
private static void prepareResources(Context context) {
if (mMetrics != null)
return;
mMetrics = new DisplayMetrics();
Activity act = (Activity)context;
act.getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
AssetManager mgr = context.getAssets();
mResources = new Resources(mgr, mMetrics, context.getResources().getConfiguration());
}
private static BitmapDrawable loadDrawableFromStream(Context context, InputStream stream) {
prepareResources(context);
final Bitmap bitmap = BitmapFactory.decodeStream(stream);
//Log.i(LOGTAG, String.format("Loaded bitmap (%dx%d).", bitmap.getWidth(), bitmap.getHeight()));
return new BitmapDrawable(mResources, bitmap);
}
public static final int CACHE_DURATION_INFINITE = Integer.MAX_VALUE;
public static final int CACHE_DURATION_ONE_DAY = 1000 * 60 * 60 * 24;
public static final int CACHE_DURATION_TWO_DAYS = CACHE_DURATION_ONE_DAY * 2;
public static final int CACHE_DURATION_THREE_DAYS = CACHE_DURATION_ONE_DAY * 3;
public static final int CACHE_DURATION_FOUR_DAYS = CACHE_DURATION_ONE_DAY * 4;
public static final int CACHE_DURATION_FIVE_DAYS = CACHE_DURATION_ONE_DAY * 5;
public static final int CACHE_DURATION_SIX_DAYS = CACHE_DURATION_ONE_DAY * 6;
public static final int CACHE_DURATION_ONE_WEEK = CACHE_DURATION_ONE_DAY * 7;
public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource) {
setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, CACHE_DURATION_THREE_DAYS);
}
public static void setUrlDrawable(final ImageView imageView, final String url) {
setUrlDrawable(imageView.getContext(), imageView, url, null, CACHE_DURATION_THREE_DAYS);
}
public static void loadUrlDrawable(final Context context, final String url) {
setUrlDrawable(context, null, url, null, CACHE_DURATION_THREE_DAYS);
}
public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable) {
setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, CACHE_DURATION_ONE_DAY);
}
public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource, long cacheDurationMs) {
setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, cacheDurationMs);
}
public static void loadUrlDrawable(final Context context, final String url, long cacheDurationMs) {
setUrlDrawable(context, null, url, null, cacheDurationMs);
}
public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable, long cacheDurationMs) {
setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, cacheDurationMs);
}
private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, int defaultResource, long cacheDurationMs) {
Drawable d = null;
if (defaultResource != 0)
d = imageView.getResources().getDrawable(defaultResource);
setUrlDrawable(context, imageView, url, d, cacheDurationMs);
}
private static boolean isNullOrEmpty(CharSequence s) {
return (s == null || s.equals("") || s.equals("null") || s.equals("NULL"));
}
private static boolean mHasCleaned = false;
public static String getFilenameForUrl(String url) {
return "" + url.hashCode() + ".urlimage";
}
private static void cleanup(Context context) {
if (mHasCleaned)
return;
mHasCleaned = true;
try {
// purge any *.urlimage files over a week old
String[] files = context.getFilesDir().list();
if (files == null)
return;
for (String file : files) {
if (!file.endsWith(".urlimage"))
continue;
File f = new File(context.getFilesDir().getAbsolutePath() + '/' + file);
if (System.currentTimeMillis() > f.lastModified() + CACHE_DURATION_ONE_WEEK)
f.delete();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, final Drawable defaultDrawable, long cacheDurationMs) {
cleanup(context);
// disassociate this ImageView from any pending downloads
if (imageView != null)
mPendingViews.remove(imageView);
if (isNullOrEmpty(url)) {
if (imageView != null)
imageView.setImageDrawable(defaultDrawable);
return;
}
final UrlImageCache cache = UrlImageCache.getInstance();
Drawable d = cache.get(url);
if (d != null) {
//Log.i(LOGTAG, "Cache hit on: " + url);
if (imageView != null)
imageView.setImageDrawable(d);
return;
}
final String filename = getFilenameForUrl(url);
File file = context.getFileStreamPath(filename);
if (file.exists()) {
try {
if (cacheDurationMs == CACHE_DURATION_INFINITE || System.currentTimeMillis() < file.lastModified() + cacheDurationMs) {
//Log.i(LOGTAG, "File Cache hit on: " + url + ". " + (System.currentTimeMillis() - file.lastModified()) + "ms old.");
FileInputStream fis = context.openFileInput(filename);
BitmapDrawable drawable = loadDrawableFromStream(context, fis);
fis.close();
if (imageView != null)
imageView.setImageDrawable(drawable);
cache.put(url, drawable);
return;
}
else {
//Log.i(LOGTAG, "File cache has expired. Refreshing.");
}
}
catch (Exception ex) {
}
}
// null it while it is downloading
if (imageView != null)
imageView.setImageDrawable(defaultDrawable);
// since listviews reuse their views, we need to
// take note of which url this view is waiting for.
// This may change rapidly as the list scrolls or is filtered, etc.
//Log.i(LOGTAG, "Waiting for " + url);
if (imageView != null)
mPendingViews.put(imageView, url);
ArrayList<ImageView> currentDownload = mPendingDownloads.get(url);
if (currentDownload != null) {
// Also, multiple vies may be waiting for this url.
// So, let's maintain a list of these views.
// When the url is downloaded, it sets the imagedrawable for
// every view in the list. It needs to also validate that
// the imageview is still waiting for this url.
if (imageView != null)
currentDownload.add(imageView);
return;
}
final ArrayList<ImageView> downloads = new ArrayList<ImageView>();
if (imageView != null)
downloads.add(imageView);
mPendingDownloads.put(url, downloads);
AsyncTask<Void, Void, Drawable> downloader = new AsyncTask<Void, Void, Drawable>() {
@Override
protected Drawable doInBackground(Void... params) {
AndroidHttpClient client = AndroidHttpClient.newInstance(context.getPackageName());
try {
HttpGet get = new HttpGet(url);
final HttpParams httpParams = new BasicHttpParams();
HttpClientParams.setRedirecting(httpParams, true);
get.setParams(httpParams);
HttpResponse resp = client.execute(get);
int status = resp.getStatusLine().getStatusCode();
if(status != HttpURLConnection.HTTP_OK){
// Log.i(LOGTAG, "Couldn't download image from Server: " + url + " Reason: " + resp.getStatusLine().getReasonPhrase() + " / " + status);
return null;
}
HttpEntity entity = resp.getEntity();
// Log.i(LOGTAG, url + " Image Content Length: " + entity.getContentLength());
InputStream is = entity.getContent();
FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
copyStream(is, fos);
fos.close();
is.close();
FileInputStream fis = context.openFileInput(filename);
return loadDrawableFromStream(context, fis);
}
catch (Exception ex) {
// Log.e(LOGTAG, "Exception during Image download of " + url, ex);
return null;
}
finally {
client.close();
}
}
@Override
protected void onPostExecute(Drawable result) {
if (result == null)
result = defaultDrawable;
mPendingDownloads.remove(url);
cache.put(url, result);
for (ImageView iv: downloads) {
// validate the url it is waiting for
String pendingUrl = mPendingViews.get(iv);
if (!url.equals(pendingUrl)) {
//Log.i(LOGTAG, "Ignoring out of date request to update view for " + url);
continue;
}
mPendingViews.remove(iv);
if (result != null) {
final Drawable newImage = result;
Drawable newSize=resize(newImage);
final ImageView imageView = iv;
imageView.setImageDrawable(newSize);
}
}
}
private BitmapDrawable resize(Drawable newImage) {
// TODO Auto-generated method stub
Bitmap d = ((BitmapDrawable)newImage).getBitmap();
Bitmap bitmapOrig = Bitmap.createScaledBitmap(d, 75, 75, false);
return new BitmapDrawable(bitmapOrig);
}
};
downloader.execute();
}
private static Hashtable<ImageView, String> mPendingViews = new Hashtable<ImageView, String>();
private static Hashtable<String, ArrayList<ImageView>> mPendingDownloads = new Hashtable<String, ArrayList<ImageView>>();
}
我的应用程序中的另一个问题是当我从详细信息页面返回时,我的图像尺寸变得非常小。我该如何处理?