Android:使用带有自定义适配器的notifyDataSetChanged()刷新ListFragment无效
我正在使用带有自定义列表适配器的ListFragment,我想通过单击ActionBar中的图标来刷新列表。不幸的是,它不起作用,我不知道为什么 我的ItemListFragment:Android:使用带有自定义适配器的notifyDataSetChanged()刷新ListFragment无效,android,listview,android-fragments,android-listfragment,notifydatasetchanged,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"); //s
@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();
}
My 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);
}
}
我的错误在哪里?适配器的当前更新代码将不起作用,因为您没有更新对数据的正确引用,而数据是适配器实际基于的数据。调用
refreshList
时,您将创建该线程来解析xml并将结果分配给feed
变量,但是适配器有自己对初始数据(\u feed
)的引用,该引用不受前一次分配的影响,因此在notifyDataSetChanged()时
call它仍会看到旧数据,并且不会执行任何操作
解决方案是更新适配器的\u提要
引用,以指向新的解析结果集,然后在适配器上调用notifyDataSetChanged()
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();
你也可以用这个代替刷新按钮。这对你很有帮助。
不要认为这是相关的,但您不需要执行
lv.setAdapter(adapter)代码>订阅源刷新。另外,您是否检查过这段代码是否运行到其完成状态?我在ActionBar中的动画停止,因此我认为代码在您再次解析xml的线程中运行完全,并将其分配给feed
变量,然后调用notifyDataSetChanged()
但这不会更新适配器,因为您不会更新适配器持有的实际数据引用(因此它仍然会看到旧的数据列表)。因此,当您需要更新适配器时,在调用notifyDataSetChanged()
之前,首先更新适配器的\u feed
变量,以指向新解析的feed
(您可以在适配器中添加setter方法,将feed
分配给\u feed
(并在更新线程中调用它).你救了我一天!你能写一个新的评论,这样我就可以把它标记为解决方案吗!这会起作用的..毫无疑问,但每次你到底部时,它都会把你带到列表视图的顶部..这会导致非常糟糕的用户体验…因此这不是解决方案如果你在做setA,NotifyDataSangeetched有什么用一次又一次地改变。