有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么捆绑包中的ArrayList仍然存在?

设置:

带有一个片段的活动,该片段通过单击按钮实例化。在片段的构造函数中使用Bundle。在Bundle中设置了String (surname)ArrayList<String> (fornames)。片段通过回调分离

问题: 当片段被分离时String (surname)会像预期的那样被破坏,但ArrayList会继续存在。因此,当调用片段的新实例时,前面的ArrayList条目出现。回调不是问题所在。该行为也会在没有回调的情况下出现

我已经在片段构造函数(FRAG_CONSTRUCTOR)、片段onCreate方法(FRAG_ARGS_ONCREATE)和片段回调(FRAG_CALLBACK)中用Log.d检查了变量(surname = Blackfornename = Joe)。 surname Black不像LogCat中所示的那样,但是forname Joe仍然存在

活动:

public class MainActivity extends AppCompatActivity implements FragRecycler.FragRecyclerCallBackListener {

    private Button button;
    private String surname;
    private ArrayList<String> fornames;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fornames = new ArrayList<String>();
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addFragmentWithTransition(R.id.container, FragRecycler.newInstance(surname, fornames), "FRAG_RECYCLER");
            }
        });

    }

    public void addFragmentWithTransition(int containerViewId, Fragment fragment, String fragmentTag) {
        getSupportFragmentManager()
                .beginTransaction()
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                .add(containerViewId, fragment, fragmentTag)
                .addToBackStack(fragmentTag)
                .commit();
    }

    @Override
    public void onFragRecyclerCallback() {
        Log.d("FRAG_CALLBACK", "forname: " + fornames + " surname: " + surname);
        getSupportFragmentManager().popBackStack();
    }

    @Override
    public void onBackPressed() {
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStack();
        } else {
            super.onBackPressed();
        }
    }
}

片段:

public class FragRecycler extends Fragment {

    private View v;
    private Toolbar toolbar;
    private TextInputEditText vSurname;
    private RecyclerView rvForenames;
    private AdapterForName adapter;

    private FragRecyclerCallBackListener callback;

    public interface FragRecyclerCallBackListener {
        void onFragRecyclerCallback();
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof AppCompatActivity){
            try {
                callback = (FragRecyclerCallBackListener) context;
            } catch (ClassCastException e) {
                throw new ClassCastException(context.toString() + " must implement FragRecyclerCallBackListener");
            }
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        callback = null;
    }

    public static FragRecycler newInstance(String surname, ArrayList<String> fornames) {
        Log.d("FRAG_CONSTRUCTOR", "forname: " + fornames + " surname: " + surname);
        FragRecycler p = new FragRecycler();
        Bundle b = new Bundle();
        b.putString("SURNAME", surname);
        b.putStringArrayList("FORNAMES", fornames);
        p.setArguments(b);

        return p;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        Log.d("FRAG_ARGS_ONCREATE", "forname: " + getArguments().getStringArrayList("FORNAMES") + " surname: " + getArguments().getString("SURNAME"));
        v = inflater.inflate(R.layout.frag_recycler, container, false);
        toolbar = (Toolbar) v.findViewById(R.id.toolbar);

        vSurname = (TextInputEditText) v.findViewById(R.id.surname);
        rvForenames = (RecyclerView) v.findViewById(R.id.rv_forenames);

        vSurname.setText(getArguments().getString("SURNAME"));
        adapter = new AdapterForName("Forename", getArguments().getStringArrayList("FORNAMES"));
        rvForenames.setAdapter(adapter);
        rvForenames.setLayoutManager(new LinearLayoutManager(getContext()));

        toolbar.setNavigationIcon(ContextCompat.getDrawable(getContext(), R.drawable.ic_clear));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               callback.onFragRecyclerCallback();
            }
        });

        return v;
    }


    class AdapterForName extends RecyclerView.Adapter<AdapterForName.ViewHolder> {

        private ArrayList<String> names;
        private String callType;

        public AdapterForName(String callType, ArrayList<String> names) {
            this.callType = callType;
            this.names = names;
            if (names.size() == 0) {
                addEmptyEntryToList();
            } else {
                if (!(names.get(names.size() - 1).trim().length() < 1)) {
                    addEmptyEntryToList();
                }
            }
        }

        protected void addEmptyEntryToList() {
            names.add("");
            notifyDataSetChanged();
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.name, parent, false);
            return new ViewHolder(v);
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder,  int position) {

            if (position == 0) {
                holder.inputLayout.setHint(callType);
            } else {
                holder.inputLayout.setHint(String.valueOf(position + 1) + " th." + " " + callType);
            }

            holder.input.setText(names.get(position));
            holder.input.setTag(position);
            holder.input.addTextChangedListener(new TextWatcher() {

                public void afterTextChanged(Editable s) {

                    final String inputText = s.toString().trim();

                    names.set(holder.getAdapterPosition(), inputText);

                }

                public void beforeTextChanged(CharSequence s, int start,
                                              int count, int after) {

                }

                public void onTextChanged(CharSequence s, int start,
                                          int before, int count) {

                }

            });

            holder.input.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View view, boolean b) {
                    if (!b) { // inputEditText hat keinen Focus mehr.
                        if (holder.input.getText().toString().trim().length() > 0){
                            int count = 0;
                            for (int i = 0; i < names.size(); i++) {
                                if (names.get(i).trim().length() == 0) {
                                    count = count + 1;
                                }
                            }

                            if (count == 0) {
                                names.add("");
                                notifyDataSetChanged();
                            }
                        }
                        if (holder.input.getText().toString().trim().length() == 0){
                            int count = 0;
                            for (int i = 0; i < names.size(); i++) {
                                if (names.get(i).trim().length() == 0) {
                                    count = count + 1;
                                }
                            }
                            if (count > 0) {
                                names.remove(holder.getAdapterPosition());
                                notifyDataSetChanged();
                            }
                        }
                    }
                }
            });
        }

        public ArrayList<String> getList() {
            ArrayList<String> trimmedList = new ArrayList<>();
            for (int i = 0; i < names.size(); i++) {
                if (names.get(i).trim().length() > 0) {
                    trimmedList.add(names.get(i));
                }
            }
            return trimmedList;
        }

        @Override
        public int getItemCount() {
            return names.size();
        }


        class ViewHolder extends RecyclerView.ViewHolder {

            public TextInputLayout inputLayout;
            public TextInputEditText input;

            public ViewHolder(View itemView) {
                super(itemView);
                inputLayout = (TextInputLayout) itemView.findViewById(R.id.input_layout);
                input = (TextInputEditText) itemView.findViewById(R.id.input);
            }
        }
    }

}

