2013-08-23 20 views
7

Tôi đang sử dụng android:background để cung cấp hình nền cho bố cục Android.
Sau khi đưa một số hình ảnh tôi nhận được ngoại lệ này:
OutOfMemory khi tải Hình nền lớn

08-24 00:40:19.237: E/dalvikvm-heap(8533): Out of memory on a 36000016-byte allocation. 


làm thế nào tôi có thể sử dụng hình ảnh lớn làm nền trên android?
tôi có thể mở rộng bộ nhớ heap ứng dụng không? hoặc là điều gì đó không tốt để làm?

+3

Như được đề cập trong nhiều câu hỏi này, không sử dụng hình nền lớn (> 30MB trong trường hợp của bạn). – kabuko

+2

Có rất nhiều câu hỏi tương tự như thế này trong StackOverFlow. Tôi đã cố gắng để làm cho một bản tóm tắt của nhiều lựa chọn thay thế để giải quyết này: http://stackoverflow.com/questions/11820266/android-bitmapfactory-decodestream-out-of-memory-with-a-400kb-file-with-2mb- f/16528487 # 16528487 –

+0

ngoài việc không sử dụng một hình ảnh rất lớn, nên xem xét khả năng của các thiết bị, vấn đề thực sự là thiết bị không có khả năng sạc như nền mà hình ảnh khổng lồ. –

Trả lời

7

hãy có một cái nhìn vào câu hỏi có liên quan của tôi:

High resolution Image - OutOfMemoryError

Cố gắng hạn chế tối đa việc sử dụng bộ nhớ của ứng dụng của bạn bằng cách giữ hình nền càng nhỏ càng tốt.

này có thể được thực hiện thông qua:

  • cắt xén hình ảnh để nó phù hợp với màn hình
  • nén hình ảnh tiếp theo (sử dụng ví dụ photoshop) trước khi thậm chí sử dụng nó trong các ứng dụng
  • sử dụng dưới đây phương pháp tải bitmap của bạn
  • tái chế bitmap ngay khi bạn không cần đăng nhập
  • đảm bảo bạn không giữ nhiều bản sao trong bộ nhớ
  • thiết lập các tài liệu tham khảo để null sau khi sử dụng bitmap

Hãy chắc chắn rằng hình ảnh mà bạn thiết lập như là một nền tảng được nạp đúng cách (ví dụ cắt kích thước, ví dụ phù hợp với kích thước màn hình) và phát hành từ bộ nhớ ngay sau khi chúng không còn cần thiết nữa.

Đảm bảo bạn chỉ có một phiên bản Bitmap trong bộ nhớ. Sau khi hiển thị, hãy gọi recycle() và đặt tham chiếu của bạn thành không.

Đây là cách bạn có thể tải hình ảnh của bạn:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
     int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeResource(res, resId, options); 
} 

public static 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) { 

     // Calculate ratios of height and width to requested height and width 
     final int heightRatio = Math.round((float) height/(float) reqHeight); 
     final int widthRatio = Math.round((float) width/(float) reqWidth); 

     // Choose the smallest ratio as inSampleSize value, this will guarantee 
     // a final image with both dimensions larger than or equal to the 
     // requested height and width. 
     inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 
    } 

    return inSampleSize; 
} 

Nhờ Adam Stelmaszczyk cho mảnh đẹp mã này.

+0

Hey, ý của bạn là gì bằng cách đặt tham chiếu thành null sau khi sử dụng bitmap? –

5

Tôi đã gặp phải sự cố tương tự do hình nền trong bố cục. Kích thước bình thường của việc cấp phát bộ nhớ của một hình ảnh phải là chiều cao * chiều rộng * 4 byte (ở chế độ ARGB_8888, chế độ mặc định).

Nếu bạn thấy và phân bổ 30MB khi hiển thị một hoạt động thì phải có một số vấn đề. Kiểm tra xem bạn có đang đặt hình nền trong thư mục có thể kéo hay không. Trong trường hợp đó, hệ thống phải quy mô hình ảnh đó với mật độ cụ thể của màn hình, gây ra chi phí bộ nhớ lớn.

