加载图像时应用程序崩溃(java.lang.OutOfMemoryError)

时间:2013-11-27 14:44:20

标签: android android-activity imageview out-of-memory android-gallery

我有两项活动。在开始活动中有小图像。点击其中的每一个,然后在ViewPager处使用图库打开其他活动。

当打开图库时,它可以完美地滑动图像而没有任何问题。

但是当我回到开始活动并重新打开图库时,应用程序崩溃了 java.lang.OutOfMemoryError位图大小超过vm预算

我尝试重新调整图片大小,将图片缩小,但没有用。它也崩溃了一会儿。

我认为当Gallery和所有图像的活动没有被销毁时。它有内存泄漏。

对于图库,我使用AndroidTouchGallerylink

这是使用此代码的示例应用:workspace link on GoogleDrive

我的代码。 开始活动

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        ArrayList<String> list_big_images = new ArrayList<String>();
        list_big_images.add("http://www.oa.edu.ua/assets/images/n/2013/small/evropeyska_misiya1_s.jpg");
        list_big_images.add("http://www.oa.edu.ua/assets/images/n/2013/small/evropeyska_misiya2_s.jpg");
        list_big_images.add("http://www.oa.edu.ua/assets/images/n/2013/small/evropeyska_misiya3_s.jpg");

        ArrayList<String> list_big_images_big = new ArrayList<String>();
        list_big_images_big.add("http://www.oa.edu.ua/assets/images/n/2013/big/evropeyska_misiya1_b.jpg");
        list_big_images_big.add("http://www.oa.edu.ua/assets/images/n/2013/big/evropeyska_misiya2_b.jpg");
        list_big_images_big.add("http://www.oa.edu.ua/assets/images/n/2013/big/evropeyska_misiya3_b.jpg");      


         //get Screen size
        int width; //Display width
        int height; //Display height

        if (  Integer.valueOf(android.os.Build.VERSION.SDK_INT) > 13 ) {
               Display display = getWindowManager().getDefaultDisplay();
                  Point size = new Point();
                  display.getSize(size);
                  width = size.x;
                  height = size.y;
        } else {
             Display display = getWindowManager().getDefaultDisplay(); 
             width = display.getWidth();
             height = display.getHeight();
        }

        ImageView[] imageViewArray = new ImageView[list_big_images.size()];
        for (int i = 0; i<list_big_images.size(); i++)  
             try {
                    String url = list_big_images.get(i);
                    //url_img_small.add(text);
                    // Let's create the missing ImageView
                    imageViewArray[i] = new ImageView(MainActivity.this);                               

                    // Now the layout parameters, these are a little tricky at first
                    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width/3, width/3);
                    imageViewArray[i].setScaleType(ImageView.ScaleType.FIT_XY);
                    imageViewArray[i].setId(i + 1); // BELOW id 0 doesn't work
                    imageViewArray[i].setPadding(0, 5, 5, 0);
                    if (i > 0) {
                        if (i % 3 == 0){
                            params.addRule(RelativeLayout.BELOW, imageViewArray[i - 3].getId());
                        }
                        else {
                            params.addRule(RelativeLayout.RIGHT_OF, imageViewArray[i - 1].getId());
                            if (i>2)
                                params.addRule(RelativeLayout.BELOW, imageViewArray[i - 3].getId());
                        };
                    }

                    Drawable drawable = grabImageFromUrl(url);
                    imageViewArray[i].setImageDrawable(drawable);

                    final ArrayList<String> list_big_images_big2 = list_big_images_big;
                    final int pos = i;
                    imageViewArray[i].setOnClickListener( new OnClickListener()

                        {
                            @Override
                            public void onClick(View v) {
                                System.out.println(v.getId());
                                Intent intent = new Intent(v.getContext(), Full_Image_Activity.class);
                                intent.putExtra("ArrayImgBig", list_big_images_big2);
                                intent.putExtra("pos", pos+1);
                                startActivityForResult(intent, 0);

                            }
                        });

                    // Let's get the root layout and add our ImageView
                    RelativeLayout layout = (RelativeLayout) findViewById(R.id.moreImages);
                    layout.addView(imageViewArray[i], params);
                }
                catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }   
        }

    //load Image from Url
    private Drawable grabImageFromUrl(String url) throws Exception {
        return Drawable.createFromStream(
                (InputStream) new URL(url).getContent(), "src");
    }


}

它与画廊的活动

public class Full_Image_Activity extends Activity {

