我對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片段是否應該處理它?
我試着從addNewActionToDictionary(Action toAdd)調用它。用戶配置文件是從活動級別和ActiveMenuFragment以及ActionSelectorDialogFragment中更新的。但是,當返回時DialogFragment彈出堆棧時,它仍然是一樣的。你確定這不是導致我問題的後臺嗎?也許我應該重新創建DialogFragment。 –
更新:每次從片段中重新創建時,我都會在適配器中添加一些LogCat行。事實證明,底層數據在那裏,但它並沒有顯示在ListView中。 –
如果適配器中有物品,那麼這些物品就會顯示出來。當你的Fragment開始關注時(在後退鍵按下之後)你能檢查適配器的作用。如果它還有新添加的項目。最後的手段是強制listview使用調用invalidate() – prijupaul