Android:使用带有自定义适配器的notifyDataSetChanged()的ListFragment刷新不起作用

时间:2013-11-15 23:32:31

标签: android listview android-fragments android-listfragment notifydatasetchanged

我正在使用带有自定义列表适配器的ListFragment,我想通过单击ActionBar中的图标来刷新列表。不幸的是它不起作用,我不明白为什么。

我的ItemListFragment:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.d("debug","Hallo in ItemListFragment");

    //show ActionBar
    setHasOptionsMenu(true);

    //get reference to activity
    myApp = getActivity().getApplication();

    //check if intent from ItemListActivity is null
    Bundle be = getActivity().getIntent().getExtras();
    if (be == null){
        //if null read local feed
        feed = ReadFeed(fileName);
        Log.d("debug", "Lese Feed lokal :"+feed);
    }else{
        //else get extras from the intent
        feed = (RSSFeed) getActivity().getIntent().getExtras().get("feed");
        Log.d("debug", "Intent von ItemListActivity an ItemListFragment vorhanden");
    }

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
        Bundle savedInstanceState) {
    //inflate the fragment with the custom detail fragment
    View view = inflater.inflate(R.layout.feed_list, null);
    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    //get listview from layout
    lv = getListView();
    lv.setVerticalFadingEdgeEnabled(true);

    // Set custom list adapter to the ListView        
    adapter = new CustomListAdapter(getActivity(), feed);
    lv.setAdapter(adapter);

}

//Inflate ActionBar
@Override
public void onCreateOptionsMenu(Menu optionsMenu, MenuInflater inflater) {
    inflater.inflate(R.menu.main, optionsMenu);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    // Restore the previously serialized activated item position.
    if (savedInstanceState != null
            && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
        setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
    }
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // Activities containing this fragment must implement its callbacks.
    if (!(activity instanceof Callbacks)) {
        throw new IllegalStateException("Activity must implement fragment's callbacks.");
    }

    mCallbacks = (Callbacks) activity;
}

@Override
public void onDetach() {
    super.onDetach();

    // Reset the active callbacks interface to the dummy implementation.
    mCallbacks = sCallbacks;
}

@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
    super.onListItemClick(listView, view, position, id);

    // Notify the active callbacks interface (the activity, if the
    // fragment is attached to one) that an item has been selected.
    if (mCallbacks != null) {
        Log.d("debug","Callback in ItemListFragment mit Position: "+position+"und Feed: "+feed);
        mCallbacks.onItemSelected(position, feed);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    if (mActivatedPosition != ListView.INVALID_POSITION) {
        // Serialize and persist the activated item position.
        outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
    }
}

/**
 * Turns on activate-on-click mode. When this mode is on, list items will be
 * given the 'activated' state when touched.
 */
public void setActivateOnItemClick(boolean activateOnItemClick) {
    // When setting CHOICE_MODE_SINGLE, ListView will automatically
    // give items the 'activated' state when touched.
    getListView().setChoiceMode(activateOnItemClick
            ? ListView.CHOICE_MODE_SINGLE
                    : ListView.CHOICE_MODE_NONE);
}

private void setActivatedPosition(int position) {
    if (position == ListView.INVALID_POSITION) {
        getListView().setItemChecked(mActivatedPosition, false);
    } else {
        getListView().setItemChecked(position, true);
    }

    mActivatedPosition = position;
}

//OnClick auf ActionBar
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        return true;
    case R.id.refresh_option:
        refreshList(item);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