    ArrayList <String> ArrayImgBig = null;
    int id_news;
    private GalleryViewPager mViewPager;
    int pos ; //Picture Position
    UrlPagerAdapter pagerAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_full__image);

        ArrayImgBig = getIntent().getExtras().getStringArrayList("ArrayImgBig");
        pos = getIntent().getExtras().getInt("pos");

        UrlPagerAdapter pagerAdapter = new UrlPagerAdapter(Full_Image_Activity.this, ArrayImgBig);
        pagerAdapter.setOnItemChangeListener(new OnItemChangeListener()
        {
            @Override
            public void onItemChange(int currentPosition)
            {
                Toast.makeText(Full_Image_Activity.this, "Current item is " + currentPosition, Toast.LENGTH_SHORT).show();
            }


        });

        mViewPager = (GalleryViewPager)findViewById(R.id.viewer);
        mViewPager.setOffscreenPageLimit(3);
        mViewPager.setAdapter(pagerAdapter);
        mViewPager.setCurrentItem(pos);  
    }


    @Override
    public void onBackPressed() {
        this.finish();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        pagerAdapter = null;
        mViewPager = null;
        System.gc();
    }
} 

我使用方法onDestoy。但它没有帮助。一切都是一样的。

日志:

11-27 15:39:59.239: I/System.out(471): 1
11-27 15:40:00.248: D/dalvikvm(471): GC_EXTERNAL_ALLOC freed 1638K, 48% free 4736K/9031K, external 15372K/16229K, paused 116ms
11-27 15:40:00.879: D/dalvikvm(471): GC_EXTERNAL_ALLOC freed 35K, 48% free 4742K/9031K, external 17773K/18518K, paused 100ms
11-27 15:40:02.519: I/dalvikvm(471): Jit: resizing JitTable from 2048 to 4096
11-27 15:40:04.959: W/KeyCharacterMap(471): No keyboard for id 0
11-27 15:40:04.959: W/KeyCharacterMap(471): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
11-27 15:40:05.159: D/dalvikvm(471): GC_EXPLICIT freed 155K, 49% free 4654K/9031K, external 20410K/21124K, paused 111ms
11-27 15:40:05.738: D/dalvikvm(471): GC_EXPLICIT freed 3K, 49% free 4652K/9031K, external 20410K/21124K, paused 223ms
11-27 15:40:10.703: I/System.out(471): 2
11-27 15:40:11.748: D/dalvikvm(471): GC_EXTERNAL_ALLOC freed 43K, 48% free 4754K/9031K, external 20410K/21124K, paused 106ms
11-27 15:40:11.998: D/dalvikvm(471): GC_EXTERNAL_ALLOC freed 4K, 48% free 4780K/9031K, external 23046K/23760K, paused 112ms
11-27 15:40:12.048: E/dalvikvm-heap(471): 1334000-byte external allocation too large for this process.
11-27 15:40:12.208: E/GraphicsJNI(471): VM won't let us allocate 1334000 bytes
11-27 15:40:12.208: D/dalvikvm(471): GC_FOR_MALLOC freed 0K, 48% free 4780K/9031K, external 23046K/23760K, paused 87ms
11-27 15:40:12.229: D/skia(471): --- decoder->decode returned false
11-27 15:40:12.238: W/dalvikvm(471): threadid=23: thread exiting with uncaught exception (group=0x40015560)
11-27 15:40:12.248: E/AndroidRuntime(471): FATAL EXCEPTION: AsyncTask #5
11-27 15:40:12.248: E/AndroidRuntime(471): java.lang.RuntimeException: An error occured while executing doInBackground()
11-27 15:40:12.248: E/AndroidRuntime(471):  at android.os.AsyncTask$3.done(AsyncTask.java:200)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.FutureTask.run(FutureTask.java:138)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.lang.Thread.run(Thread.java:1019)
11-27 15:40:12.248: E/AndroidRuntime(471): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
11-27 15:40:12.248: E/AndroidRuntime(471):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
11-27 15:40:12.248: E/AndroidRuntime(471):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
11-27 15:40:12.248: E/AndroidRuntime(471):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:525)
11-27 15:40:12.248: E/AndroidRuntime(471):  at ru.truba.touchgallery.TouchView.UrlTouchImageView$ImageLoadTask.doInBackground(UrlTouchImageView.java:102)
11-27 15:40:12.248: E/AndroidRuntime(471):  at ru.truba.touchgallery.TouchView.UrlTouchImageView$ImageLoadTask.doInBackground(UrlTouchImageView.java:1)
11-27 15:40:12.248: E/AndroidRuntime(471):  at android.os.AsyncTask$2.call(AsyncTask.java:185)
11-27 15:40:12.248: E/AndroidRuntime(471):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
11-27 15:40:12.248: E/AndroidRuntime(471):  ... 4 more

2 个答案:

答案 0 :(得分:0)

将您的onDestroy编辑为以下内容:

 @Override
public void onDestroy() {
    pagerAdapter = null;
    mViewPager = null;
    System.gc();
    super.onDestroy();
}

或将代码放入onPause()

答案 1 :(得分:0)

您可以在viewpager适配器中检查是否覆盖了destroyItem。这将在屏幕上不再显示时删除视图,从而释放为该图像分配的内存。

示例:

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

我还建议你使用像Picasso或通用图像加载器这样的图像加载器来异步加载ui线程的图像,并为你处理它们在内存中的分配,这样你就不会出现内存异常...