我一直试图重新加载ListView
内的ListFragment
。通过我在FragmentDialog
中创建的侦听器调用刷新。正确调用了 reloadItems 方法,并且我已经验证了变量中项目列表的正确更新。
这似乎是一件很直接的事情,但我被困住了。 ListView从未实际更新,但我认为它与使用的Context
有关。
onClick
属性设置的ListView
行上的按钮调用 android:onClick
。
解决方案
问题是我的选项卡适配器getItem(...)
在创建AlertDialog
时意外地被再次调用,并且由于我的代码不好,它重新实现了选项卡,并且刷新从未发生在可见片段上。 (见最后的原始代码)
一旦发现这个(参见接受的答案),我就可以通过重新编写代码选项卡适配器来维护引用来修复它。这是我ViewPager
的工作标签适配器,以防它对任何人有帮助。
public class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
static final class TabInfo {
private final Class<?> mClass;
private final Bundle mArgs;
TabInfo(Class<?> _class, Bundle _args) {
mClass = _class;
mArgs = _args;
}
public String getClassName() {
return mClass.getName();
}
public Bundle getArgs() {
return mArgs;
}
}
public TabsAdapter(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
Fragment fragment = Fragment.instantiate(mContext, info.getClassName(), info.getArgs());
mFragments.add(fragment);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
解决方案结束
活动
public class MyActivity extends Activity {
// unrelated code removed
public void onClick(View v) {
// onClick is called via a button on a list item
MyFragment sf = (MyFragment)mTabsAdapter.getItem(0);
sf.myClick(v, getFragmentManager());
}
}
MyFragment
public class MyFragment extends ListFragment {
static final String TAG = "StatusFragment";
private ArrayList<MyObject> mItems = null;
AlarmDataSource datasource;
StatusAdapter mAdapter;
public void reloadItems(Context context) {
Log.d(TAG, "reloadItems");
datasource = new MyObjectDataSource(context);
datasource.open();
mItems = new ArrayList<MyObject>();
ArrayList<MyObject> active = (ArrayList<MyObject>)datasource.getAllEnabled();
for (int i = 0; i < active.size(); i++) {
MyObject next = active.get(i);
mItems.add(next);
}
mAdapter = new StatusAdapter(
context,
R.layout.status_list_item,
mItems);
// set a breakpoint and this is called when called from
// statusOptionDialogClose below. Here mAdapter DOES HAVE updated items
// inside. However getView within the adaper is NOT called
setListAdapter(mAdapter);
datasource.close();
}
public void myClick(View v, FragmentManager manager) {
StatusOptionDialog sod = StatusOptionDialog.newInstance(v.getContext());
sod.setStatusOptionDialogListener(new StatusOptionDialogListener() {
public void statusOptionDialogClose(Context context) {
// this is correctly called when dialog closed
// context is the same as sent in with newInstance above.
reloadItems(context);
}
});
sod.show(manager, "StatusOptionDialog");
}
}
有人看到任何错误吗?我已经尝试了很多不同的方法,但没有任何效果。
注意我在更新时也尝试了mAdapter.notifyDataSetChanged()
,但也无效。我将尝试在今天晚些时候逐步浏览Android SDK代码,看看我是否也可以在那里找到数据,以防数据没有进入适配器或奇怪的东西。
更新我已经找到了更多问题。在使用已更新项目的 mAdapter 成功调用setListItem(mAdapter)
后,似乎未调用适配器getView(...)
。
更新#2 我已经发布了reloadItems(...)
函数,我将其提炼为最简单的代码。使用已更新项目的更新适配器调用setListAdapter(...)
。但是,通过getView(...)
reloadItems(...)
时,永远不会调用statusOptionDialogClose(...)
如果我终止应用程序并重新启动它,ListView会显示已更新的数据。只是在再次调用reloadItems时不刷新。
适配器
public class StatusAdapter extends ArrayAdapter<MyObject> {
private Context mContext;
private int mRes;
private ArrayList<MyObject> mItems;
public StatusAdapter(Context context, int textViewResourceId, ArrayList<MyObject> items) {
super(context, textViewResourceId, items);
this.mItems = items;
this.mRes = textViewResourceId;
this.mContext = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(mRes, null);
}
Alarm a = mItems.get(position);
if (a != null) {
// fills out list item
}
return v;
}
@Override
public int getCount() {
return mItems.size();
}
public void setNewList(ArrayList<Alarm> items) {
this.mItems = items;
}
}
标签适配器这用于启用ViewPager
和标签。
public class TabsAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
public void onPageScrollStateChanged(int state) {
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i = 0; i < mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
答案 0 :(得分:3)
尽量不要每次都设置适配器,但请更新适配器。
mAdapter.setNewList(newList); //custom method, just replace the old list with the new one
mAdapter.notifyDataSetChanged();
这意味着您不需要每次都使用setListAdapter(mAdapter);
,而只是第一次。
希望这会对你有所帮助。
答案 1 :(得分:1)
理论上(正如其他人所说),调用notifyDataSetChanged()
就足够了,但看看在setNewList()
方法中更新数据后调用ListView.invalidateViews()
是否会强制列表显示新数据(应调用您的getView()
方法)。
如果在强制它时调用getView()
但它仍然具有旧数据,则有可能以某种方式具有ListFragment的冗余副本(并且具有更新的适配器数据的副本不可见) 。也许您需要查看mTabsAdapter
实施。
答案 2 :(得分:0)
就像CFlex所说,你应该只在首次创建setListAdapter()
时拨打Fragment
。
看起来你只是想清除你的清单。通常,您使用的Adapter
将使用clear()
方法为您处理,这可能比每次完全重新分配数据对象更整洁。如果您使用的是自定义Adapter
,那么请自行覆盖该方法。在对数据进行所有更改后,请务必致电notifyDataSetChanged()
。这将导致ListView
更新其视图。