I have a list that gets refreshed every 2 seconds via the Handler postDelayed() method.
Every 2 seconds an AsyncTask is run that makes an HTTP GET request, turns the JSON into a list of objects, then sets the ListAdapter:
MyListAdapter adapter = new MyListAdapter(someObjects);
setListAdapter(adapter);
My problem is that every time the task completes (so, roughly every two seconds) my 开发者_开发技巧list jumps back to the top, even if I have scrolled down to the middle or bottom of the list. This would be very annoying to the end user, so I need the list to update in the background, as it's doing, but the current view of the list to not jump back to the top at the completion of the AsyncTask.
I can include any more code needed. I'm somewhat new to android development, so I'm not sure what is helpful to others.
Additional Information
Taking suggestions from hacksteak25, I'm able to get to the point where I try to remove all the data from the adapter, then add it back one object at a time. This isn't the end solution since this would probably still cause the screen to jump, but I'm trying to use it as a proof of concept for how I could merge the data at some point.
My problem is that I call the following code:
MyListAdapter adapter = (MyListAdapter)getListAdapter();
adapter.clear();
for(MyObject myObject : myObjects)
{
adapter.add(myObject);
}
After the first call to "add(myObject)" the getView() method of the MyListAdapter is being called. The private internal ArrayList of the custom adapter is empty at this point, either because I set the adapter with no myObjects in onCreate() or because I called clear() on the adapter, I'm not sure. Either way, this causes getView to fail since there are no objects in the ArrayList to be getting the view from.
getView() looks like this:
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
LayoutInflater mInflater = getLayoutInflater();
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.myObject, null);
holder = new ViewHolder();
holder.someProperty = (TextView)convertView.findViewById(R.id.someProperty);
holder.someOtherProperty = (TextView)convertView.findViewById(R.id.someOtherProperty);
holder.someOtherOtherProperty = (TextView)convertView.findViewById(R.id.someOtherOtherProperty);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.someProperty.setText( mObjects.get(position).getSomeProperty());
...
That last line is the one that causes an IndexOutOfBoundsException.
How should I handle this situation where I get the data I want in there without causing the list to jump?
I think the preferred way is to update the adapter itself and not to replace it. Maybe you can write a method that merges the new and old data using the adapters insert()
and remove()
methods. I think that should keep your position.
Added Information:
I use the following as basic structure. Maybe it helps.
public class PlaylistAdapter extends ArrayAdapter<Playlist> {
private ArrayList<Playlist> items;
public PlaylistAdapter(Context context, int textViewResourceId, ArrayList<Playlist> items) {
super(context, textViewResourceId, items);
this.items = items;
}
}
精彩评论