android - O que é o SortedList<T> trabalhando com RecyclerView.Adapter?




android-appcompat android-recyclerview (3)

Há um exemplo SortedListActivity no repositório de origem da biblioteca de suporte que demonstra como usar SortedList e SortedListAdapterCallback dentro de um RecyclerView.Adapter. Na raiz do SDK, com a biblioteca de suporte instalada, ele deve estar em extras/android/support/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java (também no github ).

A existência desses exemplos específicos é mencionada exatamente uma vez na documentação do Google, na parte inferior de uma página que trata de um tópico diferente, então não culpo você por não encontrá-lo.

A Biblioteca de suporte Android 22.1 foi lançada ontem. Muitos novos recursos foram adicionados à biblioteca de suporte v4 e v7, entre os quais android.support.v7.util.SortedList<T> chama minha atenção.

Diz-se que, SortedList é uma nova estrutura de dados, funciona com o RecyclerView.Adapter , mantém o item adicionado / excluído / movido / alterado nas animações fornecidas pelo RecyclerView . Parece uma List<T> em um ListView mas parece mais avançado e poderoso.

Então, qual é a diferença entre SortedList<T> e List<T> ? Como eu poderia usá-lo eficientemente? Qual é a aplicação de SortedList<T> sobre List<T> se é assim? Alguém poderia postar algumas amostras?

Todas as dicas ou códigos serão apreciados. Desde já, obrigado.


Sobre a implementação SortedList , ela é apoiada por uma matriz de <T> com uma capacidade mínima padrão de 10 itens. Quando a matriz estiver cheia, ela será redimensionada para size() + 10

O código fonte está disponível here

Da developer.android.com/reference/android/support/v7/util/…

Uma implementação de lista classificada que pode manter os itens em ordem e também notificar as alterações na lista, para que possa ser vinculado a um RecyclerView.Adapter.

Ele mantém os itens ordenados usando o método compare (Object, Object) e usa a pesquisa binária para recuperar itens. Se os critérios de classificação dos seus itens forem alterados, chame os métodos apropriados enquanto os edita para evitar inconsistências nos dados.

Você pode controlar a ordem dos itens e alterar as notificações por meio do parâmetro SortedList.Callback.

Em relação ao desempenho, eles também adicionaram SortedList.BatchedCallback para realizar várias operações ao mesmo tempo, em vez de uma por vez.

Uma implementação de retorno de chamada que pode notificar em lote os eventos despachados pelo SortedList.

Essa classe pode ser útil se você deseja executar várias operações em uma SortedList, mas não deseja despachar cada evento um por um, o que pode resultar em um problema de desempenho.

Por exemplo, se você deseja adicionar vários itens a uma chamada SortedList, BatchedCallback converte chamadas individuais onInserted (index, 1) em uma onInserted (index, N) se itens forem adicionados a índices consecutivos. Essa alteração pode ajudar o RecyclerView a resolver alterações com muito mais facilidade.

Se alterações consecutivas na SortedList não forem adequadas para lote, o BatchingCallback as despachará assim que esse caso for detectado. Depois que suas edições na SortedList forem concluídas, você sempre deve chamar dispatchLastEvent () para liberar todas as alterações no retorno de chamada.


SortedList lida com a comunicação com o adaptador Recycler via Callback .

Uma diferença entre SortedList e List é vista no método auxiliar addAll na amostra abaixo.

public void addAll(List<Page> items) {
        mPages.beginBatchedUpdates();
        for (Page item : items) {
            mPages.add(item);
        }
        mPages.endBatchedUpdates();
    }
  1. Mantém o último item adicionado

Digamos que eu tenha 10 itens em cache para carregar imediatamente quando minha lista de recicladores for preenchida. Ao mesmo tempo, consultei minha rede para os mesmos 10 itens, pois eles poderiam ter sido alterados desde que eu os armazenei em cache. Posso chamar o mesmo método addAll e SortedList substituirá os cachedItems por fetchedItems sob o capô (sempre mantém o último item adicionado).

