欢迎所有人。
我有一个FragmentStatePagerAdapter,每个页面都有一个Listview。 FragmentStatePagerAdapter每秒刷新一次,为他的一些页面添加新数据(记住每个页面都是列表视图)。
我使用setAdapter设置listview的内容:
StableArrayAdapter adapter = new StableArrayAdapter((MainActivity) getActivity(), R.layout.list_view_item, ((MainActivity) getActivity()).getData(mPage));
listView.setAdapter(adapter);
问题在于某些页面有很多内容和垂直滚动,所以当调用listView.setAdapter(adapter);
时,每一秒都会强制列表视图的滚动。这是一种非常不正常和烦人的行为。
我在stackoverflow上找到了这个:notifyDataSetChanged() makes the list refresh and scroll jumps back to the top
问题是这些解决方案是针对普通的ViewPager或普通适配器而设计的,并且不能使用FragmentStatePageAdapter或其他东西,因为在尝试它们之后我仍然遇到同样的问题。
这是我对FragmentStatePagerAdapter的适配器:
public class CollectionPagerAdapter extends FragmentStatePagerAdapter {
public CollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return ObjectFragment.newInstance(position);
}
@Override
public int getCount() {
return infoTitlesArray.length;
}
@Override
public CharSequence getPageTitle(int position) {
return infoTitlesArray[position];
}
}
ViewPager有问题:
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="4dp"
android:paddingBottom="4dp"
style="@style/CustomPagerTitleStrip"/>
</android.support.v4.view.ViewPager>
片段的布局:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ListView>
片段的java代码:
public static class ObjectFragment extends Fragment implements DataUpdateListener {
private int mPage;
private ListView listView;
public static ObjectFragment newInstance(int page) {
ObjectFragment objectFragment = new ObjectFragment();
Bundle args = new Bundle();
args.putInt("page", page);
objectFragment.setArguments(args);
return objectFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt("page");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
((MainActivity) getActivity()).addDataUpdateListener(this);
listView = (ListView) rootView;
StableArrayAdapter adapter = new StableArrayAdapter((MainActivity) getActivity(), R.layout.list_view_item, ((MainActivity) getActivity()).getData(mPage));
listView.setAdapter(adapter);
return rootView;
}
@Override
public void onDestroyView() {
((MainActivity) getActivity()).removeDataUpdateListener(this);
super.onDestroyView();
}
//DataUpdateListener interface methods
@Override
public int getPage() {
return mPage;
}
@Override
public void onDataUpdated(ArrayList<String> data) {
StableArrayAdapter adapter = new StableArrayAdapter((MainActivity) getActivity(), R.layout.list_view_item, data);
listView.setAdapter(adapter);
}
}
当需要更新片段的内容(列表视图)时,将使用参数中接收的新内容调用onDataUpdated方法。
感谢您的帮助
编辑:
使用Budius中的代码示例添加生成崩溃的适配器:
private static class StableArrayAdapter extends ArrayAdapter<String> {
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
public StableArrayAdapter(Context context, int textViewResourceId, List<String> objects) {
super(context, textViewResourceId, objects);
for (int i = 0; i < objects.size(); ++i) {
mIdMap.put(objects.get(i), i);
}
}
public void setData(List<String> objects){
mIdMap.clear();
for (int i = 0; i < objects.size(); ++i) {
mIdMap.put(objects.get(i), i);
}
}
@Override
public long getItemId(int position) {
String item = getItem(position);
return mIdMap.get(item);
}
@Override
public boolean hasStableIds() {
return true;
}
}
编辑2:
尝试使用Budius解决方案的新适配器。但它不起作用。内容没有刷新。
private static class StableArrayAdapter extends ArrayAdapter<String> {
List<String> objects;
public StableArrayAdapter(Context context, int textViewResourceId, List<String> objects) {
super(context, textViewResourceId, objects);
this.objects = new ArrayList<>();
this.objects.addAll(objects);
}
public void setData(List<String> objects){
this.objects.clear();
this.objects.addAll(objects);
}
@Override
public long getItemId(int position) {
return Math.abs(objects.get(position).hashCode());
}
@Override
public boolean hasStableIds() {
return true;
}
}
答案 0 :(得分:1)
调用setAdapter(adapter)
并返回顶部的列表是正常的并且是“预期的”行为。毕竟,它是一个新的适配器,框架不应该假设新适配器与旧适配器有任何关系。
说,您的解决方案应该仍然在notifyDataSetChanged()
左右,并且stableIds
的适当用法。考虑到这一点,你应该做的只是切换ArrayList<String> data
而不是创建一个新的@Override
public void onDataUpdated(ArrayList<String> data) {
adapter.setData(data); // internally replaces the old data with this new one
adapter.notifyDataSetChanged();
}
。像这样:
hasStableIds
然后在实施StableArrayAdapter时,您必须覆盖getItemId
才能返回true并覆盖Math.abs(value.hashCode)
以返回有意义的值。考虑到你的数据只是字符串,这有点棘手,但像RecyclerView
这样的东西就足够了。
PS:我强烈建议使用ListView
代替public class StableArrayAdapter extends /* whatever you're extending */ {
... your code as usual
@Override public boolean hasStableIds() { return true; }
@Override public long getItemId(int position) {
return Math.abs(data.get(position).hashCode());
}
}
。就个人而言,我不明白为什么Google还没有弃用ListView。
修改强>
根据评论,有点像这样:
ID
表示您告诉系统ArrayAdapter
与您获得的数据直接相关,并且您返回与您的数据相关联的ID(即使连接丢失)。这意味着,它将是一个数据的一个ID和不同数据的不同ID。
通知ListView的方式知道根据ID保持te位置。
编辑2:
我发现了你的错误。您的适配器从List<String>
延伸。这内部已经有getItem(position);
,当您致电List<String> objects;
时,数据来自该内部列表。
修复很简单。
add
并使用内部列表。要更新您从ArrayAdapter(https://developer.android.com/reference/android/widget/ArrayAdapter.html)调用addAll
,clear
和@Override
public void onDataUpdated(ArrayList<String> data) {
adapter.clear();
adapter.addAll(data);
adapter.notifyDataSetChanged();
}
方法的数据:
类似的东西:
tell application "Finder"
set srcPath to POSIX path of ((parent of (path to me) as text) & "M Templates")
set dstPath to POSIX path of (((path to movies folder) as text) & "M Templates")
duplicate entire contents of srcPath to dstPath
end tell