Tenho uma pergunta sobre o RecyclerView.State do Android .
Estou usando um RecyclerView, como posso usar e vinculá-lo ao RecyclerView.State?
Meu objetivo é salvar a posição de rolagem do RecyclerView .
Tenho uma pergunta sobre o RecyclerView.State do Android .
Estou usando um RecyclerView, como posso usar e vinculá-lo ao RecyclerView.State?
Meu objetivo é salvar a posição de rolagem do RecyclerView .
Como você planeja salvar a última posição salva com RecyclerView.State
?
Você sempre pode contar com o bom estado de salvamento. Estenda RecyclerView
e substitua onSaveInstanceState () e onRestoreInstanceState()
:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
}
SavedState newState = new SavedState(superState);
newState.mScrollPosition = mScrollPosition;
return newState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
if(state != null && state instanceof SavedState){
mScrollPosition = ((SavedState) state).mScrollPosition;
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null){
int count = layoutManager.getItemCount();
if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
layoutManager.scrollToPosition(mScrollPosition);
}
}
}
}
static class SavedState extends android.view.View.BaseSavedState {
public int mScrollPosition;
SavedState(Parcel in) {
super(in);
mScrollPosition = in.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mScrollPosition);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
Atualizar
A partir do
recyclerview:1.2.0-alpha02
lançamentoStateRestorationPolicy
foi introduzido. Pode ser uma abordagem melhor para o problema em questão.Este tópico foi abordado no artigo médio de desenvolvedores Android .
Além disso, @ rubén-viguera compartilhou mais detalhes na resposta abaixo. https://stackoverflow.com/a/61609823/892500
Resposta antiga
Se você estiver usando LinearLayoutManager, ele vem com api linearLayoutManagerInstance.onSaveInstanceState () e restore api linearLayoutManagerInstance.onRestoreInstanceState (...)
Com isso, você pode salvar o pacote devolvido em seu outState. por exemplo,
e restaure a posição de restauração com o estado que você salvou. por exemplo,
Para encerrar, seu código final será semelhante a
Editar: Você também pode usar as mesmas apis com o GridLayoutManager, pois é uma subclasse de LinearLayoutManager. Obrigado @wegsehen pela sugestão.
Edit: Lembre-se, se você também estiver carregando dados em um thread de segundo plano, você precisará fazer uma chamada para onRestoreInstanceState dentro de seu método onPostExecute / onLoadFinished para que a posição seja restaurada após a mudança de orientação, por exemplo
fonte
RecyclerView
mas não se você tiver umViewPager
com umRecycerView
em cada página.onCreateView
, mas após o carregamento dos dados. Veja a resposta de @Farmaker aqui.Loja
Restaurar
e se isso não funcionar, tente
Armazenar
onPause()
e restauraronResume()
fonte
lastFirstVisiblePosition
para0
após restaurá-lo. Este caso é útil quando você tem um fragmento / atividade que carrega dados diferentes em umRecyclerView
, por exemplo, um aplicativo explorador de arquivos.SwipeRefreshLayout
?RecyclerView
Eu queria salvar a posição de rolagem do Recycler View ao navegar para fora da minha atividade de lista e clicar no botão Voltar para navegar de volta. Muitas das soluções fornecidas para esse problema eram muito mais complicadas do que o necessário ou não funcionavam para minha configuração, então pensei em compartilhar minha solução.
Primeiro salve o estado da instância em onPause, como muitos mostraram. Acho que vale a pena enfatizar aqui que esta versão de onSaveInstanceState é um método da classe RecyclerView.LayoutManager.
A chave para fazer isso funcionar corretamente é certificar-se de chamar onRestoreInstanceState depois de conectar seu adaptador, como alguns indicaram em outros threads. No entanto, a chamada do método real é muito mais simples do que muitos indicaram.
fonte
I Defina as variáveis em onCreate (), salve a posição de rolagem em onPause () e defina a posição de rolagem em onResume ()
fonte
Você não precisa mais salvar e restaurar o estado sozinho. Se você definir um ID exclusivo em xml e recyclerView.setSaveEnabled (true) (true por padrão), o sistema fará isso automaticamente. Aqui está mais sobre isso: http://trickyandroid.com/saving-android-view-state-correctly/
fonte
Todos os gerenciadores de layout incluídos na biblioteca de suporte já sabem como salvar e restaurar a posição de rolagem.
A posição de rolagem é restaurada na primeira passagem de layout, o que acontece quando as seguintes condições são atendidas:
RecyclerView
RecyclerView
Normalmente você define o gerenciador de layout em XML, então tudo que você precisa fazer agora é
RecyclerView
Você pode fazer isso a qualquer momento, não está restrito a
Fragment.onCreateView
ouActivity.onCreate
.Exemplo: certifique-se de que o adaptador esteja conectado sempre que os dados forem atualizados.
A posição de rolagem salva é calculada a partir dos seguintes dados:
Portanto, você pode esperar uma pequena incompatibilidade, por exemplo, se seus itens tiverem dimensões diferentes na orientação retrato e paisagem.
O
RecyclerView
/ScrollView
/ qualquer coisa precisa ter umandroid:id
para que seu estado seja salvo.fonte
LinearLayoutManager.SavedState
: cs.android.com/androidx/platform/frameworks/support/+/…Aqui está minha abordagem para salvá-los e manter o estado de visualização de reciclagem em um fragmento. Primeiro, adicione mudanças de configuração em sua atividade pai conforme o código abaixo.
Então, em seu Fragment, declare esses métodos de instância
Adicione o código abaixo em seu método @onPause
Adicione o método onConfigartionChanged como abaixo.
Esta abordagem resolverá seu problema. se você tiver um gerenciador de layout diferente, então apenas substitua o gerenciador de layout superior.
fonte
É assim que eu restauro a posição do RecyclerView com GridLayoutManager após a rotação quando você precisa recarregar dados da Internet com AsyncTaskLoader.
Faça uma variável global de Parcelable e GridLayoutManager e uma string final estática:
Salvar o estado do gridLayoutManager em onSaveInstance ()
Restaurar em onRestoreInstanceState
Então, quando o carregador obtém dados da Internet, você restaura a posição de reciclagem de visualização em onLoadFinished ()
.. claro que você tem que instanciar o gridLayoutManager dentro de onCreate. Felicidades
fonte
Eu tive o mesmo requisito, mas as soluções aqui não me ajudaram muito, devido à fonte de dados para o recyclerView.
Eu estava extraindo o estado LinearLayoutManager de RecyclerViews em onPause ()
Parcelable
state
é salvo emonSaveInstanceState(Bundle outState)
e extraído novamente emonCreate(Bundle savedInstanceState)
, quandosavedInstanceState != null
.No entanto, o adaptador recyclerView é preenchido e atualizado por um objeto ViewModel LiveData retornado por uma chamada DAO para um banco de dados Room.
Por fim, descobri que restaurar o estado da instância diretamente após os dados serem definidos no adaptador manteria o estado de rolagem nas rotações.
Suspeito que isso seja porque o
LinearLayoutManager
estado que eu restaurei estava sendo sobrescrito quando os dados foram retornados pela chamada do banco de dados ou o estado restaurado não fazia sentido em um LinearLayoutManager 'vazio'.Se os dados do adaptador estiverem disponíveis diretamente (ou seja, não contigentes em uma chamada de banco de dados), a restauração do estado da instância no LinearLayoutManager poderá ser feita após o adaptador ser configurado no recyclerView.
A distinção entre os dois cenários me sustentou por muito tempo.
fonte
No Android API Nível 28, simplesmente garanto que configurei meu
LinearLayoutManager
eRecyclerView.Adapter
no meuFragment#onCreateView
método, e tudo Just Worked ™ ️. Eu não precisava fazer nadaonSaveInstanceState
ouonRestoreInstanceState
trabalhar.A resposta de Eugen Pechanec explica por que isso funciona.
fonte
A partir da versão 1.2.0-alpha02 da biblioteca androidx recyclerView, agora é gerenciado automaticamente. Basta adicioná-lo com:
E use:
O enum StateRestorationPolicy tem 3 opções:
Observe que, no momento desta resposta, a biblioteca recyclerView ainda está em alpha03, mas a fase alpha não é adequada para fins de produção .
fonte
Para mim, o problema era que eu configurava um novo gerenciador de layout toda vez que trocava meu adaptador, perdendo a posição de rolagem no recyclerView.
fonte
Gostaria apenas de compartilhar a situação recente que encontro com o RecyclerView. Espero que qualquer pessoa com o mesmo problema se beneficie.
Meu requisito de projeto: Portanto, tenho um RecyclerView que lista alguns itens clicáveis em minha atividade principal (Atividade-A). Quando o item é clicado, uma nova atividade é exibida com os detalhes do item (Atividade-B).
Eu implementei no Manifesto arquivo que a Activity-A é pai da Activity-B, dessa forma, tenho um botão voltar ou home na ActionBar da Activity-B
Problema: toda vez que pressiono o botão Voltar ou Início na ActionBar da Activity-B, a Activity-A entra em todo o ciclo de vida da atividade começando em onCreate ()
Embora eu tenha implementado um onSaveInstanceState () salvando a Lista do Adaptador do RecyclerView, quando a Activity-A inicia seu ciclo de vida, o saveInstanceState é sempre nulo no método onCreate ().
Pesquisando mais na internet, me deparei com o mesmo problema, mas a pessoa percebeu que no botão Voltar ou Início abaixo do dispositivo Anroid (botão Voltar / Início padrão), a Atividade-A não entra no Ciclo de Vida da Atividade.
Solução:
Eu habilitei o botão home ou voltar na Activity-B
No método onCreate (), adicione esta linha supportActionBar? .SetDisplayHomeAsUpEnabled (true)
No método overide fun onOptionsItemSelected (), verifiquei o item.ItemId no qual o item foi clicado com base no id. O Id para o botão Voltar é
android.R.id.home
Em seguida, implemente uma chamada de função finish () dentro de android.R.id.home
Isso encerrará a Atividade-B e trará o Acitivy-A sem passar por todo o ciclo de vida.
Para minhas necessidades, esta é a melhor solução até agora.
fonte
Eu tive o mesmo problema com uma pequena diferença, eu estava usando Databinding , e estava configurando o adaptador recyclerView e o layoutManager nos métodos de binding.
O problema era que a vinculação de dados estava acontecendo depois de onResume, então estava redefinindo meu layoutManager depois de onResume e isso significa que estava rolando de volta para o lugar original todas as vezes. Portanto, quando parei de definir layoutManager nos métodos do adaptador de ligação de dados, ele voltou a funcionar bem.
fonte
No meu caso, eu estava configurando o RecyclerView
layoutManager
tanto em XML quanto emonViewCreated
. Remover a atribuição noonViewCreated
consertou.fonte
Activity.java:
Por que estou usando o
OnSaveInstanceState()
inonPause()
significa, embora a mudança para outra atividade onPause seja chamada. Isso salvará a posição do scroll e restaurará a posição quando voltarmos de outra atividade.fonte