MEK Web Solution MEK Web Solution - 5 months ago 43
Android Question

Android ListView resets scrolling state when updating its data

I try to updating data based on listview scrolling. The data is updating well. But after updating data, the listview went to top. I need to keep it same. I tried lot from stockoverflow. Nothing helps. I think i did mistake in my code. Please help me to solve.

My Code is:

public class ViewAll extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_all);

new GetMessage().execute();

FinalMessage = new ArrayList<HashMap<String, String>>();

ProgressBar footer = new ProgressBar(this);
ListView lv = (ListView) findViewById(listView);
lv.addFooterView(footer);
}

private void getMessageFromUrl()
{

new GetMessage().execute();
}

private class GetMessage extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
......
}

@Override
protected Void doInBackground(Void... arg0)
{
ServiceHandler sh = new ServiceHandler();
nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("page",String.valueOf(page)));
String jsonStr = sh.makeServiceCall(url, ServiceHandler.POST, nameValuePairs);
Log.d("Response: ", "> " + jsonStr);
if (jsonStr != null) {
try {
......
}
}
catch (JSONException e)
{
e.printStackTrace();
}
}
else
{
Log.e("SericeHandler","Couldn't get any data from url");
}
return null;
}

@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);


runOnUiThread(new Runnable() {
public void run() {

if(dorefresh==1)
{
ListView lv = (ListView) findViewById(listView);
Customlistadapter adapter = new Customlistadapter(ViewAll.this, title1, msg1);
lv.setAdapter(adapter);
int index = lv.getFirstVisiblePosition();
View v = lv.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
lv.setSelectionFromTop(index, top);

page = page + 1;
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
int currentVisibleItemCount;
int currentScrollState;
int currentFirstVisibleItem;
int totalItem;

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
this.currentScrollState = scrollState;
this.isScrollCompleted();
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
this.currentFirstVisibleItem = firstVisibleItem;
this.currentVisibleItemCount = visibleItemCount;
this.totalItem = totalItemCount;
}

private void isScrollCompleted() {

if (totalItem - currentFirstVisibleItem == currentVisibleItemCount
&& this.currentScrollState == SCROLL_STATE_IDLE) {
getMessageFromUrl();
}
}
});
Toast.makeText(ViewAll.this, "Updated", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(ViewAll.this, "No More Messages", Toast.LENGTH_SHORT).show();
}



}

});
}

}
}


CustomlistAdapter.java

public class Customlistadapter extends ArrayAdapter<String> {
ArrayList<String> title;
ArrayList<String> msg;
Context context;
public Customlistadapter(Activity context, ArrayList<String> text, ArrayList<String> msgView) {
super(context, R.layout.list_row, text);
// TODO Auto-generated constructor stub
this.title = text;
this.msg = msgView;
this.context = context;
}

public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View single_row = inflater.inflate(R.layout.list_row, null,
true);
TextView textView = (TextView) single_row.findViewById(R.id.title);
TextView msgView = (TextView) single_row.findViewById(R.id.msgView);
textView.setText(title.get(position));
msgView.setText(msg.get(position));

return single_row;
}

}

Answer

Your problem is that you create a new Customlistadapter each time you update the data. If you want the ListView to keep its scrolling state, you have to reuse the adapter. Just change the data in the adapter and call myAdapter.notifyDataSetChanged().

E.g. if your Adapter is an ArrayAdapter you could do this like:

ArrayAdapter adapter = (ArrayAdapter)listView.getAdapter();
adapter.clear();
adapter.addAll(newData);
adapter.notifyDataSetChanged();