LoaderManager.LoaderCallbacks é uma interface de callback que permite que um cliente interaja com o LoaderManager .
Loaders, em especial o CursorLoader, são esperados para reter seus dados depois de ser interrompido. Isso permite aos aplicativos que mantenham seus dados através dos métodos onStop() e onStart() da atividade ou fragmento, de modo que quando os usuários retornam a um pedido, eles não tem que aguardar os dados para recarregarem. Você usa o método LoaderManager.LoaderCallbacks quando quer saber quando criar um carregador novo, e para dizer a aplicação quando é hora de parar de usar um gerenciador de dados.
LoaderManager.LoaderCallbacks inclui os seguintes métodos:
onCreateLoader() - instancia e retorna um novo Loader para o ID dado.
onLoadFinished() - Chamado quando um loader criado anteriormente terminou sua carga.
onLoaderReset() - Chamado quando um loader criado anteriormente está sendo redefinido, tornando os dados disponíveis.
Esses métodos são descritos em detalhes nas seções seguintes. onCreateLoader
Quando você tenta acessar um loader (por exemplo, através initLoader()), ele verifica se o carregador especificado pelo ID existe. Se isso não ocorrer, ele aciona o método onCreateLoader() do LoaderManager.LoaderCallbacks. Isto é onde você irá criar um carregador novo. Normalmente, esse será um CursorLoader, mas você pode implementar sua própria subclasse Loader.
Neste exemplo, o onCreateLoader() cria um método de retorno CursorLoader. Você deve construir o CursorLoader usando o método construtor, que exige um conjunto completo de informações necessárias para realizar uma consulta para o ContentProvider. Especificamente, é necessário:
URI - A URI para o conteúdo para recuperar.
projeção - uma lista de quais colunas retornar. Passando null irá retornar todas
as colunas, que é ineficiente.
seleção - Um filtro que declara que as linhas de retorno, formatado como uma
cláusula WHERE SQL (excluindo o próprio WHERE). Passando null retornará todas as linhas para o URI especificado.
selectionArgs - Você pode incluir ?s na seleção, que serão substituídas pelos
valores da selectionArgs, na ordem em que aparecem na seleção. Os valores serão vinculados como Strings.
SortOrder - Como adquirir as linhas, formatado como uma cláusula ORDER BY
de SQL (excluindo-se o ORDER BY). Passando null usará a ordem de classificação padrão, que pode ser desordenada.
// If non-null, this is the current filter the user has provided.
String mCurFilter; ...
publicLoader<Cursor> onCreateLoader(int id,Bundle args){
// This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering.
Uri baseUri;
if(mCurFilter !=null){
baseUri =Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
}else{
baseUri =Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed.
Stringselect="(("+Contacts.DISPLAY_NAME +" NOTNULL) AND ("
+Contacts.HAS_PHONE_NUMBER +"=1) AND ("
+Contacts.DISPLAY_NAME +" != '' ))";
returnnewCursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION,select,null,
onLoadFinished
Este método é chamado quando um loader criado anteriormente terminou sua carga. Este método é garantido para ser chamado antes do lançamento do último dado que foi fornecido para este carregador. Neste ponto, você deve remover todo uso dos dados antigos (desde que será lançado em breve), mas não deve fazer a seu próprio lançamento dos dados desde o seu carregador é o dono e vai cuidar disso.
O carregador vai lançar os dados, uma vez que conhece que o aplicativo não está mais usando. Por exemplo, se os dados são um cursor de um CursorLoader, você não deve chamar close() sobre ele mesmo. Se o cursor está sendo colocado em um CursorAdapter, você deve usar o método swapCursor() para que o antigo Cursor não seja fechado. Por exemplo:
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter; ...
publicvoid onLoadFinished(Loader<Cursor> loader,Cursor data){
// Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.)
mAdapter.swapCursor(data); }
onLoaderReset
Este método é chamado quando um loader criado anteriormente está sendo redefinido, tornando os seus dados indisponíveis. Este retorno permite saber quando o dado está prestes a ser liberado assim você pode remover a referência a ele.
Esta aplicação chama swapCursor() com um valor null:
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter; ...
publicvoid onLoaderReset(Loader<Cursor> loader){
// This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it.
mAdapter.swapCursor(null); }
Exemplo
Como exemplo, aqui é a implementação completa de um Fragment que apresenta um ListView com os resultados de uma consulta contra o provedor de conteúdo contatos. Ele usa um CursorLoader para gerenciar a consulta do fornecedor.
Para uma aplicação para acessar os contatos de um usuário, como mostrado neste exemplo, o manifesto deve incluir a permissão READ_CONTACTS .
publicstaticclassCursorLoaderListFragmentextendsListFragment
implementsOnQueryTextListener,LoaderManager.LoaderCallbacks<Cursor>{
// This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter;
// If non-null, this is the current filter the user has provided. String mCurFilter;
@Overridepublicvoid onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real // application this would come from a resource.
setEmptyText("No phone numbers");
// We have a menu item to show in action bar. setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data. mAdapter =newSimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2,null,
newString[]{Contacts.DISPLAY_NAME,Contacts.CONTACT_STATUS },
newint[]{ android.R.id.text1, android.R.id.text2 },0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one, // or start a new one.
getLoaderManager().initLoader(0,null,this);
}
@Overridepublicvoid onCreateOptionsMenu(Menu menu,MenuInflater inflater){
// Place an action bar item for searching. MenuItem item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView sv =newSearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
// Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter.
mCurFilter =!TextUtils.isEmpty(newText)? newText :null;
getLoaderManager().restartLoader(0,null,this);
returntrue;
}
@Overridepublicboolean onQueryTextSubmit(String query){
// Don't care about this. returntrue;
}
@Overridepublicvoid onListItemClick(ListView l,View v,int position,long id){
// Insert desired behavior here.
Log.i("FragmentComplexList","Item clicked: "+ id);
}
// These are the Contacts rows that we will retrieve.
staticfinalString[] CONTACTS_SUMMARY_PROJECTION =newString[]{
Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, };
publicLoader<Cursor> onCreateLoader(int id,Bundle args){
// This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering.
Uri baseUri;
if(mCurFilter !=null){
baseUri =Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
}else{
baseUri =Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed.
Stringselect="(("+Contacts.DISPLAY_NAME +" NOTNULL) AND ("
+Contacts.HAS_PHONE_NUMBER +"=1) AND ("
+Contacts.DISPLAY_NAME +" != '' ))";
returnnewCursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION,select,null,
Contacts.DISPLAY_NAME +" COLLATE LOCALIZED ASC");
}
publicvoid onLoadFinished(Loader<Cursor> loader,Cursor data){
// Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.)
mAdapter.swapCursor(data);
publicvoid onLoaderReset(Loader<Cursor> loader){
// This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it.
mAdapter.swapCursor(null);
} }