Every time I pull to refresh (using chrisbanes library), my ListView gets all the “new” data appended to the end of the old data, instead of replacing it. I already checked my Json parser, which returns my ArrayList, and it’s definitely NOT that I’m accidentally doubling up in the list itself.
I’ve tried all sorts of “notifyDataSetChanged()”‘s and “.invalidate()”‘s and I just cannot seem to convince my ListView to fully repopulate itself. It works correctly on orientation-shift, which I realize is a clue, but I can’t seem to figure out what is different in that case.
Code below, thanks for any tips!
public class VoicemailsPME extends Activity{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.voicemails_pme);
listView = (PullToRefreshListView) findViewById(R.id.pulllist);
final String username = getIntent().getExtras().getString("username");
final String password = getIntent().getExtras().getString("password");
mailboxId = getIntent().getExtras().getString("mailboxId");
m_voicemails = new ArrayList<Voicemail>();
mHandlerFirst.post(new Runnable() {
@Override
public void run() {
CheckConnectionTask CCT = new CheckConnectionTask(VoicemailsPME.this);
CCT.execute(username, password);
firstTime = false;
}
});
listView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override
public void onRefresh(PullToRefreshBase<ListView> lv) {
lv.invalidate();
mHandler.post(new Runnable() {
@Override
public void run() {
CheckConnectionTask CCT = new CheckConnectionTask(VoicemailsPME.this);
CCT.execute(username, password);
}
});
}
});
this.m_adapter = new OrderAdapter(this, R.layout.voicemails_pme_row, m_voicemails);
listView.setAdapter(m_adapter);
}
private Runnable returnRes = new Runnable() {
@Override
public void run() {
if(m_voicemails != null && m_voicemails.size() > 0){
for(int i=0;i<m_voicemails.size();i++)
m_adapter.add(m_voicemails.get(i));
}
}
};
private void getVoicemails(){
try{
//Log.d("Data right before Json Parse", data);
Json jsonParser = new Json(data);
m_voicemails = jsonParser.getVoicemailsPME();
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
private class OrderAdapter extends ArrayAdapter<Voicemail> {
private ArrayList<Voicemail> items;
public OrderAdapter(Context context, int textViewResourceId, ArrayList<Voicemail> items) {
super(context, textViewResourceId, items);
this.items = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Voicemail vm = items.get(position);
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.voicemails_pme_row, null);
}
if (vm != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
TextView nm = (TextView) v.findViewById(R.id.length);
if (tt != null)
{
tt.setText(vm.getPhoneNumber());
if(vm.getNewStatus())
tt.setTypeface(null, Typeface.BOLD);
}
if(bt != null)
{
bt.setText(vm.getDate());
}
if(nm != null)
{
nm.setText(vm.getLength());
}
}
return v;
}
}
class CheckConnectionTask extends AsyncTask<String, Void, String> {
private VoicemailsPME activity;
private ProgressDialog dialog;
private Context context;
public CheckConnectionTask(VoicemailsPME activity)
{
this.activity = activity;
context = activity;
dialog = new ProgressDialog(context);
}
String username, password, str;
@Override
protected void onPreExecute() {
if(firstTime)
{
this.dialog.setMessage("Loading...");
this.dialog.show();
}
}
@Override
protected String doInBackground(String...arg0)
{
username = arg0[0];
password = arg0[1];
DefaultHttpClient httpclient = new DefaultHttpClient();
Credentials creds = new UsernamePasswordCredentials(username, password);
httpclient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), creds);
try{
HttpPost post = new HttpPost("https://www.my.patlive.com/api/v1.0/Mailbox/" + mailboxId + "/messages?format=json");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("username", username));
nameValuePairs.add(new BasicNameValuePair("password", password));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(post);
str = inputStreamToString(response.getEntity().getContent()).toString();
if(str.contains("\"ErrorCode\":0"))
{
//data = str;
return str;
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();}
return str;
}
@Override
protected void onPostExecute(String newData)
{
if(dialog.isShowing())
{
dialog.dismiss();
}
data = newData;
getVoicemails();
m_adapter.notifyDataSetChanged();
listView.onRefreshComplete();
}
}
}
I think that your
getVoicemail()method is the culprit.Because of the way that the adapter works, it’s using the backing array you provided originally (
m_voicemails), and when you refresh it you create a new list but the original one is not cleared and then you just add on top of that.I’ve found that it’s clearer to keep a list of the data separate from your adapter and then just feed that data into the adapter (using a set instead of an add).