在使用AsyncTask和大图像时OutOfMemory

时间:2012-07-21 01:08:56

标签: android image android-asynctask out-of-memory

下面的类解析rss提要并使用AsyncTask在屏幕上绘制图像/文本。我使用的是nasa rss feed。昨晚我切换到相同的饲料,但图像较大。现在,当我尝试按下刷新按钮时,内存耗尽。我怎么处理这个?我知道这只是因为图像太大(大约6mb,相比之下另一幅图像的36kb)而且我已经读过静态也无济于事。我没有看到任何方式它是静态的,因为当你将壁纸设置为图像时,我需要将final_image检索为类的单独实例。所以下面的一切都适用于较小的图像。使用大图像,它只工作一次,但如果你试图按下刷新按钮(它只运行RssParseSync.execute())它无法刷新,我得到下面的错误。我想要更大的图像,因为当将它设置为壁纸时,小图像看起来非常糟糕。

public class RssParseSync extends AsyncTask<String,String,Bitmap>{  

        private Activity parent;
        private ProgressDialog dialog;
        private static Bitmap final_image; //must be static because a new instance is required to access getFinalImage();


        public RssParseSync(Activity parent){this.parent =parent;}//constructor to pass parent activity, need this to call findViewById

                private XmlPullParser makeParser(){

                }

