我必须在图库中获取图像的图像路径,以便将其保存为列表,不幸的是,如果所选图像太大,以下代码会使应用程序崩溃(并且我的try catch块中的警报未被查看) 。
private void openImage() {
try{
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("image/*");
startActivityForResult(i, FILE_REQ_CODE);
} catch (RuntimeException e) {
e.printStackTrace();
Alerts.TooLargeImage(LoadImage.this);
}
}
protected void onActivityResult(int requestCode, int resultCode,
Intent intentData) {
try{
Uri tmp = intentData.getData();
String path = tmp.toString();
imagePathList.add(path);
preview.setImageURI(tmp);
FileArchiveManager.saveImagePath(imagePathList);
super.onActivityResult(requestCode, resultCode, intentData);
} catch (RuntimeException e) {
e.printStackTrace();
Alerts.TooLargeImage(LoadImage.this);
}
}
错误日志
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=8135KB, Allocated=3718KB, Bitmap Size=11707KB)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:694)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:494)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
at android.widget.ImageView.resolveUri(ImageView.java:592)
at android.widget.ImageView.setImageURI(ImageView.java:313)
at com.myapp.LoadImage.onActivityResult(LoadImage.java:131)
at android.app.Activity.dispatchActivityResult(Activity.java:4108)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3016)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3072)
at android.app.ActivityThread.access$2000(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1084)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:4385)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
at dalvik.system.NativeStart.main(Native Method)
如何解决此问题?
答案 0 :(得分:1)
来自http://developer.android.com/training/displaying-bitmaps/load-bitmap.html:
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);
}
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
使用BitmapFactory.decodeResource()
和BitmapFactory.Options.inSampleSize
将允许您将位图的缩减采样版本加载到RAM中(因为您实际上不需要显示如此大的图像)而不会导致java.lang.OutofMemoryError
答案 1 :(得分:0)
如果您使用的是android 3.0及更高版本,请在清单文件中的应用程序标记内使用波纹管代码
应用 android:largeHeap =“ true”
答案 2 :(得分:0)
我也遇到了同样的问题,我只是使用了 Glide 。我需要从任何1:1比例的图像代码中输出640x640图像:
class AlarmAudioService : Service() {
private var mediaPlayer: MediaPlayer? = null
private val completedTimers = mutableListOf<String>()
private val runningTimers = mutableListOf<String>()
private var notificationController: NotificationController? = null
enum class SERVICE_ACTION {
START,
ADD_RUNNING_TIMER,
REMOVE_RUNNING_TIMER,
TIMER_COMPLETE,
TIMERS_IN_FOCUS,
STOP
}
companion object {
private var isServiceRunning: Boolean = false
fun startService(context: Context) {
if (isServiceRunning) return
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.START)
ContextCompat.startForegroundService(context, intent)
}
fun addRunningTimer(context: Context, timerTitle: String) {
if (!isServiceRunning) return
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.ADD_RUNNING_TIMER)
val paramTitleKey = context.getString(R.string.notifications_parameter_title_key)
intent.putExtra(paramTitleKey, timerTitle)
ContextCompat.startForegroundService(context, intent)
}
fun removeRunningTimer(context: Context, timerTitle: String) {
if (!isServiceRunning) return
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.REMOVE_RUNNING_TIMER)
val paramTitleKey = context.getString(R.string.notifications_parameter_title_key)
intent.putExtra(paramTitleKey, timerTitle)
ContextCompat.startForegroundService(context, intent)
}
fun timerComplete(context: Context, timerTitle: String) {
if (!isServiceRunning) return
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.TIMER_COMPLETE)
val paramTitleKey = context.getString(R.string.notifications_parameter_title_key)
intent.putExtra(paramTitleKey, timerTitle)
ContextCompat.startForegroundService(context, intent)
}
fun timersInFocus(context: Context) {
if (!isServiceRunning) return
// This is called when we got the user attention, we can assume they know of completed timers and we can stop the alarm sound
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.TIMERS_IN_FOCUS)
ContextCompat.startForegroundService(context, intent)
}
fun stopService(context: Context) {
if (!isServiceRunning) return
val intent = createAlarmAudioServiceIntent(context, SERVICE_ACTION.STOP)
ContextCompat.startForegroundService(context, intent)
}
private fun createAlarmAudioServiceIntent(context: Context, action: SERVICE_ACTION): Intent {
val intent = Intent(context, AlarmAudioService::class.java)
intent.putExtra("action", action)
return intent
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val action = intent?.getSerializableExtra("action") as SERVICE_ACTION
when (action) {
SERVICE_ACTION.START -> start()
SERVICE_ACTION.ADD_RUNNING_TIMER -> addRunningTimer(intent)
SERVICE_ACTION.REMOVE_RUNNING_TIMER -> removeRunningTimer(intent)
SERVICE_ACTION.TIMER_COMPLETE -> timerComplete(intent)
SERVICE_ACTION.TIMERS_IN_FOCUS -> timersInFocus()
SERVICE_ACTION.STOP -> stop()
}
return START_STICKY
}
//#region Service Actions
private fun start() {
if (isServiceRunning) {
return
}
isServiceRunning = true
InitNotificationController()
updateNotificationDescription()
InitMediaPlayer()
}
private fun addRunningTimer(intent: Intent) {
val paramTitleKey = getString(R.string.notifications_parameter_title_key)
val timerTitle = intent.getStringExtra(paramTitleKey) ?: ""
if (timerTitle.isNotEmpty()) {
runningTimers.add(timerTitle)
}
}
private fun removeRunningTimer(intent: Intent) {
val paramTitleKey = getString(R.string.notifications_parameter_title_key)
val timerTitle = intent.getStringExtra(paramTitleKey) ?: ""
if (timerTitle.isNotEmpty()) {
runningTimers.remove(timerTitle)
}
}
private fun timerComplete(intent: Intent) {
val paramTitleKey = getString(R.string.notifications_parameter_title_key)
val timerTitle = intent.getStringExtra(paramTitleKey) ?: ""
if (timerTitle.isNotEmpty()) {
completedTimers.add(timerTitle)
runningTimers.removeAll{ it == timerTitle }
}
StartSound()
updateNotificationDescription()
}
private fun timersInFocus() {
StopSound()
completedTimers.clear()
updateNotificationDescription()
}
private fun stop() {
if (runningTimers.count() > 0) {
return
}
isServiceRunning = false
runningTimers.clear()
completedTimers.clear()
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
notificationController?.CancelNotification(1)
notificationController = null
stopSelf()
}
//#endregion
private fun InitMediaPlayer() {
if (mediaPlayer == null) {
val attr = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ALARM)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
.build()
mediaPlayer = MediaPlayer.create(this, R.raw.alarm_sound, attr, 0)
mediaPlayer?.isLooping = true
}
}
private fun InitNotificationController() {
if (notificationController == null) {
notificationController = NotificationController(this)
}
}
override fun onBind(intent: Intent): IBinder? {
return null
}
private fun StartSound() {
// Only start media player if not playing
if (mediaPlayer?.isPlaying == false) {
mediaPlayer?.start()
}
}
private fun StopSound() {
if (mediaPlayer?.isPlaying == true) {
mediaPlayer?.pause()
}
}
private fun createNotificationDescription(): String {
return when {
completedTimers.count() > 1 -> {
"Multiple timers are completed."
}
completedTimers.count() == 1 -> {
"${completedTimers.first()} is completed."
}
else -> {
"You will be notified when a timer is complete."
}
}
}
private fun updateNotificationDescription() {
if (!isServiceRunning) {
return
}
val description = createNotificationDescription()
// Oreo API 26+ requires a foreground notification for a service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notification = notificationController?.CreateForegroundNotification(description)
startForeground(1, notification)
} else {
val notification = notificationController?.CreateForegroundNotification(description)
startForeground(1, notification)
}
}
}
使用最大40mb的图像文件进行测试