2017-08-05 39 views
0

设置:为什么包中的ArrayList持续存在?

活性与被实例化与按钮点击一个片段。在片段的构造函数Bundle中使用。在Bundle中设置了String (surname)ArrayList<String> (fornames)。片段通过回调被分离。

问题: 当片段被分离时,String (surname)被按预期破坏,但ArrayList仍然存在。因此,当调用片段的新实例时,会出现前者ArrayList条目。回调不是问题。这种行为也没有回调。

我与Log.d检查变量(surname = Blackfornename = Joe)在点片段构造(FRAG_CONSTRUCTOR),片段在onCreate方法(FRAG_ARGS_ONCREATE)和片段回调(FRAG_CALLBACK)。 的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); 
      } 
     } 
    } 

} 

的logcat:

08-05 21:42:34.387 17055-17055/com.example.user.recyclertest W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.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 

回答

0

在你活动的onCreate()方法,你写

fornames = new ArrayList<String>(); 

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

FragRecycler.newInstance(surname, fornames) 

导致fornames被添加到最终传递到您的适配器的构造

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

您的适配器分配一个新片段的“论据”捆绑

b.putStringArrayList("FORNAMES", fornames); 

它到它的names实例变量:

 this.names = names; 

你的程序然后继续当用户使用你的应用程序来修改适配器的names名单。

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

如果你想确保你的Fragment不能修改你的Activity的fornames列表实例,你应该改变你的Fragment的newInstance()方法如下。替换此

b.putStringArrayList("FORNAMES", fornames); 

与此:

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

new关键字意味着现在你的片段具有比活动为您提供不同 ArrayList实例,所以修改此人会不会影响其他。这里使用的特定构造函数将确保这个新的ArrayList实例仍然保持与原始值相同的值。

+0

你好,本,感谢您的绝对和逻辑的解释。你是对的。这是解决方案。我没有看到这个事实。 – Roland

0

你有什么期望有如果FRAG_CALLBACK叫你引用不同的领域?您引用的是MainActivity.surnameMainActivity.fornames,但在您的片段中,它们位于完全不同的内存位置,因为Bundle中的值是按值传递的 - 当您调用putX,然后getX时,您将获得副本。

相关问题