rookieDeveloper rookieDeveloper - 1 month ago 6
Android Question

ListView repeating the data on load more

I am using on scroll to load more data and show them in list view but my

ListView
first shows already loaded data then adds the newly added data to
ListView


I have used for reference this and many others but unable to solve the issue

Here is my activity class

protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_all);
ButterKnife.bind(this);

Users = Users.getCurrentUser(this);

setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
UIUtility.setStatusColor(this);

Intent intent = getIntent();
try {
entityData = new JSONArray(intent.getStringExtra(EXTRA_DATA));
} catch (JSONException e) {
e.printStackTrace();
}
viewAllCategory = intent.getIntExtra(EXTRA_CATEGORY, 0);
viewAllEntityType = intent.getIntExtra(EXTRA_TYPE, 0);
latitude = intent.getDoubleExtra(EXTRA_LATITUDE, 0);
longitude = intent.getDoubleExtra(EXTRA_LONGITUDE, 0);

setTitle(TITLES[viewAllCategory]);

if (viewAllEntityType == Constants.SMBEntityType.TYPE_USER) {
List<Users> users = Utility.convertJsonArrayToUsers(entityData);
adapterUser = new ViewAllUserAdapter(this, users);
lvEntity.setAdapter(adapterUser);
} else {
List<Book> books = Utility.convertJsonArrayToBook(entityData);
adapterBook = new ViewAllBookAdapter(this, books);
lvEntity.setAdapter(adapterBook);
}
lvEntity.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (!stopLoadingMore) {
if (totalItemCount == firstVisibleItem + visibleItemCount && !isLoading) {
isLoading = true;
showLoading();
loadMoreData();
}
}
}
});
}

private void loadMoreData() {
String loadMoreUrl = buildLoadMoreUrl();
ShareMyBookHttpClient client = new ShareMyBookHttpClient();
client.get(loadMoreUrl, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
hideLoading();
if (responseBody != null) {
start = start+20;
try {
JSONObject jo = new JSONObject(new String(responseBody));
if (!jo.getBoolean(Constants.JsonKeys.ERROR)) {
JSONArray data = jo.getJSONArray(Constants.JsonKeys.DATA);
if (data.length() == 0) {
stopLoadingMore = true;
return;
}
if (data.length() < 20) {
stopLoadingMore = true;
}
for (int i = 0; i < data.length(); i++) {
entityData.put(data.getJSONObject(i));
}
if (viewAllEntityType == Constants.SMBEntityType.TYPE_USER) {
List<Users> users = Utility.convertJsonArrayToUsers(entityData);
adapterUser.mergeArray(users);
} else {
List<Book> books = Utility.convertJsonArrayToBook(entityData);
adapterBook.mergeArray(books);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}

@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
hideLoading();
}
});
}

private String buildLoadMoreUrl() {
switch (viewAllCategory) {
default:
case ViewAllCategory.CATEGORY_USER:
return Constants.createUrlToGetViewAllUsers(Users.getId(), latitude, longitude, Users.getAuthToken(), start, LIMIT);

case ViewAllCategory.CATEGORY_MY_BOOKS:
return Constants.createUrlToGetViewAllMyBooks(Users.getId(), Users.getAuthToken(), start, LIMIT);
}
}

private void showLoading() {
sbLoading = Snackbar.make(coolMain, R.string.view_all_loading, Snackbar.LENGTH_INDEFINITE);
sbLoading.show();
}

private void hideLoading() {
isLoading = false;
if (sbLoading != null) {
sbLoading.dismiss();
}
}


and following is my
AdapterClasss


public class ViewAllUserAdapter extends BaseAdapter {

private List<Users> users;
private Context context;

public ViewAllUserAdapter(Context context, List<Users> usersData) {
this.context = context;
users = usersData;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row=convertView;
UserVH holder=null;
if(row==null) {
LayoutInflater inflater = LayoutInflater.from(context);
row= inflater.inflate(R.layout.list_item_view_all_user, parent, false);
holder = new UserVH(row, position);

Users user = users.get(position);
UIUtility.setUserProfileUsingPicasso(context, user.getProfileImageUrlSmall(), holder.ivUserImage);

holder.tvName.setText(user.getName());
if (user.getDistance() == -1) {
holder.tvDistance.setText("");
} else {
holder.tvDistance.setText(context.getString(R.string.distance_notation, user.getDistance()));
}
row.setTag(holder);
}
else {
holder=(UserVH)row.getTag();Users user = users.get(position);
UIUtility.setUserProfileUsingPicasso(context, user.getProfileImageUrlSmall(), holder.ivUserImage);

holder.tvName.setText(user.getName());
if (user.getDistance() == -1) {
holder.tvDistance.setText("");
} else {
holder.tvDistance.setText(context.getString(R.string.distance_notation, user.getDistance()));
}

}

return row;
}

@Override
public int getCount() {
return users == null ? 0 : users.size();
}

@Override
public Object getItem(int position) {
return null;
}

@Override
public long getItemId(int position) {
return 0;
}

public void mergeArray(List<Users> additionalUsers) {
Log.e("users", String.valueOf(additionalUsers.size()));
if (additionalUsers != null) {
for (int i = 0; i < additionalUsers.size(); i++) {
if(!(users.contains(additionalUsers.get(i)))) {
users.add(additionalUsers.get(i));
}
}
}
notifyDataSetChanged();
}

public class UserVH extends View {
@Bind(R.id.item_vau_iv_user_image)
ImageView ivUserImage;
@Bind(R.id.item_vau_tv_name)
TextView tvName;
@Bind(R.id.item_vau_tv_distance)
TextView tvDistance;

private int position;

public UserVH(View view, final int position) {
super(context);
this.position = position;
ButterKnife.bind(this, view);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
UIUtility.openUserDetailActivity(context, users.get(position));
}
});
}
}
}

Jai Jai
Answer

As you already referred this link, Exactly the same issue is happening with you, You should have correct implementation for holder class in getView method.

Update your getView() method as per below :

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row=convertView;
        UserVH holder=null;
        if(row==null) {
            LayoutInflater inflater = LayoutInflater.from(context);
            row= inflater.inflate(R.layout.list_item_view_all_user, parent, false);
            holder = new UserVH(row, position);

            row.setTag(holder);
        }
        else {
            holder=(UserVH)row.getTag();

        }



        Users user = users.get(position);
        UIUtility.setUserProfileUsingPicasso(context, user.getProfileImageUrlSmall(), holder.ivUserImage);

            holder.tvName.setText(user.getName());
            if (user.getDistance() == -1) {
                holder.tvDistance.setText("");
            } else {
                holder.tvDistance.setText(context.getString(R.string.distance_notation, user.getDistance()));
            }

        return row;
    }

And update your getItemId and getItem methods as per below :

@Override
public Object getItem(int position) {
    return users.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

EDIT : clear the list additional users before adding the new objects

public void mergeArray(List<Users> additionalUsers) {
    Log.e("users", String.valueOf(additionalUsers.size()));
    if (additionalUsers != null) {
        // Following line to be added          
        additonalusers.clear();
        for (int i = 0; i < additionalUsers.size(); i++) {
            if(!(users.contains(additionalUsers.get(i)))) {
                users.add(additionalUsers.get(i));
            }
        }
    }
    notifyDataSetChanged();
}