I have a FragmentStatePagerAdapter with a Listview in each page. The FragmentStatePagerAdapter is being refreshed once every second with new data for some of his pages (remember that each page is a listview).
I set the content of the listview with setAdapter:
StableArrayAdapter adapter = new StableArrayAdapter((MainActivity) getActivity(), R.layout.list_view_item, ((MainActivity) getActivity()).getData(mPage));
listView.setAdapter(adapter);
The problem is that some pages has a lot of content and a vertical scroll, so every second when listView.setAdapter(adapter);
is being called, the scroll of the listview is forced to his upper position. It is a very abnormal and annoying behaviour.
I find this on Stack Overflow: notifyDataSetChanged() makes the list refresh and scroll jumps back to the top
The problem is that these solutions are designed for a normal ViewPager or normal Adapter and can't work with FragmentStatePageAdapter or something, because after trying them I still have the same problem.
This is my adapter for the 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];
}
}
The ViewPager which has the problem:
<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>
Layout of the fragment:
<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>
The Java code for the fragment:
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);
}
}
When the content of the fragment (which is a listview) needs to be updated, the method onDataUpdated is called with the new content received in the parameter.
Edit
Adding adapter which generates a crash, using the code samples from 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;
}
}
Edit 2
New adapter trying to use Budius solution. But it does not work. The content is not being refreshed.
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;
}
}