title: Refreshing a ListView's adapter from inside an AsyncTask without duplicates
body: <p>I have a <code>ListView</code> and obviously an adapter the uses a <code>List&lt;T&gt;</code> object.<br>
  I added a button that is supposed to refresh the listview (= re-query the database and recreate the <code>ListView</code>).  </p>
  
  <p>All of the above (from querying the db to setting the adapter) happens inside an <code>AsyncTask</code>.  </p>
  
  <h2>Update Button Code</h2>
  
  <pre><code>    mRefreshButton.setOnClickListener(new OnClickListener() {
  
          @Override
          public void onClick(View v) {
              v.setClickable(false);
              new GetScheduleTask().execute((Void[]) null); //Basically, execute it again.
          }
      });
  </code></pre>
  
  <h2>AsyncTask (I deleted some unnecessary code)</h2>
  
  <pre><code>    private class GetScheduleTask extends AsyncTask&lt;Void, Void, List&lt;Object[]&gt;&gt; {
  
          @Override
          protected List&lt;Object[]&gt; doInBackground(Void... params) {           
              SQLiteDatabase db = SchooLauncherDbHelper.getInstance(getActivity()).getReadableDatabase();
              //TODO test repetition
              String sql = "LONG A** SQL HERE";
  
              Cursor c = db.rawQuery(sql, new String[] {String.valueOf(cal.getTimeInMillis()), String.valueOf(cal.getTimeInMillis()),
                      String.valueOf(cal.getTimeInMillis()), String.valueOf(cal.get(Calendar.MONTH))});
  
              while(c.moveToNext()) {
                  ......................
                  mEventList.add(new Object[] {new Class(...), new Subject(...)});
                  }
              }
  
              db.close();
              return mEventList;
          }
  
          @Override
          protected void onPostExecute(List&lt;Object[]&gt; result) {
              mScheduleListView = (ListView) view
                      .findViewById(R.id.mScheduleListView);
  
              TextView myTv = new TextView(getActivity());
              myTv.setText("No Results");
              mScheduleListView.setEmptyView(myTv);
  
              mScheduleEventAdapter = new ScheduleEventAdapter(getActivity(),
                  R.layout.schedule_item_layout, mEventList);
              mScheduleListView.setAdapter(mScheduleEventAdapter);
  
              if(!mImageView.isClickable())
                  mImageView.setClickable(true);
          }
      }
  </code></pre>
  
  <h2>ScheduleEventAdapter</h2>
  
  <pre><code>public class ScheduleEventAdapter extends ArrayAdapter&lt;Object[]&gt;{
  
      private Context context; 
      private int layoutResourceId;    
      private List&lt;Object[]&gt; data = null;
      private View row = null;
      private LayoutInflater inflater;
      private Subject mSubject;
      private Event mEvent;
      private String mEventStartTime, mEventEndTime;
  
      public ScheduleEventAdapter(Context context, int layoutResourceId, List&lt;Object[]&gt; data) {
          super(context, layoutResourceId, data);
          this.layoutResourceId = layoutResourceId;
          this.context = context;
          this.data = data;
      }
  
      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
              row = convertView;
  
              if(row == null) {
                  inflater = ((Activity)context).getLayoutInflater();
                  row = inflater.inflate(this.layoutResourceId, parent, false);
              }
  
              mSubject = (Subject) data.get(position)[1];
              mEvent = (Event) data.get(position)[0];
              ((ImageView) row.findViewById(R.id.subjecticon)).setImageResource(mSubject.icon);
              ((TextView) row.findViewById(R.id.schedule_event_subject_name)).setText(mSubject.name);
              ((TextView) row.findViewById(R.id.schedule_event_title)).setText(mEvent.mEventTitle);
              ((TextView) row.findViewById(R.id.schedule_event_location)).setText(((Class)mEvent).mClassLocation);
              this.mEventStartTime = ((int) mEvent.mEventStartTime / (1000*60*60)) + ":" + ((int) (((mEvent.mEventStartTime / (1000*60)) % 60)));
              this.mEventEndTime = ((int) mEvent.mEventEndTime / (1000*60*60)) + ":" + ((int) (((mEvent.mEventEndTime / (1000*60)) % 60)));
              ((TextView) row.findViewById(R.id.schedule_event_time)).setText(this.mEventStartTime + " - " + this.mEventEndTime);
  
          return row;
      }
  }
  </code></pre>
  
  <h2>The Problem</h2>
  
  <p>The problem is that the button works, but instead of re-creating the list, duplicates are being shown. </p>
  
  <p>As you can see, new items are being added <code>mEventList</code>, even the ones that already show.
  I could use an <code>if</code> statement with the <code>.contains()</code> method of the list to determine whether an object needs to be added to the list or not, but the problem is, even though the <strong>contents</strong> of the objects may be the same, the pointers are different which I guess is why it also doesn't work (I tried).</p>
  
  <p>I also tried resetting the adapter and playing with the data and <code>.notifyDataSetChanged()</code> but it didn't work.</p>
  
  <p>The only solution I could think of is to compare each field of each object inside the array, but that sounds too much like a performance-hit to me.</p>
  
  <p><strong>If so, what would be the most efficient and correct way to fix this problem?</strong></p>