Как исправить утечку памяти для представления, созданного и добавляемого динамически, путем удаления всех представлений? - PullRequest
1 голос
/ 26 мая 2020

У меня есть собственный класс для динамического создания просмотра с помощью моего метода generate () , но когда я вызываю метод fini sh () в своей деятельности g c не работает, а память до 10 МБ для каждого вызова активности (с использованием проверки в Profiler), мне нужно исправить это с помощью ручного удаления представления из памяти с помощью g c , я знаю g c делать это, когда у меня нет сильной ссылки на мои представления, и я следовал этим правилам и сохранял все свои представления в коллекцию как WeakHashMap но g c не освобождает для моих представлений:

public class CustomQuestionAdapter {

    public ArrayList<Question> items;
    private Context mActivity;
    private boolean isDisabled = false;
    private String TAG = "CUSTOM_QUESTION_ADAPTER";
    private OnProgressViewChanged onProgressViewChanged;
    private WeakHashMap<String, View> boxReferences = new WeakHashMap<>();

    private SparseArray<EditTextPlus> textViewsReferences = new SparseArray<>();

    public CustomQuestionAdapter(Context context) {
        this.mActivity = context;
    }

    public void setItems(ArrayList<Question> items) {
        this.items = items;
    }


    public void generate(int index) {

        int total = items.size();

        generateBoxes(index);

        this.onProgressViewChanged.onChanged((int) ((index * 1.0 / total) * 100));
        if ( index < total - 1){
            this.onProgressViewChanged.onFinish(boxReferences.get(items.get(index).getQId().toString()), false);
        }else{
            this.onProgressViewChanged.onChanged(100);
            this.onProgressViewChanged.onFinish(boxReferences.get(items.get(index).getQId().toString()), true);
        }


    }

    public void removeAllView(ViewGroup v){
        for (View view: boxReferences.values()){
            try{
                view.setVisibility(View.VISIBLE);
                ((ViewGroup) view).removeAllViews();
                Log.d(TAG, "removeAllView: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ removed ");
            }catch (Exception e){
                Log.d(TAG, "removeAllView: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ occured error" );
            }

        }
        if (v != null){
            v.removeAllViews();
        }
        boxReferences = null;
        textViewsReferences = null;
        items.clear();

    }

    public void setDisabled(boolean isDisabled) {
        this.isDisabled = isDisabled;
    }

    @Nullable
    private View generateBoxes(final int position) {

        final Question item = items.get(position);
        final HashMap<String, String> options = item.getOptionsHashMap();
        item.setQText(String.format("(%d) %s", position + 1, item.getQText()));

        if (item.getQType().equals("Text")) {
//            final View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_text, null, false);

            View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_text, null, false);

            try {
                ((TextViewPlus) layoutView.findViewById(R.id.question)).setText(String.format("%s%s", item.getQText(), Boolean.valueOf(options.get("required")) ? " (الزامی)" : ""));
            } catch (Exception e) {
                e.printStackTrace();
            }

            EditTextPlus answerText = layoutView.findViewById(R.id.answer);


            textViewsReferences.put(position, answerText);

            answerText.setText(item.getAnswer());
            if (isDisabled)
                answerText.setEnabled(false);

            layoutView.setVisibility(item.getShouldHide() ? View.GONE : View.VISIBLE);

            boxReferences.put(item.getQId().toString(), layoutView);

            return layoutView;
        } else if (item.getQType().equals("Checkbox")) {


            View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_radio, null, false);
            LinearLayout optionsLayout = layoutView.findViewById(R.id.options);


            try {
                ((TextViewPlus) layoutView.findViewById(R.id.question)).setText(String.format("%s%s", item.getQText(), Boolean.valueOf(options.get("required")) ? " (الزامی)" : ""));
            } catch (Exception e) {
                e.printStackTrace();
            }

//            new Thread(new Runnable() {
//                @Override
//                public void run() {
            optionsLayout.removeAllViews();
            final List<CheckBox> checkBoxes = new ArrayList<>();
            for (int i = 0; i < item.getFields().size(); i++) {
                Field field = item.getFields().get(i);

                View view = LayoutInflater.from(mActivity).inflate(R.layout.template_checkbox, null);

                CheckBox checkBox = view.findViewById(R.id.radio);
                TextViewPlus titleText = view.findViewById(R.id.title);
                if (isDisabled)
                    checkBox.setEnabled(false);

                checkBox.setChecked(item.getAnswer().contains(field.getName() + "|"));
                checkBox.setTag(field.getName());
                titleText.setText(field.getTitle());
                optionsLayout.addView(view);

                checkBoxes.add(checkBox);
                checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                        StringBuilder answer = new StringBuilder();
                        for (CheckBox checkBox1 : checkBoxes) {
                            if (checkBox1.isChecked()) {
                                answer.append(checkBox1.getTag()).append("|");
                            }
                        }
//                            answers.set(position, answer);
                        item.setAnswer(answer.toString());
                    }
                });
            }