Giải pháp:

  1. Đặt một phiên bản cụ thể của hình ảnh nền trong mỗi thư mục drawable (mdpi, hdpi, xhdpi ...).
  2. Đặt hình nền trong thư mục tài nguyên đặc biệt có tên "drawable-nodpi".Hệ thống sẽ không cố gắng chia tỷ lệ hình ảnh được đặt trong thư mục này vì vậy chỉ có một quy trình streching được thực hiện và bộ nhớ được phân bổ sẽ là dự kiến.

biết thêm thông tin trong answer

Hy vọng điều này sẽ giúp này.

+0

Điều này làm giảm phân bổ bộ nhớ đồ họa của tôi một nửa! Cảm ơn bạn! – Magritte

1

can I expand the application heap memory?

Có, bạn có thể. Chỉ cần đặt android:largeHeap:="true" trong tệp Manifest.xml của bạn.

<application 
     android:name="com.pepperonas.libredrive.App" 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:largeHeap="true" 
     android:label="@string/app_name" 
     android:launchMode="standard"> 
+0

Tính năng này không hoạt động, các ứng dụng vẫn có thể hết bộ nhớ và cũng làm chậm ứng dụng của bạn xuống, với mức lớn. https://developer.android.com/training/articles/memory.html Ngoài ra, kích thước heap lớn không giống nhau trên tất cả các thiết bị và khi chạy trên các thiết bị có RAM giới hạn, kích thước heap lớn có thể chính xác giống như kích thước heap thông thường. Vì vậy, ngay cả khi bạn yêu cầu kích thước heap lớn, bạn nên gọi getMemoryClass() để kiểm tra kích thước heap thông thường và cố gắng luôn ở bên dưới giới hạn đó. – Nickmccomb

+0

Đối với tôi, tính năng này đã giải quyết được vấn đề trong một mảnh bản đồ (hiển thị tới 30k dấu địa lý) ... Và có, rõ ràng, mọi thiết bị đều có RAM giới hạn - vì vậy chúng tôi nên tạo mã tiêu thụ tài nguyên thấp nhất có thể (đôi khi nó tốt hơn để cache dữ liệu, đôi khi nó được khuyến khích hơn để sử dụng cpu). Tại thời điểm này không ai có thể đưa ra một câu trả lời ngắn. Nhưng như tôi đã nói, đoạn mã trên đây đã làm điều đó cho tôi trong một số trường hợp .. vì vậy nó sai khi nói "điều này không làm việc". –

+0

Tôi không đồng ý. Tôi tin rằng một giải pháp không nên làm chậm ứng dụng của bạn và giới thiệu nhiều vấn đề hơn trên đường. Ứng dụng này không hoạt động vì nó đang sử dụng sai bitmap, gây ra lỗi Out Of Memory. "Giải pháp" của bạn sẽ không khắc phục điều này bởi vì, ngay cả khi bitmap dưới kích thước của bộ nhớ có sẵn với bản sửa lỗi của bạn (có thể không), một lần nữa bitmap được giới thiệu chắc chắn sẽ xảy ra, và lỗi OOM vẫn sẽ xảy ra . Đó không phải là một giải pháp. – Nickmccomb

3

tôi đã cùng một vấn đề và cố định nó bằng cách sau:

  1. Tạo một thư mục drawable-nodpi và đưa hình ảnh nền của bạn trong đó.

  2. Sử dụng Picasso để hiển thị những hình ảnh http://square.github.io/picasso/

hiển thị chúng với .fit() và .centerCrop() và Picasso quy mô hình ảnh nếu nó cần phải

ImageView ivLogo = (ImageView) findViewById(R.id.ivLogo); 
Picasso.with(getApplicationContext()) 
    .load(R.drawable.logo) 
    .fit() 
    .centerCrop() 
    .into(ivLogo); 

Nếu bạn làm hết bộ nhớ, Picasso sẽ không hiển thị hình ảnh, thay vì cho bạn một lỗi OOM. Tôi hi vọng cái này giúp được!

Các vấn đề liên quan