0

DialogFragments と backstacks で本当に厄介な問題が発生しています。

ActiveMenuFragment をホストする MainActivity があります。

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 を表示します。この時点ではすべて問題ありません。以前に追加された新しいアクションもここに表示されます。ここで、ユーザーが新しいアクションを定義したい場合は、DialogFragmentDefineNewAction を起動する DialogFragment のボタンを押します。

/**
    * 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);
   }

参考までに、ArrayAdapter を含む DialogFragmentActionSelector 全体を次に示します。

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 オブジェクトには、アクション ディクショナリと、ユーザーに関連するその他の情報も保持されます。ホスト アクティビティはこれを保持して変更する必要がありますか、それとも ActiveMenu フラグメントで処理する必要がありますか?

4

1 に答える 1

0

新しいアイテムをアダプタに追加したらnotifyDataSetChanged()、リストビューがアダプタで見つかった新しいデータ セットで更新されるように呼び出す必要があります。関数で行っているように、アダプター自体を変更する必要はありませんupdateProfile

于 2013-09-22T22:39:32.757 に答える