问题
In one of my past projects I implemented a "Time Picker Carousel". It is based on a HorizontalScrollView
. The user can pick a time while scrolling this view. The time value is calculated from the X-Offset of the HorizontalScrollView
.
I wanted to share this project at github, but while cleaning up the code I realized some bad performance issue.
The HorizontalScrollView
is populated with a custom ArrayAdapter
. The getView()
uses a Holder
for the convertView
. I thought it might work as an adapter within a ListView
, so only the visible items are rendered and reused if they will be destroyed. Instead, all items are rendered!!! (in my case 1008!) I add them myself (#1 in Code example), but even if I try to add less, the logic from remove (and recycle) old ones doesn't work, or did I miss something?
So my basic question is: What do I have to change to make my adapter behave like ListView
?
- I found this so link and tried overriding
remove
function, but this is never called (somehow logic, because i am only adding) - There's a good PagerAdapter example at github, but somehow I cannot translate this to
ArrayAdapter<String>
Any thoughts, links are welcome!
And please don't suggest using ListView
instead. We decided to use HorizontalScrollView
because of callbacks and the fact we already have a ListView
in the layout.
HorizontalScrollView
InfiniteTimeScrubberHorizontalView extends HorizontalScrollView{
...
public void setAdapter(Context context, TimeScrubberListAdapter mAdapter) {
this.mAdapter = mAdapter;
try {
fillViewWithAdapter(mAdapter);
} catch (ZeroChildException e) {
e.printStackTrace();
}
}
private void fillViewWithAdapter(TimeScrubberListAdapter mAdapter) {
//...
ViewGroup parent = (ViewGroup) getChildAt(0);
parent.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
//#1: Here: ALL views are added
parent.addView(mAdapter.getView(i, null, parent));
}
}
Adpater
public class TimeScrubberListAdapter extends ArrayAdapter<String> {
//...
private ArrayList<String> list; //list from 0:00,0:30...23:00,23:30
final static int MAXIMUM_DAYS = 21
@Override
public int getCount() {
return list.size() * MAXIMUM_DAYS;
}
@Override
public String getItem(int position) {
return list.get(position % list.size());
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
RelativeLayout layout;
if (convertView == null) {
layout = (RelativeLayout) View.inflate(context, layoutId, null);
holder = new Holder();
holder.title = (TextView) layout.findViewById(R.id.epg_item_text);
layout.setTag(holder);
} else {
layout = (RelativeLayout) convertView;
view = layout;
holder = (Holder) layout.getTag();
}
layout.setLayoutParams(mLP);
String timeValue = getItem(position);
holder.title.setText(timeValue);
return layout;
}
//...
@Override
public void remove(String object) {
//not called...some how logic, because i do not remove an item
super.remove(object);
}
回答1:
I think maybe you are confusing where the logic lies for rendering between View and Adapter. Using an Adapter does not cause view recycling behavior. It is the ListView
itself, along with its parent, AbsListView
, that implement the view recycling behavior. The Adapter is required by the ListView
in order to properly populate the Views that are shown on screen as needed, but the logic for actually choosing which Views to display and when and how to recycle those views is not in the Adapter at all.
If you look at the source code for HorizontalScrollView and for ListView, you will see that they are dramatically different. They are not just the same thing in different orientations.
So, the long and short of it is that you will not be able to get the view recycling that you are looking for by using a HorizontalScrollView
or even a simple descendent. If you want view recycling, you should check out the RecyclerView.
回答2:
ScrollView keeps all child views in memory, so performance issue is common while using them.
Why not use some open source HorizontalListView library. On searching I got these two libs out of which i have used first one in one of my projects and it worked smoothly without any memory issues.
Android-HorizontalListView
HorizontalVariableListView
These libs are horizontal implementation of ListView, which does recycling of items for you based on which views are visible on screen. Scrollview is bad choice for inifinite scrolling view.
UPDATE: Now we have RecyclerView from Android itself, which supports horizontal scrolling as well, it also enforces the use of Viewholder pattern
来源:https://stackoverflow.com/questions/26341587/horizontalscrollview-customadapter-with-getview-doesnt-reuse-convertviews-li