quarta-feira, 20 de junho de 2018

Rumo ao Certificado Android: Loaders

No post anterior, vimos que o Sistema Android pode destruir e reconstruir atividades conforme necessário, como na rotação do aplicativo. Entretanto, isso pode ser complicado quando usamos um AsyncTask. Se a activity estiver controlando uma AsyncTask diretamente, um processo de destruição e reconstrução fará com que a AsyncTask responda a Activity destruída, mas não a nova instancia reconstruída, logo, não terá efeito. Ou pior ainda! Irá criar uma nova thread fazendo a mesma coisa, só que para a Activity nova.

Para resolver esse problema, podemos utilizar o Loader e o LoaderManager para gerenciá-los.

Vamos entender como usá-los:

1. Crie uma classe para implementar LoadManager.LoaderCallbacks<T>, onde o T é o resultado do AsyncTask;

public class Classe implements LoaderManager.LoaderCallbacks<String>{
}

O Android Studio vai pedir para importar a classe e criar os métodos da implementação, só fazer o que foi pedido.

2. Criar uma constante para servir como identificador. É recomendado que cada recurso que utilize Loader tenha um ID único.

public class Classe implements LoaderManager.LoaderCallbacks<String>{
private static final int RESOURCE_1 = 10;

}

3. Implementar o método onCreateLoader. Este método possui dois parâmetros, o ID que nós usamos e um Bundle com os parâmetros para carregar. Aqui vamos criar um novo AsyncTaskLoader e implementar seus métodos. O código ficará assim:

public class Classe implements LoaderManager.LoaderCallbacks<String>{
private static final int RESOURCE_1 = 10;

@Override
public Loader<String> onCreateLoader(int id, final Bundle bundle){
return new AsyncTaskLoader<String>(this){

@Override
protected void onStartLoading(){
super.onStartLoading();
if(bundle==null){
return;
}
//Aqui você pode fazer um feedback de loading, por
//exemplo, exibir uma mensagem indicando o inicio
}

@Override
public String loadInBackground(){
//Aqui é a rotina de carregamento, semelhante
//ao AsyncTask visto anteriormente
}
}
}


}

4. Implementar o método onLoadFinished. Esse método vai ser chamado quando a tarefa for concluída. O código fica o seguinte:

public class Classe implements LoaderManager.LoaderCallbacks<String>{
  [...]

@Override
public void onLoadFinished(Loader<String> loader, String data){
//Aqui faz o tratamento do retorno dos dados, seja correto
//erros
}


}

5. Chamar o LoaderManager. Cada Activity tem seu próprio LoadManager e podemos conseguir invocando o método getLoaderManager. Note que dependendo se você estiver usando fragmentos, ou appCompat, pode haver variações no nome, como getSupportLoaderManager. Uma discussão sobre isso pode ser visto aqui. Então, nós tentamos inicializá-lo ou recuperá-lo, dependendo se o mesmo já foi executado antes.

public class Classe implements LoaderManager.LoaderCallbacks<String>{
   private static final int RESOURCE_1 = 10;

   public void startLoad(Activity act, Bundle bundle){
      LoaderManager loaderManager = act.getLoaderManager();
      Loader<String> loader = loaderManager.getLoader(RESOURCE_1);
if(loader == null){
loaderManager.initLoader(RESOURCE_1, bundle, act);
}else{
loaderManager.restartLoader(RESOURCE_1, bundle, act);
}
   }
}

Passo Bônus: Guardar o resultado em cache. Para isso, podemos criar uma propriedade que vai armazenar o retorno do Loader. É uma boa prática se você sabe que o resultado não vai ser diferente para uma mesma consulta, ou algo semelhante. Então, no loadInBackground você pode verificar se o valor que está no cache já é o que deseja e retornar ele, ao invés de recarregar de novamente.

Experiência Própria: Quando usar Loaders ou AsyncTask?
A resposta é bem simples, se é uma Activity, use sempre Loader, caso contrário, use AsyncTask. Se você está seguindo a série "Rumo ao Certificado Android" na ordem de publicação, até agora só trabalhamos com Activity, mas existem outras situações, que no meu caso foi a implementação de um Widget, que não havia como obter um loader, e assim, precisei usar um AsyncTask.

Nenhum comentário:

Postar um comentário