Loading list item at top of listview without losing scroll position

It seemed very easy for me when I started doing it. But later I realised it is no more easy. Adding an item in listview is an ordinary process but keeping the scroll position is a challenge. I did a small research on this but could not find any thing useful. Until I encountered this SO post. It directed me to this amazing link of Chris banes. The following video shows the required final output I achieved.

Problem,

Whenever we add an item and call

adapter.notifyDataSetChanged();

it refresh the listview with new items and hence we lose our current scroll position.

Solution,

While adding new item into a listview, inorder to stop flicking scroll position we need to block laying out children layout of listview. This can be achieved by creating a custom listview.

public class StoryListView extends ListView {

    private boolean blockLayoutChildren;

    public StoryListView(Context context) {
        super(context);
    }

    public StoryListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setBlockLayoutChildren(boolean blockLayoutChildren) {
        this.blockLayoutChildren = blockLayoutChildren;
    }

    @Override
    protected void layoutChildren() {
        if (!blockLayoutChildren) {
            super.layoutChildren();
        }
    }
}

All we need is to set and unset

blockLayoutChildren

boolean while adding an item.

//    get first visible position of the list view
int firstVisPos = listView.getFirstVisiblePosition();

//    get child view at visible 0th position of the listview
View firstVisView = listView.getChildAt(0);

//    set top in pixel of the child view
int top = firstVisView != null ? firstVisView.getTop() : 0;

//    block from laying child layout
listView.setBlockLayoutChildren(true);

//    add new item to the collection
items.add(0, "New Story " + count++);

//    no. of items added in list before firstVisible item - it is '1' in our case
int itemsAddedBeforeFirstVisible = 1;

//    notify the adapter
adapter.notifyDataSetChanged();

//    un block from laying child layout
listView.setBlockLayoutChildren(false);

//    finally set item selection
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
listView.setSelectionFromTop(firstVisPos + itemsAddedBeforeFirstVisible, top);
} else {
listView.setSelection(firstVisPos + itemsAddedBeforeFirstVisible);
}

Code above is self explanatory. The full source code is available in GitHub.

Happy Coding!

Advertisements

How to track App-crash in Android?

I would say it is a million dollar question, since there is no call back to trace app crashes in Android. I had spent much time on figuring out this. But any how, two of my colleagues found a way to trace it (it’s great!!). Here am sharing it as a reference to all.

Step 1 :

Application class is the first to be executed during app launch. Hence we chose to track App-crash in it. The code below, returns the default exception handler that’s executed when uncaught exception terminates a thread.

Thread.UncaughtExceptionHandler defaultSystemHandler = Thread.getDefaultUncaughtExceptionHandler();

Step 2 :

The code below, sets the default uncaught exception handler. This handler is invoked in case any Thread dies due to an un handled exception.

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
System.out.println("Ouch! crashed!!!!"); // do your stuff here
if (defaultSystemHandler != null) {
defaultSystemHandler.uncaughtException(thread, ex); // pass the terminating thread and exception to defaultSystemHandler
} else {
android.os.Process.killProcess(android.os.Process.myPid()) // kill app like iOS when crashed
}
} catch (Exception e) {
e.printStackTrace();
defaultSystemHandler.uncaughtException(thread, ex); // pass the terminating thread and exception to defaultSystemHandler
}
}
});

That’s it.!
Happy coding!