//Click on refresh in ActionBar -> Refresh the List
public void refreshList(final MenuItem item) {
    /* Attach a rotating ImageView to the refresh item as an ActionView */
    LayoutInflater inflater = (LayoutInflater) getActivity().getApplication()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    ImageView iv = (ImageView) inflater.inflate(R.layout.action_refresh,
            null);

    Animation rotation = AnimationUtils.loadAnimation(getActivity(),
            R.anim.refresh_rotate);
    rotation.setRepeatCount(Animation.INFINITE);
    iv.startAnimation(rotation);

    item.setActionView(iv);

    // trigger feed refresh:
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            DOMParser tmpDOMParser = new DOMParser();
            feed = tmpDOMParser.parseXml("http://www.example.de/feed");

            Log.d("debug", "Refresh Liste mit Feed: "+feed);

            ItemListFragment.this.getActivity().runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (feed != null && feed.getItemCount() > 0) {
                        Log.d("debug", "Aktualisiere Liste");
                        adapter.notifyDataSetChanged();
                        item.getActionView().clearAnimation();
                        item.setActionView(null);
                    }
                }
            });
        }
    });
    thread.start();
}

@Override
public void onDestroy() {
    super.onDestroy();
    //TODO Datenverbrauch dadurch geringer?
    //adapter.imageLoader.clearCache();
    adapter.notifyDataSetChanged();
}   

我的CustomListAdapter.java

public class CustomListAdapter extends BaseAdapter  {

    private LayoutInflater layoutInflater;
    public ImageLoader imageLoader;
    public RSSFeed _feed;

    public CustomListAdapter(Activity activity, RSSFeed feed) {

        _feed = feed;

        layoutInflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader = new ImageLoader(activity.getApplicationContext());
    }

    @Override
    public int getCount() {
        // Set the total list item count
        return _feed.getItemCount();
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // Inflate the item layout and set the views
        View listItem = convertView;
        int pos = position;
        if (listItem == null) {
            listItem = layoutInflater.inflate(R.layout.list_item, null);
        }

        // Initialize the views in the layout
        ImageView iv = (ImageView) listItem.findViewById(R.id.thumb);
        TextView tvTitle = (TextView) listItem.findViewById(R.id.title);
        TextView tvDate = (TextView) listItem.findViewById(R.id.date);
        TextView tvDesc = (TextView) listItem.findViewById(R.id.description);

        // Set the views in the layout
        imageLoader.DisplayImage(_feed.getItem(pos).getImage(), iv);
        tvTitle.setText(_feed.getItem(pos).getTitle());
        tvDate.setText(_feed.getItem(pos).getDate());
        tvDesc.setText(_feed.getItem(pos).getShortDescription());

        return listItem;
    }
}

这是我尝试刷新列表的部分:

        @Override
        public void run() {
            if (feed != null && feed.getItemCount() > 0) {
                Log.d("debug", "Aktualisiere Liste");
                adapter.notifyDataSetChanged();
                item.getActionView().clearAnimation();
                item.setActionView(null);
            }
        }

我的错误在哪里?

2 个答案:

答案 0 :(得分:9)

您当前的适配器更新代码将无法正常工作,因为您没有更新对数据的正确引用,即适配器实际所基于的数据。当您调用refreshList时,您创建该线程来解析xml并将结果分配给feed变量,但是您的适配器有自己对初始数据(_feed)的引用,这是不受之前作业的影响,因此在notifyDataSetChanged()通话时,它仍会看到旧数据并且什么都不做。

解决方案是更新适配器的_feed引用以指向新的已解析结果集,然后在适配器上调用notifyDataSetChanged()

答案 1 :(得分:0)

        Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        DOMParser tmpDOMParser = new DOMParser();
        feed = tmpDOMParser.parseXml("http://www.example.de/feed");

        Log.d("debug", "Refresh Liste mit Feed: "+feed);

        ItemListFragment.this.getActivity().runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (feed != null && feed.getItemCount() > 0) {
                    Log.d("debug", "Aktualisiere Liste");
    // Set custom list adapter to the ListView        
  adapter = new CustomListAdapter(getActivity(), feed);
      lv.setAdapter(adapter);
                     adapter.notifyDataSetChanged();
                    item.getActionView().clearAnimation();
                    item.setActionView(null);
                }
            }
        });
    }
});
thread.start();

而且你可以使用它来代替刷新按钮。这可以帮助你。 pulltorefresh