0

我對DialogFragments和backstack有一個非常惱人的問題。DialogFragment中的ListView不會保持最新狀態

我有一個MainActivity託管ActiveMenuFragment。

ActiveMenuFragment有一個按鈕,啓動一個DialogFragmentActionSelector(所有的方法都是從MainActivity運行被迫接口方法):

/** 
    * Opens the action selection dialog, so the user may pick an action to 
    * begin. 
    */ 
    @Override 
    public void openActionSelector() { 
     actionSelectorFragment = DialogFragmentActionSelector.newInstance(); 
     Bundle args = new Bundle(); 
     args.putSerializable("Profile", currentProfile); 
     actionSelectorFragment.setArguments(args); 
     FragmentTransaction ft = this.getFragmentManager().beginTransaction(); 
     ft.addToBackStack("Action Selector"); 
     actionSelectorFragment.show(ft, "Action Selector"); 
    } 

這個片段顯示與操作列表中一個ListView。在這一點上一切都很好。甚至以前添加的新操作也會顯示在這裏。現在,如果用戶希望定義一個新的行動,他們按在啓動DialogFragment按鈕DialogFragmentDefineNewAction:

/** 
    * Opens the action selection dialog, so the user may pick an action to 
    * begin. 
    */ 
    @Override 
    public void openActionSelector() { 
     actionSelectorFragment = DialogFragmentActionSelector.newInstance(); 
     Bundle args = new Bundle(); 
     args.putSerializable("Profile", currentProfile); 
     actionSelectorFragment.setArguments(args); 
     FragmentTransaction ft = this.getFragmentManager().beginTransaction(); 
     ft.addToBackStack("Action Selector"); 
     actionSelectorFragment.show(ft, "Action Selector"); 
    } 

用戶在他們的新行動的數據已進入後,他們打了確認按鈕,這是爲了更新前一個片段(DialogFragmenActionSelector)內的ListView,但不是。每次我通過後臺返回時,它都會顯示同樣的舊8行爲。

/** 
    * Takes the action defined in the DefineNewAction fragment and adds it to 
    * the user dictionary. 
    */ 
    @Override 
    public void addNewActionToDictionary(Action toAdd) { 
     currentProfile.getDictionary().addDefinition(toAdd); 
     actionSelectorFragment.updateProfile(currentProfile); 
    } 

僅供參考,這裏是整個DialogFragmentActionSelector,與包括其ArrayAdapter:

