在 DialogFragment 的 ImageView 上使用 setImageResource() 时如何减少内存消耗?

How to reduce memory consumption when using setImageResource() on an ImageView in a DialogFragment?

据我所见,内存使用量可能减半,但这似乎还不够。我的案例与引用的案例一样,涉及将可绘制对象加载到 ImageView 中。每个可绘制对象小于 20kb,但使用约 15mb 的内存来加载。为什么会占用这么多内存?如何将内存消耗减少一半以上?或者,我应该将对话框放在它自己的 activity 而不是片段中吗?

对话框片段Class

public class CollectableDialogFragment extends DialogFragment {
    public static final String LOG_TAG = CollectableDialogFragment.class.getSimpleName();
    /*Constants for setting Bundle keys that will be passed to this fragment*/
    public static final String SQLITE_DATA = "sqliteData";
    public static final String FIREBASE_DATA = VideoGame.KEY_UNIQUE_NODE_ID;
    private Context context;
    /*Object containing video game's data*/
    private VideoGame videoGame;
    /*Instantiated views*/
    private View view;
    private ImageView usaFlag;
    private ImageView japanFlag;
    private ImageView euFlag;
    private ImageView game;
    private ImageView manual;
    private ImageView box;
    private CustomEditText noteEditText;

    /*Initialize contentProviderBundle and componentsOwned, and handle clicking*/
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.i(LOG_TAG, "Entered DialogFragment!");
        if (getArguments() != null) {
            /*Handles adding new item to collection*/
            if (getArguments().containsKey(SQLITE_DATA)) {
                /*Extract Hashmap containing video game's data*/
                HashMap<String, String> contentProviderBundle = (HashMap<String, String>) getArguments().getSerializable(SQLITE_DATA);
                /*Set VideoGame's values*/
                videoGame = new VideoGame(contentProviderBundle.get(VideoGame.KEY_UNIQUE_ID),
                        contentProviderBundle.get(VideoGame.KEY_CONSOLE),
                        contentProviderBundle.get(VideoGame.KEY_TITLE),
                        contentProviderBundle.get(VideoGame.KEY_LICENSEE),
                        contentProviderBundle.get(VideoGame.KEY_RELEASED),
                        Integer.valueOf(contentProviderBundle.get(VideoGame.KEY_COPIES_OWNED)));
                /*Express user has not indicated ownership of any components*/
                videoGame.setValueGame(false);
                videoGame.setValueManual(false);
                videoGame.setValueBox(false);
            } else if (getArguments().containsKey(FIREBASE_DATA)) {
                /*Handles editing a collected item*/
                videoGame = new VideoGame();

                for (String key : getArguments().keySet()) {
                    if (key == VideoGame.KEY_COMPONENTS_OWNED) {
                        /*Extract serialized HashMap*/
                        videoGame.setValuesComponentsOwned((HashMap<String, Boolean>) getArguments().getSerializable(VideoGame.KEY_COMPONENTS_OWNED));
                    }
                    switch (key) {
                        case VideoGame.KEY_UNIQUE_NODE_ID:
                            videoGame.setValueUniqueNodeId(getArguments().getString(VideoGame.KEY_UNIQUE_NODE_ID));
                            break;
                        case VideoGame.KEY_CONSOLE:
                            videoGame.setValueConsole(getArguments().getString(VideoGame.KEY_CONSOLE));
                            break;
                        case VideoGame.KEY_TITLE:
                            videoGame.setValueTitle(getArguments().getString(VideoGame.KEY_TITLE));
                            break;
                        case VideoGame.KEY_REGION_LOCK:
                            videoGame.setValueRegionLock(getArguments().getString(VideoGame.KEY_REGION_LOCK));
                            break;
                        case VideoGame.KEY_NOTE:
                            videoGame.setValueNote(getArguments().getString(VideoGame.KEY_NOTE));
                            break;
                        default:
                            Log.i(LOG_TAG, "Case 'default' is running");
                            break;
                    }
                }
            }
        }



    }

    /*Inflate the layout to use as dialog or embedded fragment*/
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.activity_collectable_dialog, container, false);

        /*Set string for Toolbar's title*/
        String toolbarTitle = setToolbarTitle();
        /*Find Toolbar*/
        Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
        /*Sets toolbar as ActionBar*/
        ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
        /*Set toolbar's title*/
        toolbar.setTitle(toolbarTitle);
        /*Enable home button and supply a custom icon*/
        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
        if (actionBar != null) {
            /*Show custom drawable for up icon*/
            actionBar.setHomeAsUpIndicator(R.drawable.ic_clear_black_24dp);
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        /*Initialize views*/
        noteEditText = (CustomEditText) view.findViewById(R.id.activity_collectable_customedittext_notes);
        handleButtons(container);

        /*Populate views if possible*/
        if (videoGame.getValueRegionLock() != null) {
            clickRegionLock(videoGame.getValueRegionLock());
        }
        if (videoGame.getValueNote() != null && videoGame.getValueNote() != "") {
            populateNote(videoGame.getValueNote());
        }
        int componentsClicked = clickComponentsOwned();
        Log.i(LOG_TAG, componentsClicked + " componenets were clicked");

        /*Report that this fragment would like to participate in populating the options menu by
        receiving a call to onCreateOptionsMenu(Menu, MenuInflater) and related methods.*/
        setHasOptionsMenu(true);

        return view;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        /*Causes dialog to cover whole screen*/
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        return dialog;
    }

    /*Inflates activity_collectable_dialog_menu as the actionbar*/
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.activity_collectable_dialog_menu, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        switch (id) {
            case R.id.activity_collectable_dialog_action_save:
                if (videoGame.getValueUniqueNodeId() == null) {
                    setDate();
                    setNote();
                    videoGame.createNode();
                /*Updated number of copes owned*/
                    int updatedCopies = videoGame.getValueCopiesOwned() + 1;
                /*Key value pair used for updating database*/
                    ContentValues sqliteUpdate = new ContentValues();
                    sqliteUpdate.put(VideoGamesEntry.COLUMN_COPIES_OWNED, String.valueOf(updatedCopies));
                /*Update SQLite database*/
                    int rowsUpdate = getContext().getContentResolver().update(VideoGamesEntry.CONTENT_URI, sqliteUpdate,
                            VideoGamesEntry.COLUMN_UNIQUE_ID + "=" + videoGame.getValueUniqueID(),
                            null);

                    Log.i(LOG_TAG, "Rows updated: " + rowsUpdate);
                } else {
                    setNote();
                    videoGame.updateNode();
                    dismiss();
                    break;
                }

            case android.R.id.home:
//                Make sure to confirm discard of data if data was input
                dismiss();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    /*Head method for handling the dialog's buttons*/
    private void handleButtons(ViewGroup container) {
        /*Initialization of every ImageView on activty_add_collectable_dialog.xml for programmatic use*/
        usaFlag = (ImageView) view.findViewById(R.id.activity_collectable_image_usa);
        japanFlag = (ImageView) view.findViewById(R.id.activity_collectable_image_japan);
        euFlag = (ImageView) view.findViewById(R.id.activity_collectable_image_european_union);
        game = (ImageView) view.findViewById(R.id.activity_collectable_image_game);
        manual = (ImageView) view.findViewById(R.id.activity_collectable_image_manual);
        box = (ImageView) view.findViewById(R.id.activity_collectable_image_box);

        setImageResources();

        /*ArrayList of all icons*/
        ArrayList<ImageView> imageViews = new ArrayList<>();
        imageViews.add(usaFlag);
        imageViews.add(japanFlag);
        imageViews.add(euFlag);
        imageViews.add(game);
        imageViews.add(manual);
        imageViews.add(box);

        setButtonTintInactive(imageViews);

        setRegionLock(usaFlag, japanFlag, euFlag);

        setCartridgeIcon();

        setComponentsOwned(game, manual, box);

    }

    /*Set image resource for all ImageViews except R.id.activity_collectable_image_game*/
    private void setImageResources() {
        usaFlag.setImageResource(R.drawable.flag_usa);
        japanFlag.setImageResource(R.drawable.flag_japan);
        euFlag.setImageResource(R.drawable.flag_european_union);
        manual.setImageResource(R.drawable.video_game_manual_icon);
        box.setImageResource(R.drawable.box_icon);
    }

对话框布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorDarkBackground"
    android:paddingBottom="16dp">

    <include
        android:id="@+id/activity_collectable_dialog_toolbar"
        layout="@layout/toolbar_actionbar" />

    <com.example.android.gamecollector.customviews.CustomTextView
        android:id="@+id/activity_collectable_text_region_lock"
        xmlns:roboto="http://schemas.android.com/apk/com.example.customviews.CustomTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/activity_collectable_dialog_toolbar"
        android:layout_marginLeft="24dp"
        android:text="@string/region_lock"
        android:textSize="16sp"
        android:textColor="@color/colorDarkPrimaryText"
        roboto:typeface="roboto_bold.ttf" />

    <ImageView
        android:id="@+id/activity_collectable_image_usa"
        android:layout_width="30dp"
        android:layout_height="24dp"
        android:layout_below="@id/activity_collectable_text_region_lock"
        android:layout_marginTop="36dp"
        android:layout_marginLeft="40dp"
        android:tint="@color/colorInactiveIcon" />

    <ImageView
        android:id="@+id/activity_collectable_image_japan"
        android:layout_width="36dp"
        android:layout_height="24dp"
        android:layout_below="@id/activity_collectable_text_region_lock"
        android:layout_toRightOf="@id/activity_collectable_image_usa"
        android:layout_marginTop="36dp"
        android:layout_marginLeft="36dp"
        android:tint="@color/colorInactiveIcon" />

    <ImageView
        android:id="@+id/activity_collectable_image_european_union"
        android:layout_width="33dp"
        android:layout_height="24dp"
        android:layout_below="@id/activity_collectable_text_region_lock"
        android:layout_toRightOf="@id/activity_collectable_image_japan"
        android:layout_marginTop="36dp"
        android:layout_marginLeft="36dp"
        android:tint="@color/colorInactiveIcon" />

    <View
        android:id="@+id/activity_collectable_divider_1"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@id/activity_collectable_image_usa"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        android:layout_marginRight="24dp"
        android:layout_marginLeft="24dp"
        android:background="@color/colorDarkDividers"/>

    <com.example.android.gamecollector.customviews.CustomTextView
        android:id="@+id/activity_collectable_text_components_owned"
        xmlns:roboto="http://schemas.android.com/apk/com.example.customviews.CustomTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/activity_collectable_divider_1"
        android:layout_marginBottom="24dp"
        android:layout_marginLeft="24dp"
        android:text="@string/components_owned"
        android:textSize="16sp"
        android:textColor="@color/colorDarkPrimaryText"
        roboto:typeface="roboto_bold.ttf" />

    <!--Cartridge icon will be programmatically chosen-->
    <ImageView
        android:id="@+id/activity_collectable_image_game"
        android:layout_width="36dp"
        android:layout_height="24dp"
        android:layout_marginLeft="40dp"
        android:layout_below="@id/activity_collectable_text_components_owned"
        android:tint="@color/colorInactiveIcon"
        tools:src="@drawable/gameboy_cartridge_icon"/>

    <ImageView
        android:id="@+id/activity_collectable_image_manual"
        android:layout_width="22dp"
        android:layout_height="24dp"
        android:layout_marginLeft="36dp"
        android:layout_below="@id/activity_collectable_text_components_owned"
        android:layout_toRightOf="@id/activity_collectable_image_game"
        android:tint="@color/colorInactiveIcon"/>

    <ImageView
        android:id="@+id/activity_collectable_image_box"
        android:layout_width="23dp"
        android:layout_height="24dp"
        android:layout_marginLeft="36dp"
        android:layout_below="@id/activity_collectable_text_components_owned"
        android:layout_toRightOf="@id/activity_collectable_image_manual"
        android:tint="@color/colorInactiveIcon"/>

    <View
        android:id="@+id/activity_collectable_divider_2"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@id/activity_collectable_image_game"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        android:layout_marginRight="24dp"
        android:layout_marginLeft="24dp"
        android:background="@color/colorDarkDividers"/>

    <com.example.android.gamecollector.customviews.CustomTextView
        android:id="@+id/activity_collectable_text_notes"
        xmlns:roboto="http://schemas.android.com/apk/com.example.customviews.CustomTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/activity_collectable_divider_2"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="24dp"
        android:text="@string/notes"
        android:textSize="16sp"
        android:textColor="@color/colorDarkPrimaryText"
        roboto:typeface="roboto_bold.ttf" />

    <!--Make sure hint and typed text have appropriate typeface, weight, size, and color-->
    <com.example.android.gamecollector.customviews.CustomEditText
        android:id="@+id/activity_collectable_customedittext_notes"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/activity_collectable_text_notes"
        android:layout_marginRight="24dp"
        android:layout_marginLeft="40dp"
        android:hint="@string/notes_hint"/>
</RelativeLayout>

根据屏幕尺寸缩放可绘制对象并将它们放入 drawable-hdpi drawable-mdpi drawable-xhdpi 等文件夹中。你可以使用这个 source。检查 memmory allocation tracking 这些方法。 setImageResource 每张图片最多需要 0.5 MB 的内存。在默认 setImageResource.

之后以编程方式为 ImageViews 添加 tints