Android内存分配如何与ImageView一起使用?

时间:2012-01-06 18:30:03

标签: android memory-management

我从服务器加载大约20张大小为50-70K的图片,然后在ListView中显示。最初我将数据存储为Bitmap,导致内存快速耗尽。然后我决定压缩所有这些位图文件并存储在内容提供程序Media中。因此,在我的适配器中,用户数据仅包含图像文件的Uri

然而它根本没有解决问题,它运行时间稍长,但在加载约10张图片后仍然崩溃。这是编译器的错误日志 1048576-byte external allocation too large for this process
VM won't let us allocate 1048576 bytes

我将每个bitmap数据设置为ImageView之后,我甚至会清理它,并删除存储在sdcard

中的所有图像文件
    @Override
    public void onDestroy() {
        // clean up
        for (User user : userList) {
            getContentResolver().delete(user.getImageUri(), null, null);
        }
        super.onDestroy();
    }


    private Uri constructUriFromBitmap(Bitmap bitmap) {
        ContentValues values = new ContentValues(1);
        values.put(Media.MIME_TYPE, "image/jpeg");
        Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
        try {
            OutputStream outStream = getContentResolver().openOutputStream(uri);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
            outStream.close();
        } 
        catch (Exception e) {
            Log.e(TAG, "exception while writing image", e);
        }
        bitmap.recycle();
        return uri;
    }

现在我已经没想完了,我真的不知道在这种情况下会出现什么问题。我想知道是否有人经历过这个问题可能会让我失望?

由于代码很长,我只提取主要功能: 这是我的User class数据:

public class FriendFeed {
    // required parameters
    private final int activityId; // in case we want to handle the detail of
                                    // this activity
    private final int friendId;
    private final String friendName;
    private final Challenge.Type challengeType;
    private final String activityTime;
    private final String placeName;

    // optional parameter
    private String challengeName;
    private String challengeDescription;
    private Uri activitySnapPictureUri = null;
    private Uri friendPictureUri = null;
    private String activityComment;

这是我的主要功能:

@Override
protected Boolean doInBackground(Void...voids) {
            JSONArray array = JsonHelper.getJsonArrayFromUrlWithData(GET_FRIEND_FEED_URL, datas);
            if (array != null) { 
                try {
                    for (int i = 0; i < array.length(); ++i) { 
                        Uri snapPictureUri = null;
                        Uri userPictureUri = null;

                        if (Challenge.returnType(array.getJSONObject(i).getString("challenges_tbl_type")) == Challenge.Type.SNAP_PICTURE) {
                            snapPictureUri = constructUriFromBitmap(ImageHelper.downloadImage(array.getJSONObject(i).getString("activity_tbl_snap_picture_url")));
                        }

                        if(ImageHelper.downloadImage(array.getJSONObject(i).getString("users_tbl_user_image_url")) != null) {
                            userPictureUri = constructUriFromBitmap(ImageHelper.downloadImage(array.getJSONObject(i).getString("users_tbl_user_image_url")));
                        }

                        publishProgress(
                            new FriendFeed.Builder(
                                    // required parameters
                                    array.getJSONObject(i).getInt("activity_tbl_id"),
                                    array.getJSONObject(i).getInt("friends_tbl_friend_id"),
                                    array.getJSONObject(i).getString("users_tbl_username"),
                                    Challenge.returnType(array.getJSONObject(i).getString("challenges_tbl_type")),
                                    array.getJSONObject(i).getString("activity_tbl_created"),
                                    array.getJSONObject(i).getString("spots_tbl_name"))
                                        // optional parameters
                                        .challengeName(array.getJSONObject(i).getString("challenges_tbl_name"))
                                        .challengeDescription(array.getJSONObject(i).getString("challenges_tbl_description"))
                                        .activitySnapPictureUri(snapPictureUri)
                                        .friendPictureUri(userPictureUri)
                                        .activityComment(array.getJSONObject(i).getString("activity_tbl_comment"))
                                            .build());
                    }
                }
                catch (JSONException e) {
                    Log.e(TAG + "GetFriendFeedTask.doInBackGround(Void ...voids) : ", "JSON error parsing data" + e.toString());
                }
                return true;
            }
            else {
                return false;
            }
        }

1 个答案:

答案 0 :(得分:1)

Android强制执行每个进程的内存分配限制为24MB,因此您无法分配更多内容。但是,每张70K的20张照片应该只有1.4MB ...所以我的猜测:

  1. 也许您在应用的其他部分分配了位图,因此此ListView上的位图可用的内容少于1.4MB。

  2. 某处内存泄漏

  3. 如果你确定你确实需要你正在使用的所有位图,你确定你需要这么大的位图还是有这么大的分辨率?减少它们可以提供帮助。

  4. 如果所有其他方法都失败并且您确实需要大量内存中的位图,则可以始终使用OpenGL纹理。