public class DialogFragmentActionSelector extends DialogFragment implements 
     OnClickListener { 

    private EditText searchBar; 
    private Button defineNewActionBtn; 
    private ListView actionList; 
    private UserProfile user; 
    private ListViewInterface mInterface; 
    private ActionsAdapter adapter; 

    public interface ListViewInterface { 

     void openDefineNewAction(); 



     void setActiveMenuActionBar(String action); 
    } 



    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     if (activity instanceof ListViewInterface) { 
     mInterface = (ListViewInterface) activity; 
     } else { 
     throw new ClassCastException(activity.toString() 
       + " must implement ListViewInterface"); 
     } 
    } 



    /** 
    * Constructor for the fragment. 
    * 
    * @return 
    */ 
    public static DialogFragmentActionSelector newInstance() { 
     DialogFragmentActionSelector dfm = new DialogFragmentActionSelector(); 
     return dfm; 
    } 



    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 
     View toReturn = inflater.inflate(
      R.layout.fragment_action_selector_layout, container, false); 
     user = (UserProfile) this.getArguments().get("Profile"); 
     searchBar = (EditText) toReturn.findViewById(R.id.action_search_bar); 
     searchBar.addTextChangedListener(new TextWatcher() { 

     @Override 
     public void afterTextChanged(Editable arg0) { 
     } 



     @Override 
     public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, 
       int arg3) { 
     } 



     @Override 
     public void onTextChanged(CharSequence arg0, int arg1, int arg2, 
       int arg3) { 
      adapter.updateList(); 
      adapter.getFilter().filter(arg0); 
     } 
     }); 
     defineNewActionBtn = (Button) toReturn 
      .findViewById(R.id.define_new_action); 
     defineNewActionBtn.setOnClickListener(this); 
     actionList = (ListView) toReturn.findViewById(R.id.actions_list); 
     ArrayList<Action> allActions = user.getDictionary().getAllActions(); 
     adapter = new ActionsAdapter(this.getActivity(), 
      android.R.layout.simple_list_item_1, allActions, inflater); 
     actionList.setAdapter(adapter); 
     actionList.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> parent, View clickedView, 
       int index, long id) { 
      Action selectedAction = (Action) parent.getItemAtPosition(index); 
      mInterface.setActiveMenuActionBar(selectedAction.getActionName()); 
      dismiss(); 
     } 
     }); 
     return toReturn; 
    } 



    public void updateProfile(UserProfile updatedProfile) { 
     user = updatedProfile; 
     ArrayList<Action> allActions = user.getDictionary().getAllActions(); 
     adapter = new ActionsAdapter(this.getActivity(), 
      android.R.layout.simple_list_item_1, allActions, getActivity() 
        .getLayoutInflater()); 
     actionList.setAdapter(adapter); 
     actionList.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> parent, View clickedView, 
       int index, long id) { 
      Action selectedAction = (Action) parent.getItemAtPosition(index); 
      mInterface.setActiveMenuActionBar(selectedAction.getActionName()); 
      dismiss(); 
     } 
     }); 
     // this.updateListView(); 
    } 



    private void updateListView() { 
     adapter.updateList(); 
    } 

    // TODO FIX CONSTRUCTOR. UPON RETURNING, IT REVERTS TO DEFAULT 8 ACTIONS 
    // RATHER THAN NEW ONES. 
    private class ActionsAdapter extends ArrayAdapter<Action> implements 
     Filterable { 

     LayoutInflater inflater; 
     ArrayList<Action> actionsList; 



     public ActionsAdapter(Context context, int resId, 
      ArrayList<Action> objects, LayoutInflater inflater) { 
     super(context, resId, objects); 
     this.actionsList = objects; 
     this.inflater = inflater; 
     } 



     @Override 
     public int getCount() { 
     return actionsList.size(); 
     } 



     @Override 
     public Action getItem(int position) { 
     return actionsList.get(position); 
     } 



     @Override 
     public long getItemId(int position) { 
     return this.getItem(position).hashCode(); 
     } 



     public void updateList() { 
     ArrayList<Action> allActions = user.getDictionary().getAllActions(); 
     actionsList = allActions; 
     notifyDataSetInvalidated(); 
     // notifyDataSetChanged(); 
     } 



     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder = null; 
     Action toWrap = actionsList.get(position); 
     if (convertView == null) { 
      holder = new ViewHolder(); 
      convertView = inflater.inflate(
        R.layout.listview_row_action_selector, parent, false); 
      holder.actionName = (TextView) convertView 
        .findViewById(R.id.action_title); 
      convertView.setTag(holder); 
     } else 
      holder = (ViewHolder) convertView.getTag(); 
     holder.actionName.setText(toWrap.getActionName()); 
     return convertView; 
     } 

     private class ViewHolder { 

     TextView actionName; 
     } 



     /** 
     * Filters the adapter's database. 
     */ 
     @Override 
     public Filter getFilter() { 
     Filter filter = new Filter() { 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       FilterResults results = new FilterResults(); 
       ArrayList<Action> matchingActions = new ArrayList<Action>(); 
       for (int i = 0; i < actionsList.size(); i++) { 
        Action actionToCheck = actionsList.get(i); 
        ArrayList<String> actionTags = actionToCheck.getTags(); 
        String searchQuery = constraint.toString(); 
        boolean foundMatch = false; 
        int k = 0; 
        int tagSize = actionTags.size(); 
        if (tagSize != 0) { 
        while (!foundMatch && k < tagSize) { 
         if (actionTags.get(k).contains(searchQuery)) { 
          matchingActions.add(actionToCheck); 
          foundMatch = true; 
         } 
         k++; 
        } 
        } 
       } 
       results.count = matchingActions.size(); 
       results.values = matchingActions; 
       return results; 
      } 



      @SuppressWarnings("unchecked") 
      @Override 
      protected void publishResults(CharSequence constraint, 
        FilterResults results) { 
       // actionsList.clear(); 
       actionsList = (ArrayList<Action>) results.values; 
       adapter.notifyDataSetChanged(); 
      } 
     }; 
     return filter; 
     } 
    } 



    @Override 
    public void onClick(View v) { 
     switch (v.getId()) { 
     case R.id.define_new_action: 
     mInterface.openDefineNewAction(); 
     break; 
     default: 
     break; 
     } 
    } 



    public void addNewActionToDictionary(Action toAdd) { 
     user.getDictionary().addDefinition(toAdd); 
     adapter.add(toAdd); 
     adapter.updateList(); 
    } 
} 

我應該使用notifyDataSetChanged()或無效?因爲它不適用於我的適配器。

如果關閉所有對話框並再次打開它們,則更新的操作將顯示在列表視圖中。爲什麼?

另外,我覺得我做事情效率低下,使事情比他們需要的更復雜。 UserProfile對象還包含與用戶有關的Actions Dictionary和其他信息。宿主活動是否應該保留並修改它,或者ActiveMenu片段是否應該處理它?

回答

0

將新項目添加到適配器後,必須調用notifyDataSetChanged(),以便listview使用適配器中找到的新數據集刷新自身。你不需要改變適配器本身,因爲你正在做的功能updateProfile

+0

我試着從addNewActionToDictionary(Action toAdd)調用它。用戶配置文件是從活動級別和ActiveMenuFragment以及ActionSelectorDialogFragment中更新的。但是,當返回時DialogFragment彈出堆棧時,它仍然是一樣的。你確定這不是導致我問題的後臺嗎?也許我應該重新創建DialogFragment。 –

+0

更新:每次從片段中重新創建時,我都會在適配器中添加一些LogCat行。事實證明,底層數據在那裏,但它並沒有顯示在ListView中。 –

+0

如果適配器中有物品,那麼這些物品就會顯示出來。當你的Fragment開始關注時(在後退鍵按下之後)你能檢查適配器的作用。如果它還有新添加的項目。最後的手段是強制listview使用調用invalidate() – prijupaul