//                }
//            }).start();

            boxReferences.put(item.getQId().toString(), layoutView);

            layoutView.setVisibility(item.getShouldHide() ? View.GONE : View.VISIBLE);
            return layoutView;


        } else if (item.getQType().equals("Input")) {
            View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_input, null, false);

            try {
                ((TextViewPlus) layoutView.findViewById(R.id.question)).setText(String.format("%s%s", item.getQText(), Boolean.valueOf(options.get("required")) ? " (الزامی)" : ""));

                EditTextPlus answerText = layoutView.findViewById(R.id.answer);


                switch (options.get("type")) {
                    case "text": {
                        answerText.setInputType(InputType.TYPE_CLASS_TEXT);
                        break;
                    }
                    case "number": {
                        answerText.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
                        break;
                    }
                    case "date": {
                        answerText.setInputType(InputType.TYPE_CLASS_DATETIME);
                        break;
                    }
                }


                textViewsReferences.put(position, answerText);

                answerText.setText(item.getAnswer());
                if (isDisabled)
                    answerText.setEnabled(false);
            } catch (Exception e) {
                e.printStackTrace();
            }


            boxReferences.put(item.getQId().toString(), layoutView);
            layoutView.setVisibility(item.getShouldHide() ? View.GONE : View.VISIBLE);
            return layoutView;
        } else if (item.getQType().equals("Radio Button")) {

            View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_radio_with_group, null, false);
            LinearLayout textGroup = layoutView.findViewById(R.id.textGroup);
            RadioGroup radioGroup = layoutView.findViewById(R.id.radioGroup);

            try {
                ((TextViewPlus) layoutView.findViewById(R.id.question)).setText(String.format("%s%s", item.getQText(), Boolean.valueOf(options.get("required")) ? " (الزامی)" : ""));
            } catch (Exception e) {
                e.printStackTrace();
            }


            textGroup.removeAllViews();
            radioGroup.removeAllViews();



            for (int i = 0; i < item.getFields().size(); i++) {
                final Field field = item.getFields().get(i);


                final RadioButton radioButton = new RadioButton(mActivity);
                radioButton.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 70));
                radioButton.setGravity(Gravity.CENTER);
                radioButton.setChecked(false);
                radioButton.setId(View.generateViewId());


                TextViewPlus titleText = new TextViewPlus(mActivity) {{
                    setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 70) {{
                        rightMargin = 10;
                    }});
                    setEllipsize(TextUtils.TruncateAt.MARQUEE);
                    setFont(mActivity, "fonts/IRANYekanWebLight.ttf");
                    setTextSize(Dimension.SP, 14f);
                    setGravity(Gravity.CENTER | Gravity.RIGHT);

                    setTextColor(mActivity.getResources().getColor(R.color.gray));
                }};

                radioButton.setChecked(item.getAnswer().equals(field.getName()));
                radioButton.setTag(field.getName());
                if (isDisabled) {
                    radioButton.setEnabled(false);
                }

                titleText.setText(field.getTitle());

                textGroup.addView(titleText);
                radioGroup.addView(radioButton);

                radioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                        if (b) {
                            item.setAnswer(field.getName());

//                                items.set(position, item);
                        }
//
                    }
                });
            }
            if (isDisabled) {
                radioGroup.setEnabled(false);
            }