                @Override
                protected Bitmap doInBackground(String... info){

                    URL iotd;
                    int count=info.length;
                    String title="",link="",description="",date="";

                    System.out.println("Number of params is "+count);

                    try{

                        iotd = new URL("http://www.nasa.gov/rss/lg_image_of_the_day.rss");//set URl
                        BufferedReader in;//new BufferedReader
                        in = new BufferedReader(new InputStreamReader(iotd.openStream()));//get rss

                        XmlPullParserFactory factory;
                        factory = XmlPullParserFactory.newInstance();//new factory


                        factory.setNamespaceAware(true);
                        XmlPullParser xpp;
                        xpp = factory.newPullParser();
                        xpp.setInput(in);

                        //rss is now parsed, free to use XmlPullParser functions to move around and evaulate the rss

                        int eventType;
                        eventType = xpp.getEventType();//returns an int which mean different things (START_DOCUMENT,START_TAG,etc)


                    while(eventType!=XmlPullParser.END_DOCUMENT){//while the document has words

                     switch(eventType){

                        case XmlPullParser.START_DOCUMENT://beginning of xml
                            break;
                        case XmlPullParser.START_TAG://case : at beginning of new tag
                            String tagName=xpp.getName();
                            System.out.println(tagName+" "+xpp.getDepth());

                            if(tagName.equals("title")&& xpp.getDepth()==4){//depth is specific to this certain rss feed, there are multiple tags with the same names
                                info[0]=xpp.nextText();
                                title=info[0];

                            }

                            if(tagName.equals("description")&& xpp.getDepth()==4){//depth is specific to this certain rss feed, there are multiple tags with the same names
                                info[1]=xpp.nextText();
                                description=info[1];    
                                StringBuilder tabbed=new StringBuilder(description);
                                tabbed.insert(0, "\t");
                                description=tabbed.toString();
                                //info[1]=description;
                            }

                            if(tagName.equals("pubDate")){//no depth needed, only one tag is named pubDate
                                info[2]=xpp.nextText();
                                date=info[2];                           
                            }

                            if(tagName.equals("enclosure")&&xpp.getDepth()==4){//this is where our image url is. this url is an attribute of the "enclosure" tag
                                //System.out.println("Enclosure has "+xpp.getAttributeCount());
                                for(int i=0; i<=xpp.getAttributeCount()-1; i++){
                                    System.out.println("in for");
                                    if(xpp.getAttributeName(i).equals("url")){
                                        link=xpp.getAttributeValue(i);
                                        info[3]=link;
                                        //System.out.println(link);
                                    }
                                }
                            }
                            break;

                        }
                        eventType=xpp.next();
                    }//switch

                        publishProgress(title,description,date,link);

                        in.close();//close BufferedReader
                    } catch (MalformedURLException e){
                        e.printStackTrace();
                    }catch(XmlPullParserException e1){
                        e1.printStackTrace();
                    }catch(IOException e2){
                        e2.printStackTrace();
                    }         
                    Bitmap image=getBitmapFromURL(info[3]);

                    return image;
                }
                @Override
                protected void onProgressUpdate(String... progress){
                    try {
                        System.out.println("onProgressUpdate");
                        resetDisplay(progress[0],progress[1],progress[2],progress[3]);//feeding parsed rss values, title, description, date, and link
                    } catch (MalformedURLException e) {//both exceptions are thrown by resetDisplay
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }

                protected void onPostExecute(Bitmap image){//error when doing this in resetDisplay.... onPostExecute is invoked by the ui thread so this may be why it works here and not in resetDisplay
                    ImageView imageView=(ImageView) parent.findViewById(R.id.imageDisplay);
                    imageView.setImageBitmap(image);
                    final_image=image;
                    dialog.dismiss();

                }

                protected void onPreExecute(){
                     dialog=ProgressDialog.show(parent, "Loading", "Loading the image of the day");
                }

                private void resetDisplay(String title, String description,String date, String link) throws MalformedURLException, IOException{

                    TextView titleView=(TextView) parent.findViewById(R.id.imageTitle);
                    titleView.setText(title);

                    TextView dateView=(TextView) parent.findViewById(R.id.imageDate);
                    dateView.setText(date);

                    TextView descriptionView=(TextView) parent.findViewById(R.id.imageDescription);
                    descriptionView.setText(description);

                }

                public Bitmap getBitmapFromURL(String url) {
                    try {
                    Bitmap bitmap=null; 
                    InputStream input = new java.net.URL(url).openStream();
                    bitmap = BitmapFactory.decodeStream(input);//Decode an input stream into a bitmap. If the input stream is null, or cannot be used to decode a bitmap, the function returns null.
                    input.close();
                    return bitmap;
                    } catch (IOException ioe) { return null; }

                }

                public Bitmap getFinalImage(){
                    return final_image;
                };


    }//class

刷新方法

public void onRefresh(){
    System.out.println("in onRefresh");
    new RssParseSync(getActivity()).execute(title,description,date,link);
}

Logcat日志

07-20 17:44:18.470: I/System.out(7581): onProgressUpdate
07-20 17:44:18.770: D/dalvikvm(7581): GC_FOR_ALLOC freed 190K, 3% free 26538K/27299K, paused 46ms
07-20 17:44:18.770: I/dalvikvm-heap(7581): Forcing collection of SoftReferences for 24107536-byte allocation
07-20 17:44:18.790: D/dalvikvm(7581): GC_BEFORE_OOM freed 18K, 3% free 26519K/27299K, paused 23ms
07-20 17:44:18.790: E/dalvikvm-heap(7581): Out of memory on a 24107536-byte allocation.
07-20 17:44:18.790: I/dalvikvm(7581): "AsyncTask #2" prio=5 tid=13 RUNNABLE
07-20 17:44:18.790: I/dalvikvm(7581):   | group="main" sCount=0 dsCount=0 obj=0x40d6cac8 self=0x2412840
07-20 17:44:18.790: I/dalvikvm(7581):   | sysTid=7646 nice=10 sched=0/0 cgrp=default handle=32889544
07-20 17:44:18.790: I/dalvikvm(7581):   | schedstat=( 0 0 0 ) utm=7 stm=0 core=1
07-20 17:44:18.790: I/dalvikvm(7581):   at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
07-20 17:44:18.800: I/dalvikvm(7581):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:719)
07-20 17:44:18.800: I/dalvikvm(7581):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:791)
07-20 17:44:18.800: I/dalvikvm(7581):   at com.wajumbie.nasadailyimage.RssParseSync.getBitmapFromURL(RssParseSync.java:162)
07-20 17:44:18.800: I/dalvikvm(7581):   at com.wajumbie.nasadailyimage.RssParseSync.doInBackground(RssParseSync.java:116)
07-20 17:44:18.800: I/dalvikvm(7581):   at com.wajumbie.nasadailyimage.RssParseSync.doInBackground(RssParseSync.java:1)
07-20 17:44:18.800: I/dalvikvm(7581):   at android.os.AsyncTask$2.call(AsyncTask.java:264)
07-20 17:44:18.800: I/dalvikvm(7581):   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-20 17:44:18.800: I/dalvikvm(7581):   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-20 17:44:18.800: I/dalvikvm(7581):   at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
07-20 17:44:18.800: I/dalvikvm(7581):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-20 17:44:18.800: I/dalvikvm(7581):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-20 17:44:18.800: I/dalvikvm(7581):   at java.lang.Thread.run(Thread.java:864)
07-20 17:44:18.800: E/dalvikvm(7581): Out of memory: Heap Size=34019KB, Allocated=26519KB, Limit=49152KB
07-20 17:44:18.800: E/dalvikvm(7581): Extra info: Footprint=27299KB, Allowed Footprint=34019KB, Trimmed=1212KB
07-20 17:44:18.800: D/skia(7581): --- decoder->decode returned false
07-20 17:44:18.800: W/dalvikvm(7581): threadid=13: thread exiting with uncaught exception (group=0x40aa3a08)
07-20 17:44:18.810: E/AndroidRuntime(7581): FATAL EXCEPTION: AsyncTask #2
07-20 17:44:18.810: E/AndroidRuntime(7581): java.lang.RuntimeException: An error occured while executing doInBackground()
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.os.AsyncTask$3.done(AsyncTask.java:278)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.lang.Thread.run(Thread.java:864)
07-20 17:44:18.810: E/AndroidRuntime(7581): Caused by: java.lang.OutOfMemoryError: (Heap Size=34019KB, Allocated=26519KB)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:719)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:791)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at com.wajumbie.nasadailyimage.RssParseSync.getBitmapFromURL(RssParseSync.java:162)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at com.wajumbie.nasadailyimage.RssParseSync.doInBackground(RssParseSync.java:116)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at com.wajumbie.nasadailyimage.RssParseSync.doInBackground(RssParseSync.java:1)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at android.os.AsyncTask$2.call(AsyncTask.java:264)
07-20 17:44:18.810: E/AndroidRuntime(7581):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-20 17:44:18.810: E/AndroidRuntime(7581):     ... 5 more
07-20 17:44:19.061: D/OpenGLRenderer(7581): Flushing caches (mode 0)
07-20 17:44:19.061: D/memalloc(7581): ion: Unmapping buffer  base:0x52738000 size:2088960
07-20 17:44:19.061: D/memalloc(7581): ion: Unmapping buffer  base:0x52f7c000 size:2088960
07-20 17:44:19.061: D/memalloc(7581): ion: Unmapping buffer  base:0x53477000 size:2088960
07-20 17:44:19.081: D/OpenGLRenderer(7581): Flushing caches (mode 0)
07-20 17:44:19.111: D/memalloc(7581): ion: Unmapping buffer  base:0x52bea000 size:524288
07-20 17:44:19.121: D/memalloc(7581): ion: Unmapping buffer  base:0x5367d000 size:524288
07-20 17:44:19.121: D/memalloc(7581): ion: Unmapping buffer  base:0x53326000 size:524288
07-20 17:44:19.141: D/OpenGLRenderer(7581): Flushing caches (mode 2)
07-20 17:44:19.181: E/WindowManager(7581): Activity com.wajumbie.nasadailyimage.NasaAppActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40d92b30 that was originally added here
07-20 17:44:19.181: E/WindowManager(7581): android.view.WindowLeaked: Activity com.wajumbie.nasadailyimage.NasaAppActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40d92b30 that was originally added here
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:380)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:372)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.Window$LocalWindowManager.addView(Window.java:557)
07-20 17:44:19.181: E/WindowManager(7581):  at android.app.Dialog.show(Dialog.java:301)
07-20 17:44:19.181: E/WindowManager(7581):  at android.app.ProgressDialog.show(ProgressDialog.java:116)
07-20 17:44:19.181: E/WindowManager(7581):  at android.app.ProgressDialog.show(ProgressDialog.java:99)
07-20 17:44:19.181: E/WindowManager(7581):  at android.app.ProgressDialog.show(ProgressDialog.java:94)
07-20 17:44:19.181: E/WindowManager(7581):  at com.wajumbie.nasadailyimage.RssParseSync.onPreExecute(RssParseSync.java:142)
07-20 17:44:19.181: E/WindowManager(7581):  at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:561)
07-20 17:44:19.181: E/WindowManager(7581):  at android.os.AsyncTask.execute(AsyncTask.java:511)
07-20 17:44:19.181: E/WindowManager(7581):  at com.wajumbie.nasadailyimage.NasaDailyImage.onRefresh(NasaDailyImage.java:57)
07-20 17:44:19.181: E/WindowManager(7581):  at com.wajumbie.nasadailyimage.NasaAppActivity$1.run(NasaAppActivity.java:48)
07-20 17:44:19.181: E/WindowManager(7581):  at com.wajumbie.nasadailyimage.NasaAppActivity.onRefreshClicked(NasaAppActivity.java:51)
07-20 17:44:19.181: E/WindowManager(7581):  at java.lang.reflect.Method.invokeNative(Native Method)
07-20 17:44:19.181: E/WindowManager(7581):  at java.lang.reflect.Method.invoke(Method.java:511)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.View$1.onClick(View.java:3066)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.View.performClick(View.java:3538)
07-20 17:44:19.181: E/WindowManager(7581):  at android.view.View$PerformClick.run(View.java:14330)
07-20 17:44:19.181: E/WindowManager(7581):  at android.os.Handler.handleCallback(Handler.java:607)
07-20 17:44:19.181: E/WindowManager(7581):  at android.os.Handler.dispatchMessage(Handler.java:92)
07-20 17:44:19.181: E/WindowManager(7581):  at android.os.Looper.loop(Looper.java:156)
07-20 17:44:19.181: E/WindowManager(7581):  at android.app.ActivityThread.main(ActivityThread.java:5008)
07-20 17:44:19.181: E/WindowManager(7581):  at java.lang.reflect.Method.invokeNative(Native Method)
07-20 17:44:19.181: E/WindowManager(7581):  at java.lang.reflect.Method.invoke(Method.java:511)
07-20 17:44:19.181: E/WindowManager(7581):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
07-20 17:44:19.181: E/WindowManager(7581):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
07-20 17:44:19.181: E/WindowManager(7581):  at dalvik.system.NativeStart.main(Native Method)

2 个答案:

答案 0 :(得分:3)

如果图像非常大,则需要调整图像大小。

请执行以下操作:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new URL(imageUrl).openStream(),null,options);
//use your required height and width in place of 80 (size of imageview maybe)
options.inSampleSize = calculateInSampleSize(options,80, 80); 
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeStream(new URL(imageUrl).openStream(),null,options);


public int calculateInSampleSize(BitmapFactory.Options options,
        int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float) height / (float) reqHeight);
        } else {
            inSampleSize = Math.round((float) width / (float) reqWidth);
        }
    }
    return inSampleSize;
}

答案 1 :(得分:0)

我想通了,我只需要在onPreExecute中使用bitmap.recycle()方法。我确信有更好的方法可以做到这一点,但这很有效。

protected void onPreExecute(){
    if(final_image!=null){

      final_image.recycle();

    }

     dialog=ProgressDialog.show(parent, "Loading", "Loading the image of the day");
                }