日志:

08-05 21:42:34.387 17055-17055/com.example.user.recyclertest W/art: Before Android 4.1, method int 安卓.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in 安卓.widget.ListView

08-05 21:42:36.625 17055-17055/com.example.user.recyclertest D/FRAG_CONSTRUCTOR: forname: [] surname: null
08-05 21:42:36.643 17055-17055/com.example.user.recyclertest D/FRAG_ARGS_ONCREATE: forname: [] surname: null

08-05 21:42:41.852 17055-17055/com.example.user.recyclertest W/IInputConnectionWrapper: finishComposingText on inactive InputConnection

08-05 21:42:41.857 17055-17055/com.example.user.recyclertest W/IInputConnectionWrapper: finishComposingText on inactive InputConnection

08-05 21:42:45.200 17055-17055/com.example.user.recyclertest D/FRAG_CALLBACK: forname: [Joe] surname: null
08-05 21:42:45.486 17055-17055/com.example.user.recyclertest W/IInputConnectionWrapper: finishComposingText on inactive InputConnection

08-05 21:42:45.487 17055-17055/com.example.user.recyclertest W/IInputConnectionWrapper: finishComposingText on inactive InputConnection

08-05 21:43:03.441 17055-17055/com.example.user.recyclertest D/FRAG_CONSTRUCTOR: forname: [Joe, ] surname: null

共 (2) 个答案

  1. # 1 楼答案

    在活动的onCreate()方法中,您可以编写

    fornames = new ArrayList<String>();
    

    它将新的(空的)ArrayList实例分配给活动的forenames实例变量。然后你写

    FragRecycler.newInstance(surname, fornames)
    

    这将导致fornames被添加到新片段的“参数”束中

        b.putStringArrayList("FORNAMES", fornames);
    

    最终会传递给适配器的构造函数

        adapter = new AdapterForName("Forename", getArguments().getStringArrayList("FORNAMES"));
    

    适配器将其分配给其names实例变量的位置:

            this.names = names;
    

    当用户使用你的应用程序时,你的程序会继续修改适配器的names列表

    这里要实现的关键是,所有这些代码位都在讨论同一个ArrayList实例。因此,当您的应用程序添加名称或从适配器的names列表中删除名称时,它也是从活动的fornames列表中添加和删除名称。这是因为这两个变量指向同一个对象

    如果您想确保您的片段不能修改活动的fornames列表实例,您应该按如下所示更改片段的newInstance()方法。替换这个

    b.putStringArrayList("FORNAMES", fornames);
    

    为此:

    List<String> fornamesCopy = new ArrayList<>(fornames);
    b.putStringArrayList("FORNAMES", fornamesCopy);
    

    new关键字意味着现在您的片段有一个与您的活动不同的ArrayList实例,因此修改这个实例不会影响另一个实例。这里使用的特定构造函数将确保这个新的ArrayList实例仍然保持与原始实例相同的值

  2. # 2 楼答案

    如果在FRAG_CALLBACK调用中引用的是不同的字段,您希望得到什么?您正在引用MainActivity.surnameMainActivity.fornames,但是在您的片段中,它们位于完全不同的内存位置,因为Bundle中的值是按值传递的-当您调用putX然后getX时,您将得到一个副本