I have an app that has a ListView
with 15 rows. If there is a new query to search, I set adapter
to null
and clear Allvideos
variable and create a new one with
`new ArrayList();
And when user clicks to last row "more results" and I add items to Allvideos
. But after some searchings in my app and add that items to list, my app is being slow and when I try to scroll up it crashes. Here is my Adapter
public class VideosAdapter extends BaseAdapter {
// The list of videos to display
public static List<Video> videos;
// An inflator to use when creating rows
private LayoutInflater mInflater;
private Context context;
/**
* @param context this is the context that the list will be shown in - used to create new list rows
* @param videos this is a list of videos to display
*/
public VideosAdapter(Context context, List<Video> videos) {
VideosAdapter.videos = videos;
this.mInflater = LayoutInflater.from(context);
this.context = context;
}
@Override
public int getCount() {
return videos.size();
}
@Override
public Object getItem(int position) {
return videos.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public Object getItem(int position) {
return videos.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Video video = videos.get(position);
ViewHolder viewHolder;
if(video.getTitle()==null && video.getDuration()==-1)
{
convertView = mInflater.inflate(R.layout.more_results, null);
View thumbnail = convertView.findViewById(R.id.thumbnail);
thumbnail.setVisibility(View.INVISIBLE);
return convertView;
}
//animation = AnimationUtils.loadAnimation(context, R.anim.push_up_in);
// If convertView wasn't null it means we have already set it to our list_item_user_video so no need to do it again
else if(convertView == null){
convertView = mInflater.inflate(R.layout.list_item_user_video, null);
viewHolder = new ViewHolder();
viewHolder.thumb = (UrlImageView) convertView.findViewById(R.id.list_image);
viewHolder.duration=(TextView) convertView.findViewById(R.id.duration);
viewHolder.title = (TextView) convertView.findViewById(R.id.userVideoTitleTextView);
convertView.setTag(viewHolder);
}
else{
// we've just avoided calling findViewById() on resource everytime
// just use the viewHolder
viewHolder = (ViewHolder) convertView.getTag();
}
// We are using a custom imageview so that we can load images using urls
// For further explanation see: http://blog.blundell-apps.com/imageview-with-loading-spinner/
//TextView size=(TextView) convertView.findViewById(R.id.size);
int durationmin=video.getDuration()/60;
int durationsec=video.getDuration()%60;
if(durationsec<10) viewHolder.duration.setText(durationmin+":0"+durationsec);
else{
viewHolder.duration.setText(durationmin+":"+durationsec);
}
// thumb image
// Get a single video from our list
// Set the image for the list item
viewHolder.thumb.setImageDrawable(video.getThumbUrl());
// Set the title for the list item
//ytapi.com düzelene kadar böyle kalacak.
//size.setText(df.format(MainActivity.getSizeOf(MainActivity.getDownloadUrl(videoid)))+" MMB");
viewHolder.title.setText(video.getTitle());
/*animation.setDuration(1000);
convertView.startAnimation(animation);
animation = null;*/
return convertView;
}
I add items to list and set adapter with this code.
if(Allvideos.isEmpty())
{
Allvideos=videos;
}
else
{
//Remove extra more results row
Allvideos.remove(Allvideos.size()-1);
for(int i=0;i<videos.size();i++)
{
Allvideos.add(videos.get(i));
}
}
VideosAdapter adapter = new VideosAdapter(getContext(), Allvideos);
//adapter.notifyDataSetChanged();
setAdapter(adapter);
My logcat is like this.
08-22 15:53:40.557: E/InputEventReceiver(619): Exception dispatching input event.
08-22 15:53:40.657: E/AndroidRuntime(619): FATAL EXCEPTION: main
08-22 15:53:40.657: E/AndroidRuntime(619): java.lang.NullPointerException
08-22 15:53:40.657: E/AndroidRuntime(619): at com.skymaster.tut.ui.adapter.VideosAdapter.getView(VideosAdapter.java:108)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.AbsListView.obtainView(AbsListView.java:2255)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.ListView.makeAndAddView(ListView.java:1769)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.ListView.fillUp(ListView.java:706)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.ListView.fillGap(ListView.java:645)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5040)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3197)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3471)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.View.dispatchTouchEvent(View.java:7127)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2170)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1905)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1919)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1919)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1919)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2176)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1919)
08-22 15:53:40.657: E/AndroidRuntime(619): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1925)
08-22 15:53:40.657: E/AndroidRuntime(619): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1379)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.app.Activity.dispatchTouchEvent(Activity.java:2396)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.support.v7.app.ActionBarActivityDelegateICS$WindowCallbackWrapper.dispatchTouchEvent(ActionBarActivityDelegateICS.java:268)
08-22 15:53:40.657: E/AndroidRuntime(619): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1873)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.View.dispatchPointerEvent(View.java:7307)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3174)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3119)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4155)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4134)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4226)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4205)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4245)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.Choreographer.doFrame(Choreographer.java:523)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.os.Handler.handleCallback(Handler.java:615)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.os.Handler.dispatchMessage(Handler.java:92)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.os.Looper.loop(Looper.java:137)
08-22 15:53:40.657: E/AndroidRuntime(619): at android.app.ActivityThread.main(ActivityThread.java:4745)
08-22 15:53:40.657: E/AndroidRuntime(619): at java.lang.reflect.Method.invokeNative(Native Method)
08-22 15:53:40.657: E/AndroidRuntime(619): at java.lang.reflect.Method.invoke(Method.java:511)
08-22 15:53:40.657: E/AndroidRuntime(619): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
08-22 15:53:40.657: E/AndroidRuntime(619): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
08-22 15:53:40.657: E/AndroidRuntime(619): at dalvik.system.NativeStart.main(Native Method)
And error occurs at this line java:108 I take duration from site(video.getDuration()) and its in second type like 360 sec not 6 min.
duration.setText(durationmin+":"+durationsec);
For smooth scrolling i used ViewHolder
but it didn't solve my problem. As you see in my code there is URLIMAGEVIEW
in my layout for each row. With this item I load different images from url for each rows. And While image is loading spinner appears until loading is finished. Also URLIMAGEVIEW
is in another Thread
, not ui Thread
. Can URLIMAGEVIEW
be the reason of error or slow my app?
Why have videos as a static field; it is not necessary and it is a bad practice.
In addition, when displaying items from a list, consider extending ArrayAdapter
instead of BaseAdapter
; that way you will only need to overide getView; and not getPosition, getCount, etc.
if(Allvideos.isEmpty())
{
Allvideos=videos;
}
else
{
//Remove extra more results row
Allvideos.remove(Allvideos.size()-1);
Consider using a footer here instead of adding and removing the last item every time. As a bonus, it makes your getView method simpler.
for(int i=0;i<videos.size();i++)
{
Allvideos.add(videos.get(i));
You might want to look into the addAll method.
}
}
VideosAdapter adapter = new VideosAdapter(getContext(), Allvideos);
You do not need to recreate the adapter every time. Instead, do the following:
//fields
private ArrayList<Video> videos;
private ArrayAdapter mAdapter;
private View footer;
protected void onCreate(Bundle savedInstanceState) {
ListView list = findViewById(R.id.list);
footer = getLayoutInflater().inflate(R.layout.more_results, null);
list.addFooterView(footer);
videos = new ArrayList<Video>
mAdapter = new VideosAdapter(this, videos);
list.setAdapter(mAdapter);
}
public addItemsToList(List<Video> items){
videos.addAll(items);
mAdapter.notifyDataSetChanged();
}
As a bonus, the footer is always at the end of the list. You may toggle the visibility of the footer if you want to remove it, which is also nice.
Regarding your error; the problem will be fixed when you add the footer. The current problem is caused by your moreResults layout.
convertView = mInflater.inflate(R.layout.more_results, null);
View thumbnail = convertView.findViewById(R.id.thumbnail);
thumbnail.setVisibility(View.INVISIBLE);
return convertView;
Note that if your adapter tries to recycle this view next time around, convertView will not be null; however, no tag is set here. Thus, the nullPointerException occurs.