//                }
//            }).start();


            boxReferences.put(item.getQId().toString(), layoutView);
            layoutView.setVisibility(item.getShouldHide() ? View.GONE : View.VISIBLE);
            return layoutView;


        } else if (item.getQType().equals("OPTCheckbox")) {


            View layoutView = LayoutInflater.from(mActivity).inflate(R.layout.adapter_question_radio, null, false);
            LinearLayout optionsLayout = layoutView.findViewById(R.id.options);



//            new Thread(new Runnable() {
//                @Override
//                public void run() {

            try {
                ((TextViewPlus) layoutView.findViewById(R.id.question)).setText(String.format("%s%s", item.getQText(), Boolean.valueOf(options.get("required")) ? " (الزامی)" : ""));
            } catch (Exception e) {
                e.printStackTrace();
            }


            optionsLayout.removeAllViews();


            Field field = item.getFields().get(0);

            View view = LayoutInflater.from(mActivity).inflate(R.layout.template_checkbox, null);

            final CheckBox checkBox = view.findViewById(R.id.radio);
            TextViewPlus titleText = view.findViewById(R.id.title);
            if (isDisabled)
                checkBox.setEnabled(false);

            Log.e("~~~~~~~", item.getAnswer());
            if (item.getAnswer().contains(field.getName() + "|")) {
                checkBox.setChecked(true);
            } else {
                checkBox.setChecked(false);
            }


            checkBox.setTag(field.getName());
            checkBox.setId((int) 123);
            titleText.setText(field.getTitle());
            optionsLayout.addView(view);

            checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                    item.setAnswer(b ? checkBox.getTag() + "|" : "");
//                        items.set(position, item);

                    try {
                        JSONArray toToggleItems = new JSONArray(item.getOptionsHashMap().get("hidden_ls"));
                        for (int i = 0; i < toToggleItems.length(); i++) {
                            for (int j = 0; j < items.size(); j++) {
                                if (items.get(j).getQId().toString().equals(toToggleItems.getString(i))) {
                                    items.get(j).setShouldHide(!b);
                                    try {
                                        boxReferences.get(items.get(j).getQId().toString()).setVisibility(!b ? View.GONE : View.VISIBLE);
                                    } catch (Exception ignored) {

                                    }
                                    if (!b && items.get(j).getOptionsHashMap().containsKey("hidden_ls")) {
                                        try {
                                            ((CheckBox) boxReferences.get(items.get(j).getQId().toString()).findViewById((int) 123)).setChecked(false);
                                        } catch (Exception ignored) {

                                        }

                                    }
                                }
                            }

                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            });

//                }
//            }).start();

            boxReferences.put(item.getQId().toString(), layoutView);
            layoutView.setVisibility(item.getShouldHide() ? View.GONE : View.VISIBLE);
            return layoutView;

        }


        return null;
    }

    public void prepareItemsForValidation(int position) {
        try {
            items.get(position).setAnswer(textViewsReferences.get(position).getText().toString());

        } catch (Exception ignored) {

        }

    }


    public int getItemViewType(int position) {
        final Question item = items.get(position);

//        Log.e(TAG, "type:"+item.type);
        switch (item.getQType()) {
            case "Text":
                return VIEW_TYPE_TEXT;
            case "Checkbox":
                return VIEW_TYPE_CHECKBOX;
            case "Input":
                return VIEW_TYPE_INPUT;
            case "Radio Button":
                return VIEW_TYPE_RADIO;
            case "OPTCheckbox":
                return VIEW_TYPE_OPTCHECKBOX;
        }

        return VIEW_TYPE_TEXT;
//        return super.getItemViewType(position);
    }

    public void setOnProgressViewChanged(OnProgressViewChanged onProgressViewChanged) {
        this.onProgressViewChanged = onProgressViewChanged;
    }

    public interface OnProgressViewChanged {
        void onChanged(int progress);

        void onFinish(View view, Boolean lastIndex);
    }

}

Даже во время активности я вызвал метод removeAll () в методе destroy ():

@Override
    protected void onDestroy() {

        adapter.removeAllView(insideContainer);
        System.gc();
        super.onDestroy();
    } 

1 Ответ

0 голосов
/ 28 мая 2020

Я обнаружил, что каждый раз, когда мы вызываем g c, g c не выполняет свою работу. Фактически, следуя ряду вещей, например, не сохраняя сильную ссылку из View в памяти, g c сможет удалить кучу, пока куча заполнена. Так как использовалось WeakHashMap , g c удалит его вовремя. В противном случае этого бы не произошло, если бы я использовал HashMap .

...