title: Update recyclerview with new adapter
body: <p>I have a fragment whith a Searchview at the top, and below this I show a call log with the las 10 calls. To show the call log I use recyclerview with cards. This behaviour works fine, but now I want to implement something else. </p>
  
  <p>If I search a name in the Searchview, I would like to do something like when a result list gets updated showing the coincidences with the contact list. This is, I would need to reuse the recyclerview, but at this time, instead of the call log, I will show coincidences with the contact list.</p>
  
  <p>I've used code found <a href="https://github.com/Wrdlbrnft/Searchable-RecyclerView-Demo/blob/master/app/src/main/java/com/github/wrdlbrnft/searchablerecyclerviewdemo/ui/fragments/MainFragment.java" rel="nofollow">here</a>, but is not working. I'm making some test to see what is wrong and I've found that I'm not able to reuse the recyclerview. </p>
  
  <p>At first, I do this to show the call log:</p>
  
  <pre><code>mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
  mRecyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
  mLogAdapter = new LogAdapter(DisplayCallLog());
  mRecyclerView.setAdapter(mLogAdapter);
  </code></pre>
  
  <p>And when the searchview get's updated, I'm trying just showing the contactlist to verify that this is working:</p>
  
  <pre><code>public boolean onQueryTextChange(String query) {
      mContactAdapter = new ContactAdapter(ContactsList());
      mRecyclerView.swapAdapter(mContactAdapter, true);
      //final List&lt;ContactInfo&gt; filteredModelList = filter(ContactsList(), query);
      //mContactAdapter.animateTo(filteredModelList);
      //mRecyclerView.scrollToPosition(0);
      return true;
  }
  </code></pre>
  
  <p>But I don't get to show the contactlist on the same recyclerview.</p>
  
  <hr>
  
  <p><strong>EDIT 1</strong> -> Comment</p>
  
  <p>I've tried loading the contactlist at startup instead of the loglist, and it does not load it neither. Maybe the problem is that the contactlist is to long?</p>
  
  <hr>
  
  <p><strong>EDIT 2</strong> -> Extensive code added</p>
  
  <p><strong>1) Set up the SearchView</strong></p>
  
  <p>Instead of adding the searchview in the actionbar, I use a cardview to contain it. This is the <code>phone_layout.xml</code>.</p>
  
  <pre><code>&lt;LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/tools"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"&gt;
  &lt;LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="60dp"&gt;
      &lt;android.support.v7.widget.CardView
          xmlns:card_view="http://schemas.android.com/apk/res-auto"
          android:id="@+id/card_view"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          card_view:cardCornerRadius="4dp"
          card_view:cardElevation="4dp"
          android:layout_gravity="center_horizontal"
          android:layout_marginLeft="80dp"
          android:layout_marginRight="80dp"&gt;
          &lt;android.support.v7.widget.SearchView
              android:id="@+id/dialpad_searchview"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@android:color/transparent"
              android:textSize="18sp"
              app:queryHint="@string/enter_phone_number"
              app:iconifiedByDefault="false"
              android:imeOptions="flagNoFullscreen"/&gt;
      &lt;/android.support.v7.widget.CardView&gt;
  &lt;/LinearLayout&gt;
  &lt;android.support.v7.widget.RecyclerView
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/recyclerview"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="5dp"
      android:layout_marginLeft="80dp"
      android:layout_marginRight="80dp"/&gt;
  </code></pre>
  
  <p></p>
  
  <p><strong>2) Set up the adapter</strong></p>
  
  <p>First I define the model class <code>ContactInfo</code>. This is same for booth uses calllog and contact coincidences.</p>
  
  <pre><code>public class ContactInfo {
  
  public int id;
  public String name;
  public String number;
  public String type;
  public int logType;
  
  public static final String ID_PREFIX = "ID_";
  public static final String NUMBER_PREFIX = "Name_";
  public static final String NAME_PREFIX = "Number_";
  public static final String TYPE_PREFIX = "Type_";
  
  public String getContactName() {
      return name;
  }
  public String getContactNumber() {
      return number;
  }
  </code></pre>
  
  <p>The <code>ContactViewHolder</code> is also the same for booth.</p>
  
  <pre><code>public class ContactViewHolder extends RecyclerView.ViewHolder {
  protected TextView vName;
  protected TextView vType;
  protected ImageView vPic;
  
  public ContactViewHolder(View v) {
      super(v);
      vName =  (TextView) v.findViewById(R.id.contactname);
      vType = (TextView)  v.findViewById(R.id.contacttype);
      vPic = (ImageView)  v.findViewById(R.id.contactpic);
  }
  </code></pre>
  
  <p>Now, what is diferent for each use is the layout and the adapter. Starting from the calllog, here is the <code>phone_calllog_card.xml</code></p>
  
  <pre><code>&lt;android.support.v7.widget.CardView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:card_view="http://schemas.android.com/apk/res-auto"
  android:id="@+id/cardView"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  card_view:cardCornerRadius="4dp"
  card_view:cardElevation="4dp"
  android:layout_marginBottom="5dp"&gt;
  &lt;RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="?android:selectableItemBackground"&gt;
      &lt;ImageView
          android:id="@+id/contactpic"
          android:tag="image_tag"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentTop="true"
          android:layout_marginLeft="20dp"/&gt;
      &lt;TextView
          android:id="@+id/contactname"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_toRightOf="@+id/contactpic"
          android:layout_marginLeft="40dp"
          android:text="Name"
          android:textAppearance="?android:attr/textAppearanceLarge"/&gt;
      &lt;TextView
          android:id="@+id/contacttype"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@+id/contactname"
          android:layout_toRightOf="@+id/contactpic"
          android:layout_marginLeft="40dp"
          android:text="Type"
          android:textAppearance="?android:attr/textAppearanceMedium"/&gt;
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p></p>
  
  <p>And the <code>LogAdapter</code> class.</p>
  
  <pre><code>public class LogAdapter extends RecyclerView.Adapter&lt;ContactViewHolder&gt; {
  
  private List&lt;ContactInfo&gt; logList;
  
  public LogAdapter(List&lt;ContactInfo&gt; logList) {
      this.logList = logList;
  }
  
  @Override
  public int getItemCount() {
      return logList.size();
  }
  
  @Override
  public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
      final String number;
      String name;
      ContactInfo ci = logList.get(i);
      name = ci.name;
      if (name.equals("-2")) {
          name = "Private";
      }
      contactViewHolder.vName.setText(name);
      contactViewHolder.vType.setText(ci.type);
      number = ci.number;
      }
  
      contactViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Intent intent = new Intent(Intent.ACTION_CALL);
              intent.setData(Uri.parse("tel:" + number.trim()));
              if (ActivityCompat.checkSelfPermission(v.getContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
                  v.getContext().startActivity(intent);
              }
          }
      });
  }
  
  @Override
  public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
      View itemView = LayoutInflater.
              from(viewGroup.getContext()).
              inflate(R.layout.phone_calllog_card, viewGroup, false);
  
      return new ContactViewHolder(itemView);
  }
  </code></pre>
  
  <p>}</p>
  
  <p>The <code>phone_contact_card.xml</code> and the <code>ContactAdapter</code> are almost indetical to these previous ones, but with few variations.</p>
  
  <pre><code>&lt;android.support.v7.widget.CardView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:card_view="http://schemas.android.com/apk/res-auto"
  android:id="@+id/cardView"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  card_view:cardCornerRadius="4dp"
  card_view:cardElevation="4dp"
  android:layout_marginBottom="5dp"&gt;
  &lt;RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="?android:selectableItemBackground"&gt;
      &lt;ImageView
          android:id="@+id/contactpic"
          android:tag="image_tag"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentTop="true"
          android:layout_marginLeft="20dp"/&gt;
      &lt;TextView
          android:id="@+id/contactname"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_toRightOf="@+id/contactpic"
          android:layout_marginLeft="40dp"
          android:layout_centerVertical="true"
          android:text="Name"
          android:textAppearance="?android:attr/textAppearanceLarge"/&gt;
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p></p>
  
  <p>The diference between the Adapter for the call log and the contact coincidences is that the call log is shown when entered to the fragment and it shows 10 static results from the call log. But with the contact coincidences, it must have some kind of animation to refresh the list each time you enter a letter in the serachview to find coincidences, so here are some aditional methods.</p>
  
  <pre><code>public class ContactAdapter extends RecyclerView.Adapter&lt;ContactViewHolder&gt; {
  
  private List&lt;ContactInfo&gt; contactList;
  
  public ContactAdapter(List&lt;ContactInfo&gt; contactList) {
      this.contactList = contactList;
  }
  
  @Override
  public int getItemCount() {
      return contactList.size();
  }
  
  @Override
  public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
      final String number;
      ContactInfo ci = contactList.get(i);
      contactViewHolder.vName.setText(ci.name);
      contactViewHolder.vPic.setImageResource(R.drawable.contact_icon_blue);
      number = ci.number;
  
      contactViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Intent intent = new Intent(Intent.ACTION_CALL);
              intent.setData(Uri.parse("tel:" + number.trim()));
              if (ActivityCompat.checkSelfPermission(v.getContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
                  v.getContext().startActivity(intent);
              }
          }
      });
  }
  
  @Override
  public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
      View itemView = LayoutInflater.
              from(viewGroup.getContext()).
              inflate(R.layout.phone_contact_card, viewGroup, false);
  
      return new ContactViewHolder(itemView);
  }
  
  public void animateTo(List&lt;ContactInfo&gt; contacts) {
      applyAndAnimateRemovals(contacts);
      applyAndAnimateAdditions(contacts);
      applyAndAnimateMovedItems(contacts);
  }
  
  private void applyAndAnimateRemovals(List&lt;ContactInfo&gt; newContacts) {
      for (int i = contactList.size() - 1; i &gt;= 0; i--) {
          final ContactInfo model = contactList.get(i);
          if (!newContacts.contains(model)) {
              removeItem(i);
          }
      }
  }
  
  private void applyAndAnimateAdditions(List&lt;ContactInfo&gt; newContacts) {
      for (int i = 0, count = contactList.size(); i &lt; count; i++) {
          final ContactInfo model = newContacts.get(i);
          if (!contactList.contains(model)) {
              addItem(i, model);
          }
      }
  }
  
  private void applyAndAnimateMovedItems(List&lt;ContactInfo&gt; newContacts) {
      for (int toPosition = newContacts.size() - 1; toPosition &gt;= 0; toPosition--) {
          final ContactInfo model = newContacts.get(toPosition);
          final int fromPosition = contactList.indexOf(model);
          if (fromPosition &gt;= 0 &amp;&amp; fromPosition != toPosition) {
              moveItem(fromPosition, toPosition);
          }
      }
  }
  
  public ContactInfo removeItem(int position) {
      final ContactInfo model = contactList.remove(position);
      notifyItemRemoved(position);
      return model;
  }
  
  public void addItem(int position, ContactInfo model) {
      contactList.add(position, model);
      notifyItemInserted(position);
  }
  
  public void moveItem(int fromPosition, int toPosition) {
      final ContactInfo model = contactList.remove(fromPosition);
      contactList.add(toPosition, model);
      notifyItemMoved(fromPosition, toPosition);
  }
  </code></pre>
  
  <p><strong>3) Implementing logic</strong></p>
  
  <p>Finally, in the <code>PhoneFragment</code>, this is the implementation to make all this work.</p>
  
  <pre><code>public class PhoneFragment extends Fragment implements SearchView.OnQueryTextListener {
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  
      View view = inflater.inflate(R.layout.phone_layout, container, false);
  
      //query Searchview
      svContact.setOnQueryTextListener(this);
  
      //Recyclerview
      mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
      mRecyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
      //Loads the calllog
      mLogAdapter = new LogAdapter(DisplayCallLog());
      mRecyclerView.setAdapter(mLogAdapter);
  
      //RecyclerView animation
      RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
      itemAnimator.setAddDuration(1000);
      itemAnimator.setRemoveDuration(1000);
      mRecyclerView.setItemAnimator(itemAnimator);
  
      return view;
  }
  </code></pre>
  
  <p>Note: As the call log is showing correctly, I'll avoid copying here the <code>DisplayCallLog()</code> method as is too long.</p>
  
  <p>When text is entered in the searchview, we define the new adapter to achieve the functionallity of showing coincidences in the recyclerview.</p>
  
  <pre><code>    @Override
  public boolean onQueryTextChange(String query) {
      final List&lt;ContactInfo&gt; filteredModelList = filter(ContactsList(), query);
      mContactAdapter.animateTo(filteredModelList);
      mRecyclerView.scrollToPosition(0);
      return true;
  }
  
  private List&lt;ContactInfo&gt; filter(List&lt;ContactInfo&gt; contacts, String query) {
      query = query.toLowerCase();
  
      final List&lt;ContactInfo&gt; filteredModelList = new ArrayList&lt;&gt;();
      for (ContactInfo contact : contacts) {
          final String name = contact.getContactName().toLowerCase();
          final String number = contact.getContactNumber().toLowerCase();
          Log.i("FILTERED_QUERY", "name " + name + "/ number " + number);
          if (name.contains(query) || number.contains(query)) {
              filteredModelList.add(contact);
          }
      }
      return filteredModelList;
  }
  
      private ArrayList&lt;ContactInfo&gt; ContactsList() {
  
      ArrayList&lt;ContactInfo&gt; contactsList = new ArrayList&lt;ContactInfo&gt;();
      int contactID = 0;
      String contactNumber = null;
      String contactName = null;
      ContactInfo cI;
      int resultLimit = 0;
  
      Cursor cursorContacts = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
              null, null, null, null);
      while (cursorContacts.moveToNext() &amp;&amp; resultLimit&lt;10) {
          contactID = cursorContacts.getInt(cursorContacts.getColumnIndexOrThrow(
                  ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
          contactNumber = cursorContacts.getString(cursorContacts.getColumnIndexOrThrow(
                  ContactsContract.CommonDataKinds.Phone.NUMBER));
          contactName = cursorContacts.getString(cursorContacts.getColumnIndexOrThrow(
                  ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
  
          cI = new ContactInfo();
          cI.id = contactID;
          cI.name = contactName;
          cI.number = contactNumber;
          Log.i("CONTACT_INFO", cI.toString());
          resultLimit++;
      }
      cursorContacts.close();
      return contactsList;
  }
  </code></pre>
  
  <hr>
  
  <p><strong>EDIT 3</strong> -> New info</p>
  
  <p>I've tryed showing just the contacts at startup. So, instead of visualizing the log, I should see a contacts list. So in fragment's onCreateView I just do this:</p>
  
  <pre><code>mContactAdapter = new ContactAdapter(ContactsList());
  mRecyclerView.setAdapter(mContactAdapter);
  </code></pre>
  
  <p>Instead of what I was doing before:</p>
  
  <pre><code>mLogAdapter = new LogAdapter(DisplayCallLog());
  mRecyclerView.setAdapter(mLogAdapter);
  </code></pre>
  
  <p>This way, I'm just using one adapter, and if this is the problem, it should work. But is not working. So the problem must be something related to the way I achieve the contacts (I'm talking about getting the raw list of contacts from the contact list, without filtering them), or something that is wrong in the ContactAdapter. But this adapter and the LogAdapter are almost identical, so i don't know...</p>