1

我被困在试图重新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());
    }
}

我的片段

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 代码,看看我是否也可以查明其中的数据,以防数据没有进入适配器或发生奇怪的事情。

更新我已经找到了更多的问题。似乎在使用已更新项目setListItem(mAdapter)mAdaptergetView(...)成功调用后,适配器没有被调用。

更新#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) {
    }
}
4

3 回答 3

3

尽量不要每次都设置一个适配器,而是更新你的适配器。

mAdapter.setNewList(newList);    //custom method, just replace the old list with the new one
mAdapter.notifyDataSetChanged();

这意味着您不需要setListAdapter(mAdapter);每次都使用,而只是第一次使用。

希望这会帮助你。

于 2012-08-01T14:55:38.443 回答
1

理论上(正如其他人所指出的)调用notifyDataSetChanged()应该就足够了,但是看看ListView.invalidateViews()在你更新setNewList()方法中的数据之后调用是否可以强制你的列表显示新数据(你的getView()方法应该被调用)。

如果getView()在您强制它时确实被调用但它仍然具有旧数据,那么您可能以某种方式拥有 ListFragment 的冗余副本(并且具有更新的适配器数据的副本不可见)。也许你需要研究你的mTabsAdapter实现。

于 2012-08-13T14:27:30.713 回答
0

就像 CFlex 说的,你应该只setListAdapter()在你Fragment第一次创建时调用一次。

看起来您只是想清除您的列表。通常Adapter,您使用的将有一种clear()方法来为您处理,这可能比每次完全重新分配数据对象要简洁一些。如果您使用的是自定义Adapter,那么只需自己覆盖该方法。务必在notifyDataSetChanged()对数据进行所有更改后致电。这将导致ListView更新其视图。

于 2012-08-01T15:03:53.433 回答