// After creating adapter
myAdapter.addAll(cachedItems)
// Network callback
myAdapter.addAll(fetchedItems)

Em uma List regular, eu teria duplicatas de todos os meus itens (tamanho da lista 20). Com SortedList ele substitui itens iguais usando o areItemsTheSame do retorno de areItemsTheSame .

  1. É inteligente saber quando atualizar as Views

Quando os fetchedItems são adicionados, o onChange será chamado apenas se um ou mais títulos da página forem alterados. Você pode personalizar o que SortedList procura no areContentsTheSame do retorno de areContentsTheSame .

  1. Seu desempenho

Se você deseja adicionar vários itens a uma chamada SortedList, BatchedCallback, converte chamadas individuais onInserted (index, 1) em uma onInserted (index, N) se itens forem adicionados a índices consecutivos. Essa alteração pode ajudar o RecyclerView a resolver alterações com muito mais facilidade.

Amostra

Você pode obter um getter no seu adaptador para o SortedList , mas eu apenas decidi adicionar métodos auxiliares ao meu adaptador.

Classe do adaptador:

  public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private SortedList<Page> mPages;

    public MyAdapter() {
        mPages = new SortedList<Page>(Page.class, new SortedList.Callback<Page>() {
            @Override
            public int compare(Page o1, Page o2) {
                return o1.getTitle().compareTo(o2.getTitle());
            }

            @Override
            public void onInserted(int position, int count) {
                notifyItemRangeInserted(position, count);
            }

            @Override
            public void onRemoved(int position, int count) {
                notifyItemRangeRemoved(position, count);
            }

            @Override
            public void onMoved(int fromPosition, int toPosition) {
                notifyItemMoved(fromPosition, toPosition);
            }

            @Override
            public void onChanged(int position, int count) {
                notifyItemRangeChanged(position, count);
            }

            @Override
            public boolean areContentsTheSame(Page oldItem, Page newItem) {
                // return whether the items' visual representations are the same or not.
                return oldItem.getTitle().equals(newItem.getTitle());
            }

            @Override
            public boolean areItemsTheSame(Page item1, Page item2) {
                return item1.getId() == item2.getId();
            }
        });

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.viewholder_page, parent, false);
        return new PageViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        PageViewHolder pageViewHolder = (PageViewHolder) holder;
        Page page = mPages.get(position);
        pageViewHolder.textView.setText(page.getTitle());
    }

    @Override
    public int getItemCount() {
        return mPages.size();
    }

    // region PageList Helpers
    public Page get(int position) {
        return mPages.get(position);
    }

    public int add(Page item) {
        return mPages.add(item);
    }

    public int indexOf(Page item) {
        return mPages.indexOf(item);
    }

    public void updateItemAt(int index, Page item) {
        mPages.updateItemAt(index, item);
    }

    public void addAll(List<Page> items) {
        mPages.beginBatchedUpdates();
        for (Page item : items) {
            mPages.add(item);
        }
        mPages.endBatchedUpdates();
    }

    public void addAll(Page[] items) {
        addAll(Arrays.asList(items));
    }

    public boolean remove(Page item) {
        return mPages.remove(item);
    }

    public Page removeItemAt(int index) {
        return mPages.removeItemAt(index);
    }

    public void clear() {
       mPages.beginBatchedUpdates();
       //remove items at end, to avoid unnecessary array shifting
       while (mPages.size() > 0) {
          mPages.removeItemAt(mPages.size() - 1);
       }
       mPages.endBatchedUpdates();
    }
}

Classe da página:

public class Page {
    private String title;
    private long id;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

XML do espectador:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text_view"
        style="@style/TextStyle.Primary.SingleLine"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Classe de espectador:

public class PageViewHolder extends RecyclerView.ViewHolder {
    public TextView textView;


    public PageViewHolder(View itemView) {
        super(itemView);
        textView = (TextView)item.findViewById(R.id.text_view);
    }
}




sortedlist