0

我正在开发一个安卓应用程序。我已经使用延迟加载概念在我的应用程序中解析了文本和图像。它直到最后几天都可以正常工作,但今天它给出了错误

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>>();
}

我的应用程序中的另一个问题是当我从详细信息页面返回时,我的图像尺寸变得非常小。我该如何处理?

4

1 回答 1

0

尝试使用 BitmapFactory 选项作为

BitmapFactory.Options op=new BitmapFactory.Options();
op.inSampleSize=4;
final Bitmap bitmap = BitmapFactory.decodeStream(stream,null,op);
于 2012-10-30T11:57:43.687 回答