[EDIT] code updated
I have a listview which going to have about 100-200 rows, I’have created a AsyncTask class which loads the data from server side using http request and because there is many items I decided to load 10 items/call, and display them in the list and let the user to interact with them while I call the AsyncTask class again to load more 10 items….
Here is the design of the listview (photoshop)
It works great BUT when the listview is being updated it’s NOT responding for few moments to scroll, and then it responds good and then it’s being updated again and it’s not responding for few moments…till it fully loaded from server side. I also tried RUNNABLE thread but the same behavior 🙁
How can I populate the listview SMOOTHLY and let the user interact with it while it’s populating.
class DBreadInvItems extends AsyncTask<Void, Void, String> {
Connection dbConnection = null;
Statement statement = null;
ResultSet resultSet = null;
ImageView splash;
CstmrInvoice activity;
JSONObject jObj;
String phpResult;
String db;
ItemsDialog itemsdialog;
Integer ttl_read=0;
//----------------------------------------------------------------------------------------------
protected DBreadInvItems(CstmrInvoice a,ItemsDialog itemsdialog) {
this.activity = a;
this.itemsdialog=itemsdialog;
Intent iin= this.activity.getIntent();
Bundle b = iin.getExtras();
db = b.getString("db");
}
//----------------------------------------------------------------------------------------------
@Override
protected void onPreExecute() {
phpResult="";
AnimateImgLoad();
}
//----------------------------------------------------------------------------------------------
@Override
protected String doInBackground(Void... params) {
fetchitems();
return null;
}
//----------------------------------------------------------------------------------------------
@Override
protected void onPostExecute(String result) {
if(phpResult.equals(""))
{
Toast.makeText(itemsdialog.dialog.getContext(), R.string.msg_nointernet, Toast.LENGTH_LONG).show();
return;
}
else
{
if(ttl_read>=10) {
itemsdialog.adapter_items.notifyDataSetChanged();
itemsdialog.finalData = itemsdialog.list_items;
itemsdialog.setListViewHeightBasedOnChildren((ListView) itemsdialog.dialog.findViewById(R.id.listViewInvPopupItems));
//try reading more...
AnimateImgLoad();
itemsdialog.ReadMoreData();
}
}
AnimateImgLoad();
}
//----------------------------------------------------------------------------------------------
private void fetchitems()
{
try
{
JSONObject json=new JSONObject();
json.put("db",db);
json.put("action","fetchitems");
json.put("seq",itemsdialog.SEQ.toString());
HttpParams httpparams= new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpparams, 10000);
HttpClient client=new DefaultHttpClient(httpparams);
String url="http://roya4u.com:8972/roya/invoices.php";
HttpPost request=new HttpPost(url);
request.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8")));
request.setHeader("json",json.toString());
HttpResponse response=client.execute(request);
HttpEntity entity=response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
phpResult= RestClient.convertStreamToString(instream);
}
}
catch (Throwable t)
{
}
if(phpResult.equals(""))
{
//Toast.makeText(itemsdialog.dialog.getContext(), R.string.msg_nointernet, Toast.LENGTH_LONG).show();
return;
}
try
{
JSONObject object = new JSONObject(phpResult);
final String islogged = object.getString("success");
if(Boolean.valueOf(islogged))//success=true
{
ttl_read=Integer.parseInt(object.getString("total").toString());
if(ttl_read>0) {
itemsdialog.SEQ = Integer.parseInt(object.getString("seq"));
//Toast.makeText(itemsdialog.dialog.getContext(),itemsdialog.SEQ, Toast.LENGTH_SHORT).show();
for (int i = 0; i < object.getJSONArray("items").length(); i++) {
JSONObject j = object.getJSONArray("items").optJSONObject(i);
itemsdialog.list_items.add(new MyInvoiceItems(Integer.parseInt(j.get("id").toString()), j.get("mkat").toString(), 1, Double.parseDouble(j.get("ccost").toString()), j.get("iname").toString(), 0));
}
}
}
else
{
//Toast.makeText(itemsdialog.dialog.getContext(), R.string.msg_errorlogin, Toast.LENGTH_LONG).show();
}
}
catch (JSONException e)
{
//Toast.makeText(itemsdialog.dialog.getContext(),R.string.msg_nointernet, Toast.LENGTH_LONG).show();
}
}
//----------------------------------------------------------------------------------------------
//------------------------------
private void AnimateImgLoad()
{
RotateAnimation anim;
if(splash==null)
{
anim = new RotateAnimation(0f, 360f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
anim.setInterpolator(new LinearInterpolator());
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(700);
//Start animating the image
splash = (ImageView) itemsdialog.dialog.findViewById(R.id.imgReload);
splash.startAnimation(anim);
ProgressBar progressbar=(ProgressBar) itemsdialog.dialog.findViewById(R.id.invPopupProgressBar);
progressbar.setVisibility(View.VISIBLE);
}
else
{
splash.setAnimation(null);
splash=null;
ProgressBar progressbar=(ProgressBar) itemsdialog.dialog.findViewById(R.id.invPopupProgressBar);
progressbar.setVisibility(View.GONE);
}
}
}
ADAPTER:
public class SearchableItemsAdapter extends BaseAdapter implements Filterable
{
ArrayList<MyInvoiceItems> filteredData = new ArrayList<MyInvoiceItems>();
private ItemFilter mFilter;
private LayoutInflater mInflater;
//
public SearchableItemsAdapter(Context context, ArrayList<MyInvoiceItems> data) {
filteredData = data;
mInflater = LayoutInflater.from(context);
}
//
public int getCount() {
return filteredData.size();
}
//
public Object getItem(int position) {
return filteredData.get(position);
}
//
public long getItemId(int position) {
return position;
}
//
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolderItems itemsholder;
if(convertView==null)
{
convertView=mInflater.inflate(R.layout.lstcstmrinvoicepopupitems,null);
itemsholder=new ViewHolderItems();
itemsholder.iTaken=(CheckBox) convertView.findViewById(R.id.inv_popupTaken);
itemsholder.iName=(TextView) convertView.findViewById(R.id.inv_popupName);
itemsholder.iQuan=(EditText) convertView.findViewById(R.id.inv_popupQuan);
itemsholder.iPrice=(EditText) convertView.findViewById(R.id.inv_popupPrice);
itemsholder.iTotal=(TextView) convertView.findViewById(R.id.inv_popupTotal);
convertView.setTag(itemsholder);
}
else
{
itemsholder=(ViewHolderItems) convertView.getTag();
}
if(filteredData!=null) {
itemsholder.iTaken.setChecked(false);
if (filteredData.get(position).getTaken() == 1)
itemsholder.iTaken.setChecked(true);
itemsholder.iName.setText(filteredData.get(position).getItem_desc());
itemsholder.iQuan.setText(filteredData.get(position).getItem_num().toString());
itemsholder.iPrice.setText(filteredData.get(position).getItem_cost().toString());
itemsholder.iTotal.setText(filteredData.get(position).getAmountTotal());
}
return convertView;
}
//
public class ViewHolderItems {
CheckBox iTaken;
TextView iName;
EditText iQuan;
EditText iPrice;
TextView iTotal;
}
//
public Filter getFilter() {
if(mFilter==null) mFilter = new ItemFilter();
return mFilter;
}
//
private class ItemFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
//validate
if(filterString.toString().trim().equals(""))
{
results.values = list_items;
results.count = list_items.size();
}
else
{
ArrayList<MyInvoiceItems> tempData =list_items;
finalData = new ArrayList<MyInvoiceItems>();
//mhmd
int count = tempData.size();
String filterableString ;
for (int i = 0; i < count; i++) {
filterableString = tempData.get(i).getItem_desc();
if (filterableString.toLowerCase().contains(filterString)) {
finalData.add(new MyInvoiceItems(tempData.get(i).getItem_key(),tempData.get(i).getItem_mkat(),tempData.get(i).getItem_num(),tempData.get(i).getItem_cost(),tempData.get(i).getItem_desc(),tempData.get(i).getTaken()));
}
}
results.values = finalData;
results.count = finalData.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
filteredData =(ArrayList<MyInvoiceItems>) results.values;
notifyDataSetChanged();
}
}
}
popup_invitems.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#ffe3e3e3">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="48dp"
android:id="@+id/tbl_mainTitle"
android:background="#ffffffff">
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_searchIcon"
android:layout_alignParentRight="false"
android:layout_marginTop="8dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="8dp">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imgReload"
android:src="@drawable/ic_reload" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="false"
android:id="@+id/tbl_txtName"
android:layout_marginTop="11dp"
android:layout_marginRight="4dp"
android:layout_toLeftOf="@+id/tbl_sort">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="45dp"
android:layout_height="wrap_content"
android:text="@string/inv_popup_itemname_title"
android:singleLine="true"
android:id="@+id/txtName"
android:textSize="16dp"
android:textColor="#ff3c3c3c" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tbl_edtName"
android:layout_toLeftOf="@+id/tbl_txtName"
android:layout_marginTop="6dp"
android:layout_toRightOf="@+id/tbl_searchIcon"
android:layout_marginLeft="10dp"
android:stretchColumns="*">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edtName"
android:background="@drawable/edittext" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:id="@+id/tbl_sort"
android:layout_marginTop="13dp"
android:layout_marginRight="8dp" >
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imgSort"
android:src="@drawable/ic_sortb"
android:cropToPadding="false" />
</TableRow>
</TableLayout>
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:indeterminateOnly="false"
style="@style/ProgressBar.Horizontal"
android:indeterminate="true"
android:id="@+id/invPopupProgressBar"
android:visibility="gone"
android:layout_below="@+id/tbl_sort"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp" />
</RelativeLayout>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/scrollView"
android:layout_below="@+id/tbl_mainTitle"
android:layout_above="@+id/Relative_Buttons"
android:layout_marginBottom="2dp"
android:layout_marginTop="5dp">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/listViewInvPopupItems"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:background="#fff4f4f4" />
</RelativeLayout>
</ScrollView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/Relative_Buttons"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp">
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_yes"
android:layout_alignParentRight="true">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="161dp"
android:layout_height="50dp"
android:text="@string/inv_popup_btnOK_title"
android:id="@+id/txtYes"
android:drawableRight="@drawable/ic_ok"
android:drawablePadding="10dp"
android:singleLine="true"
android:textSize="16dp"
android:background="#fff4f4f4"
android:paddingRight="50dp"
android:gravity="center_vertical"
android:textColor="#ff828282" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_no"
android:layout_toLeftOf="@+id/tbl_yes"
android:layout_marginRight="2dp">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="161dp"
android:layout_height="50dp"
android:text="@string/inv_popup_btnCancel_title"
android:id="@+id/txtNo"
android:drawableRight="@drawable/ic_delete"
android:drawablePadding="10dp"
android:singleLine="true"
android:textSize="16dp"
android:background="#fff4f4f4"
android:paddingRight="50dp"
android:gravity="center_vertical|right"
android:textColor="#ff828282" />
</TableRow>
</TableLayout>
</RelativeLayout>
</RelativeLayout>
lstcstmrinvoicepopupitems.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#fff4f4f4"
android:paddingBottom="8dp"
android:paddingTop="3dp">
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_check"
android:layout_alignParentRight="true">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/inv_popupTaken" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="285dp"
android:layout_height="wrap_content"
android:id="@+id/tbl_name"
android:layout_toLeftOf="@+id/tbl_check"
android:layout_marginTop="7dp">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="צבע יסוד טרי מתאים לברזל וגם לעץ מהיר בייבוש"
android:id="@+id/inv_popupName"
android:textSize="15dp"
android:textColor="#ff000000"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_txtQuan"
android:layout_below="@+id/tbl_check"
android:layout_alignParentRight="true"
android:layout_marginRight="7dp"
android:layout_marginTop="3dp">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="45dp"
android:layout_height="wrap_content"
android:text="@string/inv_quan_title"
android:id="@+id/inv_txtQuan"
android:textSize="15dp"
android:textColor="#ff8c8a8a"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_edtQuan"
android:layout_below="@+id/tbl_check"
android:layout_toLeftOf="@+id/tbl_txtQuan">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="60dp"
android:layout_height="wrap_content"
android:id="@+id/inv_popupQuan"
android:background="@drawable/edittext"
android:text="15400"
android:textColor="#ff8c8a8a"
android:textSize="15dp"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_txtPrice"
android:layout_below="@+id/tbl_check"
android:layout_alignParentRight="false"
android:layout_marginRight="12dp"
android:layout_marginTop="3dp"
android:layout_toLeftOf="@+id/tbl_edtQuan">
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="45dp"
android:layout_height="wrap_content"
android:text="@string/inv_price_title"
android:id="@+id/txt_Price"
android:textSize="15dp"
android:textColor="#ff8c8a8a"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_edtPrice"
android:layout_below="@+id/tbl_check"
android:layout_toLeftOf="@+id/tbl_txtPrice" >
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<EditText
android:layout_width="70dp"
android:layout_height="wrap_content"
android:id="@+id/inv_popupPrice"
android:background="@drawable/edittext"
android:text="19540.66"
android:textColor="#ff8c8a8a"
android:textSize="15dp"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_equal"
android:layout_below="@+id/tbl_check"
android:layout_alignParentRight="false"
android:layout_marginRight="2dp"
android:layout_marginTop="3dp"
android:layout_toLeftOf="@+id/tbl_edtPrice" >
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="="
android:id="@+id/txt_equal"
android:textSize="15dp"
android:textColor="#ff8c8a8a"
android:singleLine="true" />
</TableRow>
</TableLayout>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbl_total"
android:layout_below="@+id/tbl_check"
android:layout_alignParentRight="false"
android:layout_marginRight="2dp"
android:layout_marginTop="3dp"
android:layout_toLeftOf="@+id/tbl_equal" >
<TableRow
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="128549.87"
android:id="@+id/inv_popupTotal"
android:textSize="15dp"
android:textColor="#ff8c8a8a"
android:singleLine="true" />
</TableRow>
</TableLayout>
</RelativeLayout>
3
Answers
It sounds like 10 items may even be too many. Try loading 1 at a time and see if performance improves.
If the listview is not responding while being updated it means the “update” is doing heavy work on the main thread. What you want to do to make it smoother is delegate as much of this work to an other thread. This includes :
EDIT: As per your edit on the question, I can see you are doing some parsing in your
onPostExecute()
method of your asynctask which is executed on the main thread. You should do this work in thedoInBackground()
method and only update the adapter in theonPostExecute()
method. In order to do that, you can return a list of MyInvoiceItems from your doInBackground method which will be passed as a parameter on your onPostExecute() method and then do something like this:I think, your heavy work is here:
setListViewHeightBasedOnChildren
this method will measure each child and get each item height,and add up to a total height for listView. (does it work so?).
as you have many rows,it will become a dangerous work.
this method works well at showing a few rows all in a vertical scrollview.
and, why you call notifyDatasetChange before dataset Changed?