Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Optimizing Android UI: Pro tips for creating sm...

Optimizing Android UI: Pro tips for creating smooth and responsive apps

A talk I gave at the Lyon Android User Group. It covered some useful tips and tricks to create smooth and responsive applications.

If you didn't [hear|see] the talk, these slides probably won't make sense.

Software: Keynote, Illustrator, Photoshop, Eclipse
Font: Arvo (http://www.google.com/webfonts/specimen/Arvo)
Colors: #1c5c82, #3ba3f4, #ffffff, #c0c0c0, #ae0000

Cyril Mottier

July 05, 2012
Tweet

More Decks by Cyril Mottier

Other Decks in Programming

Transcript

  1. HashMap< , String> hashMap = new HashMap< , String>(); hashMap.put(665,

    "Android"); hashMap.put(666, "rocks"); hashMap.get(666); Integer Integer Integer is not int
  2. QUESTION Would the result have been the same if we

    had been trying to add ″Android″ with 42 as key?
  3. QUESTION Would the result have been the same if we

    had been trying to add ″Android″ with 42 as key? ANSWER Yes 42 is the answer to the Java universe
  4. QUESTION Would the result have been the same if we

    had been trying to add ″Android″ with 42 as key? ANSWER Yes 42 is the anwser to the Java universe I AM JOKING
  5. QUESTION Would the result have been the same if we

    had been trying to add ″Android″ with 42 as key? ANSWER No Integer has an internal cache for [-128, 127]
  6. SparseArray: SparseArrays map integers to Objects. Unlike a normal array

    of Objects, there can be gaps in the indices. It is intended to be more efficient than using a HashMap to map Integers to Objects.
  7. @Override public View getView(int position, View convertView, ViewGroup parent) {

    final View itemView = mInflater.inflate( android.R.layout.two_line_list_item, // resource parent, // parent false); // attach ((TextView) itemView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) itemView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return itemView; } NEVER DO THIS !!!
  8. @Override public View getView(int position, View convertView, ViewGroup parent) {

    ((TextView) itemView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) itemView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return itemView; } NEVER DO THIS !!! android.R.layout.two_line_list_item, // resource false); // attach final View itemView = mInflater.inflate( parent, // parent inflate a new View at every getView call
  9. convertView: The old view to reuse, if possible. Note: You

    should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.
  10. (RE)USE THE CONVERTVIEW @Override public View getView(int position, View convertView,

    ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, // resource parent, // parent false); // attach } ((TextView) convertView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) convertView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return convertView; }
  11. (RE)USE THE CONVERTVIEW @Override public View getView(int position, View convertView,

    ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, // resource parent, // parent false); // attach } ((TextView) convertView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) convertView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return convertView; } check for a convertView
  12. (RE)USE THE CONVERTVIEW @Override public View getView(int position, View convertView,

    ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, // resource parent, // parent false); // attach } ((TextView) convertView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) convertView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return convertView; } create a view only when necessary check for a convertView
  13. private static final int MSG_ANIMATION_FRAME = 0xcafe; public void sendMessage(Handler

    handler, Object userInfo) { final Message message = new Message(); message.what = MSG_ANIMATION_FRAME; message.obj = userInfo; handler.sendMessage(message); }
  14. private static final int MSG_ANIMATION_FRAME = 0xcafe; public void sendMessage(Handler

    handler, Object userInfo) { final Message message = Message(); message.what = MSG_ANIMATION_FRAME; message.obj = userInfo; handler.sendMessage(message); } new creation of a new Message instance
  15. private static final int MSG_ANIMATION_FRAME = 0xcafe; public void sendMessage(Handler

    handler, Object userInfo) { final Message message = Message.obtain(); message.what = MSG_ANIMATION_FRAME; message.obj = userInfo; handler.sendMessage(message); }
  16. private static final int MSG_ANIMATION_FRAME = 0xcafe; public void sendMessage(Handler

    handler, Object userInfo) { final Message message = Message.obtain(); message.what = MSG_ANIMATION_FRAME; message.obj = userInfo; handler.sendMessage(message); } try to reuse Message instances Message.obtain(): Gets an object from a pool or create a new one
  17. Want this in your app? Go to github.com/android/platform_frameworks_base Find android.util

    Copy PoolableManager, Pool, Poolable, Pools, FinitePool, etc. Paste in your project Enjoy the easy-to-use object pooling mechanism
  18. @Override public boolean onInterceptTouchEvent(MotionEvent event) { final int x =

    (int) event.getX(); final int y = (int) event.getY(); final Rect frame = new Rect(); // Are we touching mHost ? mHost.getHitRect(frame); if (!frame.contains(x, y)) { return false; } return true; }
  19. @Override public boolean onInterceptTouchEvent(MotionEvent event) { final int x =

    (int) event.getX(); final int y = (int) event.getY(); final Rect frame = Rect(); // Are we touching mHost ? mHost.getHitRect(frame); if (!frame.contains(x, y)) { return false; } return true; } creation of a new Rect instance new
  20. private final Rect mFrameRect = new Rect(); @Override public boolean

    onInterceptTouchEvent(MotionEvent event) { final int x = (int) event.getX(); final int y = (int) event.getY(); final Rect frame = mFrameRect; // Are we touching mHost ? mHost.getHitRect(frame); if (!frame.contains(x, y)) { return false; } return true; }
  21. private final Rect mFrameRect = new Rect(); @Override public boolean

    onInterceptTouchEvent(MotionEvent event) { final int x = (int) event.getX(); final int y = (int) event.getY(); final Rect frame = mFrameRect; // Are we touching mHost ? mHost.getHitRect(frame); if (!frame.contains(x, y)) { return false; } return true; } create a single Rect
  22. private final Rect mFrameRect = new Rect(); @Override public boolean

    onInterceptTouchEvent(MotionEvent event) { final int x = (int) event.getX(); final int y = (int) event.getY(); final Rect frame = mFrameRect; // Are we touching mHost ? mHost.getHitRect(frame); if (!frame.contains(x, y)) { return false; } return true; } create a single Rect always use the same instance of Rect
  23. public class CharArrayBufferAdapter extends CursorAdapter { private interface DataQuery {

    int TITLE = 0; int SUBTITLE = 1; } public CharArrayBufferAdapter(Context context, Cursor c) { super(context, c); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; item.getText1().setText(cursor.getString(DataQuery.TITLE)); item.getText2().setText(cursor.getString(DataQuery.SUBTITLE)); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); } }
  24. public class CharArrayBufferAdapter extends CursorAdapter { private interface DataQuery {

    int TITLE = 0; int SUBTITLE = 1; } public CharArrayBufferAdapter(Context context, Cursor c) { super(context, c); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; item.getText1().setText( ); item.getText2().setText( ); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); } } cursor.getString(DataQuery.TITLE) cursor.getString(DataQuery.SUBTITLE) getString means new String
  25. private static class ViewHolder { CharArrayBuffer titleBuffer = new CharArrayBuffer(128);

    CharArrayBuffer subtitleBuffer = new CharArrayBuffer(128); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; final ViewHolder holder = (ViewHolder) view.getTag(); final CharArrayBuffer titleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.TITLE, titleBuffer); item.getText1().setText(titleBuffer.data, 0, titleBuffer.sizeCopied); final CharArrayBuffer subtitleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.SUBTITLE, subtitleBuffer); item.getText2().setText(subtitleBuffer.data, 0, subtitleBuffer.sizeCopied); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View v = LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); v.setTag(new ViewHolder()); return v; }
  26. private static class ViewHolder { CharArrayBuffer titleBuffer = new CharArrayBuffer(128);

    CharArrayBuffer subtitleBuffer = new CharArrayBuffer(128); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; final ViewHolder holder = (ViewHolder) view.getTag(); final CharArrayBuffer titleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.TITLE, titleBuffer); item.getText1().setText(titleBuffer.data, 0, titleBuffer.sizeCopied); final CharArrayBuffer subtitleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.SUBTITLE, subtitleBuffer); item.getText2().setText(subtitleBuffer.data, 0, subtitleBuffer.sizeCopied); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View v = LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); v.setTag(new ViewHolder()); return v; } attach buffers to the itemview
  27. private static class ViewHolder { CharArrayBuffer titleBuffer = new CharArrayBuffer(128);

    CharArrayBuffer subtitleBuffer = new CharArrayBuffer(128); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; final ViewHolder holder = (ViewHolder) view.getTag(); final CharArrayBuffer titleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.TITLE, titleBuffer); item.getText1().setText(titleBuffer.data, 0, titleBuffer.sizeCopied); final CharArrayBuffer subtitleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.SUBTITLE, subtitleBuffer); item.getText2().setText(subtitleBuffer.data, 0, subtitleBuffer.sizeCopied); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View v = LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); v.setTag(new ViewHolder()); return v; } attach buffers to the itemview get the buffers
  28. private static class ViewHolder { CharArrayBuffer titleBuffer = new CharArrayBuffer(128);

    CharArrayBuffer subtitleBuffer = new CharArrayBuffer(128); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; final ViewHolder holder = (ViewHolder) view.getTag(); final CharArrayBuffer titleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.TITLE, titleBuffer); item.getText1().setText(titleBuffer.data, 0, titleBuffer.sizeCopied); final CharArrayBuffer subtitleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.SUBTITLE, subtitleBuffer); item.getText2().setText(subtitleBuffer.data, 0, subtitleBuffer.sizeCopied); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View v = LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); v.setTag(new ViewHolder()); return v; } attach buffers to the itemview get the buffers copy column content to buffer
  29. private static class ViewHolder { CharArrayBuffer titleBuffer = new CharArrayBuffer(128);

    CharArrayBuffer subtitleBuffer = new CharArrayBuffer(128); } @Override public void bindView(View view, Context context, Cursor cursor) { final TwoLineListItem item = (TwoLineListItem) view; final ViewHolder holder = (ViewHolder) view.getTag(); final CharArrayBuffer titleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.TITLE, titleBuffer); item.getText1().setText(titleBuffer.data, 0, titleBuffer.sizeCopied); final CharArrayBuffer subtitleBuffer = holder.titleBuffer; cursor.copyStringToBuffer(DataQuery.SUBTITLE, subtitleBuffer); item.getText2().setText(subtitleBuffer.data, 0, subtitleBuffer.sizeCopied); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View v = LayoutInflater.from(context).inflate( android.R.layout.two_line_list_item, parent, false); v.setTag(new ViewHolder()); return v; } attach buffers to the itemview get the buffers set the buffer to the TextView copy column content to buffer
  30. 2 RelativeLayout A Layout where the positions of the children

    can be described in relation to each other or to the parent.
  31. 2 RelativeLayout A Layout where the positions of the children

    can be described in relation to each other or to the parent. Flatten hierarchy
  32. 3 <merge /> <?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"

    android:src="@drawable/icon" /> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" />
  33. 3 <merge /> <?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"

    android:src="@drawable/icon" /> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" /> INVALID XML DOCUMENT
  34. 3 <merge /> <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"

    > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" /> </FrameLayout>
  35. 3 <merge /> <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"

    > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" /> </FrameLayout> useless ViewGroup
  36. 3 <merge /> <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:src="@drawable/icon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" /> </merge>
  37. public class UnderlinedTextView extends TextView { private final Paint mPaint

    = new Paint(); private int mUnderlineHeight; public UnderlinedTextView(Context context) { super(context); } public UnderlinedTextView(Context context, AttributeSet attrs) { super(context, attrs); } public UnderlinedTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } }
  38. public class UnderlinedTextView extends TextView { private final Paint mPaint

    = new Paint(); private int mUnderlineHeight; public UnderlinedTextView(Context context) { super(context); } public UnderlinedTextView(Context context, AttributeSet attrs) { super(context, attrs); } public UnderlinedTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } } extends TextView
  39. @Override public void setPadding(int left, int top, int right, int

    bottom) { super.setPadding(left, top, right, mUnderlineHeight + bottom); } public void setUnderlineHeight(int underlineHeight) { if (underlineHeight < 0) underlineHeight = 0; if (underlineHeight != mUnderlineHeight) { mUnderlineHeight = underlineHeight; setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + mUnderlineHeight); } } public void setUnderlineColor(int underlineColor) { if (mPaint.getColor() != underlineColor) { mPaint.setColor(underlineColor); invalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint); }
  40. @Override public void setPadding(int left, int top, int right, int

    bottom) { super.setPadding(left, top, right, mUnderlineHeight + bottom); } public void setUnderlineHeight(int underlineHeight) { if (underlineHeight < 0) underlineHeight = 0; if (underlineHeight != mUnderlineHeight) { mUnderlineHeight = underlineHeight; setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + mUnderlineHeight); } } public void setUnderlineColor(int underlineColor) { if (mPaint.getColor() != underlineColor) { mPaint.setColor(underlineColor); invalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint); } use padding to avoid measurements use padding to avoid measurements
  41. @Override public void setPadding(int left, int top, int right, int

    bottom) { super.setPadding(left, top, right, mUnderlineHeight + bottom); } public void setUnderlineHeight(int underlineHeight) { if (underlineHeight < 0) underlineHeight = 0; if (underlineHeight != mUnderlineHeight) { mUnderlineHeight = underlineHeight; setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom() + mUnderlineHeight); } } public void setUnderlineColor(int underlineColor) { if (mPaint.getColor() != underlineColor) { mPaint.setColor(underlineColor); invalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint); } extend TextView default behavior use padding to avoid measurements use padding to avoid measurements
  42. DEVELOPERS TEND TO BE «NEVER SATISFIED» PEOPLE THAT ARE ALWAYS

    ASKING FOR MORE ASSERTION Yep, this is the exact same definition of «being French»
  43. @Override public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, // resource parent, // parent false); // attach } ((TextView) convertView.findViewById(android.R.id.text1)) .setText(TITLES.get(position)); ((TextView) convertView.findViewById(android.R.id.text2)) .setText(SUBTITLES.get(position)); return convertView; } DO YOU REMEMBER THIS?
  44. @Override public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, parent, false); holder = new ViewHolder(); holder.text1 = (TextView) convertView.findViewById(android.R.id.text1); holder.text2 = (TextView) convertView.findViewById(android.R.id.text2); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text1.setText(STRINGS.get(position)); holder.text2.setText(STRINGS.get(position)); return convertView; } AVOID REPETITIVE EXECUTIONS
  45. @Override public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, parent, false); holder = new ViewHolder(); holder.text1 = (TextView) convertView.findViewById(android.R.id.text1); holder.text2 = (TextView) convertView.findViewById(android.R.id.text2); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text1.setText(STRINGS.get(position)); holder.text2.setText(STRINGS.get(position)); return convertView; } AVOID REPETITIVE EXECUTIONS cache refs to the children
  46. @Override public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, parent, false); holder = new ViewHolder(); holder.text1 = (TextView) convertView.findViewById(android.R.id.text1); holder.text2 = (TextView) convertView.findViewById(android.R.id.text2); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text1.setText(STRINGS.get(position)); holder.text2.setText(STRINGS.get(position)); return convertView; } AVOID REPETITIVE EXECUTIONS cache refs to the children retrieve cached refs
  47. @Override public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate( android.R.layout.two_line_list_item, parent, false); holder = new ViewHolder(); holder.text1 = (TextView) convertView.findViewById(android.R.id.text1); holder.text2 = (TextView) convertView.findViewById(android.R.id.text2); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text1.setText(STRINGS.get(position)); holder.text2.setText(STRINGS.get(position)); return convertView; } AVOID REPETITIVE EXECUTIONS cache refs to the children retrieve cached refs use cached refs
  48. private static final int MSG_LOAD = 0xbeef; private Handler mHandler

    = new Handler(Looper.getMainLooper()); public void loadUrl(final String url) { new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); InputStream i = null; Bitmap b = null; try { i = new URL(url).openStream(); b = BitmapFactory.decodeStream(i); } catch (Exception e) { } finally { if (i != null) try { i.close(); } catch (IOException e) {} } Message.obtain(mHandler, MSG_LOAD, b).sendToTarget(); } }).start(); }
  49. private static final int MSG_LOAD = 0xbeef; private Handler mHandler

    = new Handler(Looper.getMainLooper()); public void loadUrl(final String url) { new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); InputStream i = null; Bitmap b = null; try { i = new URL(url).openStream(); b = BitmapFactory.decodeStream(i); } catch (Exception e) { } finally { if (i != null) try { i.close(); } catch (IOException e) {} } Message.obtain(mHandler, MSG_LOAD, b).sendToTarget(); } }).start(); } set a low priority
  50. private static final int MSG_LOAD = 0xbeef; private Handler mHandler

    = new Handler(Looper.getMainLooper()); public void loadUrl(final String url) { new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); InputStream i = null; Bitmap b = null; try { i = new URL(url).openStream(); b = BitmapFactory.decodeStream(i); } catch (Exception e) { } finally { if (i != null) try { i.close(); } catch (IOException e) {} } Message.obtain(mHandler, MSG_LOAD, b).sendToTarget(); } }).start(); } set a low priority post a Message to callback the UI Thread
  51. SCROLL STATES 3 ListView can have The current ListView’s scroll

    state can be obtained using an OnScrollListener
  52. 3FLING The user had previously been scrolling using touch and

    had performed a fling. The animation is now coasting to a stop Avoid blocking the animation pause worker Threads
  53. getListView().setOnScrollListener(mScrollListener); private OnScrollListener mScrollListener = new OnScrollListener() { @Override public

    void onScrollStateChanged(AbsListView view, int scrollState) { ImageLoader imageLoader = ImageLoader.get(getContext()); imageLoader.setPaused(scrollState == OnScrollListener.SCROLL_STATE_FLING); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // Nothing to do } };
  54. getListView().setOnScrollListener(mScrollListener); private OnScrollListener mScrollListener = new OnScrollListener() { @Override public

    void onScrollStateChanged(AbsListView view, int scrollState) { ImageLoader imageLoader = ImageLoader.get(getContext()); imageLoader.setPaused(scrollState == OnScrollListener.SCROLL_STATE_FLING); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // Nothing to do } }; set the listener
  55. getListView().setOnScrollListener(mScrollListener); private OnScrollListener mScrollListener = new OnScrollListener() { @Override public

    void onScrollStateChanged(AbsListView view, int scrollState) { ImageLoader imageLoader = ImageLoader.get(getContext()); imageLoader.setPaused(scrollState == OnScrollListener.SCROLL_STATE_FLING); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // Nothing to do } }; (un)pause ImageLoader set the listener