Académique Documents
Professionnel Documents
Culture Documents
Neste exercício, você vai construir uma lista de notas simples que permite ao usuário
adicionar novas notas, mas não editá-los. O exercício demonstra:
Passo 1
Abra o Notepadv1 projeto no Eclipse.
Passo 2
Acessar e modificar dados
Para este exercício, nós estamos usando um banco de dados SQLite para armazenar os
dados.Isso é útil se apenas o seu aplicativo precisa acessar ou modificar os dados. Se você
desejar para outras actividades para acessar ou modificar os dados, você tem que expor os
dados usando umContentProvider .
Se você está interessado, você pode descobrir mais sobre os provedores de conteúdo ou
todo o assunto de armazenamento de dados . A amostra de bloco de notas
na samples/ pasta do SDK também tem um exemplo de como criar um ContentProvider.
No topo da classe são algumas das definições constantes que serão usadas na
aplicação de olhar para cima os dados de nomes de domínio adequado no banco de
dados. Há também uma seqüência de criação de banco de dados definido, que é
usado para criar um esquema novo banco de dados se não existir.
Nosso banco de dados terá o nome data , e tem uma única tabela chamada notes ,
que por sua vez, tem três campos: _id ,title e body . O _id é nomeado com uma
convenção sublinhado usado em um número de lugares no interior do Android SDK e
ajuda a manter uma faixa de estado.O _id geralmente tem que ser especificado ao
consultar ou atualizar o banco de dados (nas projecções da coluna e assim por
diante). Os outros dois são campos de texto simples que irá armazenar os dados.
createNote() tem cordas para o título e corpo de uma nova nota, em seguida, cria a
nota no banco de dados. Assumindo que a nova nota é criada com êxito, o método
também retorna a linha _id valor para o recém-criado nota.
deleteNote() toma um ROWID para uma nota especial, e exclui que a nota do banco
de dados.
fetchAllNotes() emite uma consulta para retornar um Cursor sobre todas as notas
do banco de dados. A query() é chamada de análise estima e compreensão.O
primeiro campo é o nome da tabela de banco de dados para consulta (neste
casoDATABASE_TABLE é "notas"). A próxima é a lista de colunas que deseja que seja
retornada, neste caso queremos que o _id, title e body colunas de forma que estes
são especificados na matriz de String. Os campos restantes são, em
ordem: selection , selectionArgs ,groupBy , having e orderBy . Tendo todos
estes null significa que queremos todos os dados, não precisam de agrupamento, e
tomará a forma padrão.Veja SQLiteDatabase para mais detalhes.
Etapa 3
Layouts e atividades
A maioria das classes de atividades terá um esquema que lhes estão associados. O layout vai
ser o "rosto" da atividade para o usuário. Neste caso, nosso layout vai assumir toda a tela e
fornecer uma lista de notas.
layouts de tela cheia não são a única opção para uma atividade no entanto. Você também pode
querer usar um layout flutuante (por exemplo, umdiálogo ou alerta ), ou talvez você não
precisa de um layout de todo (a atividade será invisível para o usuário, a menos que você
especificar algum tipo de layout para que ele use ).
Etapa 4
Precisamos criar o layout para segurar nossa lista. Adicione o código dentro
doLinearLayout elemento para o arquivo inteiro é assim:
</ LinearLayout>
Para fazer a lista de notas no ListView, também precisamos de definir uma visão para
cada linha:
Esta é a vista que será usado para cada linha de título notas - tem apenas um campo
de texto na mesma.
Neste caso, criamos um novo id chamada text1 . A + após o @ na string id indica que
o ID deve ser automaticamente criado como um recurso se ele já não existir, por isso
estamos definindo text1 na mosca e, em seguida, usá-lo.
3. Salve o arquivo.
Abra o R.java classe no projeto e olhar para ele, você verá novas definições
paranotes_row e text1 (nossas definições novo) o que significa que agora pode ter
acesso a estes a partir do nosso código.
Passo 6
Em seguida, abra o Notepadv1 classe na fonte. Nas etapas seguintes, vamos alterar
essa classe para tornar-se um adaptador de lista e exibir nossas notas, e também nos
permite adicionar novas notas.
Passo 7
Alterar a herança de Notepadv1 deActivity para ListActivity :
Nota: você terá que importarListActivity na classe Notepadv1 usando Eclipse, Ctrl-
Shift-O no Windows ou Linux, ou Cmd-Shift-O no Mac (organizar importações) vai
fazer isso por você depois que você escreveu acima mudar.
Passo 8
Preencha o corpo do onCreate() método.
Aqui vamos definir o título para a atividade (mostrado na parte superior da tela), use
onotepad_list layout que criamos em XML, criada a NotesDbAdapter exemplo, que
terá acesso a dados da nota, e preencher a lista com os títulos de notas disponíveis:
@ Override
onCreate public void (savedInstanceState Bundle) {
super.onCreate (savedInstanceState);
setContentView (R.layout.notepad_list);
mDbHelper = NotesDbAdapter novo (este);
mDbHelper.open ();
fillData ();
}
Passo 9
Mais sobre menus
A aplicação notepad estamos construindo apenas arranhões na superfície, com menus .
Vamos agora criar o "Add Item" botão que pode ser acessada pressionando o botão
de menu do dispositivo. Nós vamos especificar que ocupam a primeira posição no
menu.
@ Override
onCreateOptionsMenu public boolean (menu Menu) {
boolean resultado super.onCreateOptionsMenu = (menu);
menu.add (0, INSERT_ID, 0, R.string.menu_insert);
resultado de retorno;
}
Etapa 10
Preencha o corpo doonOptionsItemSelected() método:
Isto está indo para lidar com o nosso novo "Adicionar Observação" item de
menu.Quando essa opção for selecionada, aonOptionsItemSelected() método será
chamado com o item.getId()definido como INSERT_ID (a constante foi utilizado
para identificar o item de menu).Nós podemos detectar isso, e tomar as ações
apropriadas:
@ Override
public boolean onOptionsItemSelected (MenuItem item) {
switch (item.getItemId ()) {
caso INSERT_ID:
createNote ();
return true;
}
retorno super.onOptionsItemSelected (item);
}
Etapa 11
Adicionar um novo createNote() método:
Nesta primeira versão de nossa aplicação,createNote() não vai ser muito útil. Nós
simplesmente criar uma nova nota com um título que lhe é atribuída com base num
contador ("Nota 1", "Nota 2 "...) e com um corpo vazio. No momento não temos
nenhuma maneira de editar o conteúdo de uma nota, então por enquanto vamos ter
que nos contentar fazendo um com alguns valores padrão:
Etapa 12
Lista de adaptadores
Nosso exemplo usa um SimpleCursorAdapterpara vincular um banco de dados Cursor em
uma ListView, e esta é uma forma comum de usar umaListAdapter . Existem outras opções
comoArrayAdapter que pode ser usado para tirar uma lista ou matriz de dados na memória e
vinculá-lo em uma lista também.
Este é um grande pedaço de código, então vamos primeiro dar uma olhada:
Etapa 13
Executá-lo!
Quando estiver pronto, passe para oExercício 2 Tutorial para adicionar a capacidade
de criar, editar e apagar notas.
Neste exercício, você irá adicionar uma segunda atividade para a sua aplicação bloco
de notas, que permite ao usuário criar e editar notas. Você também vai permitir que o
usuário excluir notas existentes através de um menu de contexto. A nova actividade
assume a responsabilidade de criar novas notas de cobrança de entrada do usuário e
embalá-lo em um pacote de devolução fornecido pela intenção. Este exercício
demonstra:
Passo 1
Criar um novo projeto Android usando as fontes de Notepadv2 sob
aNotepadCodeLab pasta, assim como você fez para o primeiro exercício. Se você ver
um erro sobre AndroidManifest.xml , ou alguns problemas relacionados com
umaandroid.zip arquivo, clique direito sobre o projeto e selecione Android
Ferramentas> Corrigir Propriedades do projeto.
Passo 2
Os menus de contexto deve sempre ser utilizado quando a execução de ações sobre
elementos específicos na interface do usuário. Quando você se registra uma exibição de um
menu de contexto, o menu de contexto é revelado através da realização de um "clique longo"
na componente de interface (pressione e segure o touchscreen ou destaque e mantenha
pressionada a tecla de seleção por cerca de dois segundos).
Primeiro, vamos criar o menu de contexto que permite que os usuários apagar notas
individuais. Abra a classe Notepadv2.
1. Para que cada item da lista no ListView para se inscrever no menu de contexto,
chamamosregisterForContextMenu() e passá-lo nosso ListView. Assim, no final
do onCreate() método de adicionar esta linha:
Etapa 3
Agora que o temos registrado nosso ListView para um menu de contexto e definir o
nosso item de menu de contexto, temos de lidar com o retorno de chamada quando
ele é selecionado. Para isso, precisamos identificar o ID da lista do item selecionado,
em seguida, excluí-lo. Então preencha oonContextItemSelected() método como
este:
public boolean onContextItemSelected (MenuItem item) {
switch (item.getItemId ()) {
caso DELETE_ID:
info AdapterContextMenuInfo = item.getMenuInfo
(AdapterContextMenuInfo) ();
mDbHelper.deleteNote (info.id);
fillData ();
return true;
}
retorno super.onContextItemSelected (item);
}
Etapa 4
Começando Outras Actividades
Neste exemplo, nossa intenção usa um nome de classe específico. Bem como iniciar as
intençõesdas classes que já conhecemos, sejam eles em nosso próprio aplicativo ou outro
aplicativo, também podemos criar Intenções sem saber exatamente qual a aplicação vai lidar
com isso.
Por exemplo, pode querer abrir uma página em um navegador, e por isso ainda usamos uma
intenção.Mas em vez de especificar uma classe para lidar com isso, usamos uma intenção
constante predefinida, e uma URI de conteúdo que descreve o que nós queremos
fazer. Vejaandroid.content.Intent para mais informações.
Esta forma de chamar a intenção alvos de uma classe específica na nossa actividade,
neste caso NoteEdit . Como a classe Intent vai precisar para se comunicar com o
sistema operacional Android para rotear solicitações, nós também temos que oferecer
um contexto ( this ).
Não se preocupe com o fato de queNoteEdit ainda não existe, vamos consertar isso
em breve.
Etapa 5
Preencha o corpo doonListItemClick() substituir.
Passo 6
O acima createNote() eonListItemClick() métodos usam uma invocação
assíncrona Intent. Precisamos de um manipulador para o retorno, então vamos
preencher o corpo doonActivityResult() .
switch (requestCode) {
caso ACTIVITY_CREATE:
String title = extras.getString (NotesDbAdapter.KEY_TITLE);
corpo String extras.getString = (NotesDbAdapter.KEY_BODY);
mDbHelper.createNote (corpo do título);
fillData ();
break;
caso ACTIVITY_EDIT:
Long mRowId = extras.getLong (NotesDbAdapter.KEY_ROWID);
if (mRowId! = null) {
editTitle extras.getString String =
(NotesDbAdapter.KEY_TITLE);
editBody extras.getString String =
(NotesDbAdapter.KEY_BODY);
mDbHelper.updateNote (mRowId, editBody, editTitle);
}
fillData ();
break;
}
Passo 7
A Arte de Layout
O arquivo de layout desde note_edit.xml é o mais sofisticado na aplicação estaremos
construindo, mas isso não significa que ele está sequer perto de o tipo de sofisticação que será
provável que deseja em aplicações reais Android.
Criar uma boa interface é parte arte e ciência da parte, eo resto é trabalho. Domínio
da Declarando Layout é uma parte essencial da criação de uma boa aparência aplicação
Android.
Dê uma olhada na Vistas Olá para alguns layouts exemplo e como usá-los. O projeto de
exemplo ApiDemos também é um recurso excelente para aprender a criar layouts diferentes.
Abra o arquivo note_edit.xml que tenha sido fornecida e dê uma olhada nisso. Este
é o código de interface do usuário para a Nota do Editor.
Esta é a interface mais sofisticada com que lidamos ainda. O arquivo é dado a você
para evitar problemas que podem esgueirar-se ao digitar o código. (O XML é muito
rigorosa sobre a sensibilidade do caso e estrutura, os erros nesses são a causa
comum de problemas com o layout.)
Para dar um exemplo: digamos que temos um rótulo de texto de edição de texto e dois
elementos em uma linha horizontal. O rótulo não tem layout_weight especificado, de
modo a ocupar o espaço mínimo necessário para render. Se o layout_weight de
cada um dos dois campos de texto elementos é definido como 1, a largura restante no
layout do pai será dividido igualmente entre eles (porque dizem que são igualmente
importantes). Se a primeira tem um layout_weight de 1, eo segundo tem
um layout_weight de 2, em seguida, um terço do espaço restante será dado ao
primeiro, e dois terços para a segunda (porque afirmamos que a segunda é mais
importante).
Este layout também demonstra como vários layouts ninho dentro da outra para atingir
um layout mais complexa e agradável.Neste exemplo, um layout horizontal linear está
aninhado a vertical para permitir que o nome do título e campo de texto a ser lado a
lado, horizontalmente.
Passo 8
Criar um NoteEdit classe que estendeandroid.app.Activity .
Esta é a primeira vez que teremos criado uma atividade sem o plugin do Eclipse
Android fazendo isso por nós. Quando você fizer isso, o onCreate() método não é
substituído automaticamente para você. É difícil imaginar uma atividade que não se
sobrepõe à onCreate() método, portanto, esta deve ser a primeira coisa a fazer.
Passo 9
Preencha o corpo do onCreate() método para NoteEdit .
Isto irá definir o título da nossa actividade de novo para dizer "Editar Nota" (uma das
seqüências definidas no strings.xml ).Ele também irá definir a exibição de conteúdo
a utilizar o nossonote_edit.xml arquivo de layout.Podemos então pegas no título e
no corpo do texto editar as vistas, e no botão de confirmação, para que nossa classe
pode usá-los para definir e obter o título da nota e do corpo, e anexar um evento para
o botão confirmar para quando é pressionado por o usuário.
Podemos, então, separar os valores que foram passados para a atividade com o
pacote de extras ligados à intenção de chamada. Vamos usá-las para preencher o
título e corpo de texto editar as vistas para que o usuário pode editá-los. Então vamos
pegar e guardar o mRowId para que possamos acompanhar o que nota o usuário está
editando.
setContentView (R.layout.note_edit);
setTitle (R.string.edit_note);
Note-se que mTitleText emBodyText são campos de membro (você precisa declará-
los no topo da definição de classe).
4. No topo da classe, declare uma Long mRowId campo privado para armazenar a
corrente mRowId sendo editado (se houver).
5. Continuando dentro onCreate() , adicione código para inicializar
otitle , body e mRowId do pacote de extras na intenção (se ele estiver presente):
= null mRowId;
Bundle getIntent extras = () getExtras ().;
if (extras! = null) {
String title = extras.getString (NotesDbAdapter.KEY_TITLE);
corpo String extras.getString = (NotesDbAdapter.KEY_BODY);
extras.getLong mRowId = (NotesDbAdapter.KEY_ROWID);
if (título! = null) {
mTitleText.setText (título);
}
if (corpo! = null) {
mBodyText.setText (corpo);
}
}
o Nós estamos puxando o title ebody para fora do extras pacote que
foi definido a partir da invocação de Intenções.
o Também nulo proteger o campo de texto de configuração (ou seja, nós
não queremos para definir os campos de texto para null acidentalmente).
6. Criar um onClickListener() para o botão:
Ouvintes podem ser um dos aspectos mais confusos de implementação da interface
do usuário, mas o que estamos tentando atingir, neste caso é simples. Queremos
um onClick()método a ser chamado quando o usuário pressiona o botão confirmar, e
usar isso para fazer algum trabalho e retornar os valores da nota editada para o
chamador Intenções. Fazemos isso usando algo chamado uma classe interna
anônima. Isto é um pouco confusa a olhar menos que você tenha visto antes, mas
tudo o que você realmente precisa tirar disso é que você pode consultar esse código
no futuro para ver como criar um ouvinte e anexá-lo a um botão. (Ouvintes são uma
expressão comum no desenvolvimento em Java, em particular para interfaces de
usuário.) Aqui está o ouvinte vazio:
});
Etapa 10
Preencha o corpo do onClick() método da OnClickListener criado na última etapa.
Este é o código que será executado quando o usuário clica no botão
confirmar.Queremos que esta para pegar o título e corpo de texto dos campos de
edição de texto, e colocá-los no pacote de retorno, para que possam ser transferidos
de volta para a atividade que invocou esteNoteEdit Atividade. Se a operação é uma
edição ao invés de criar uma, também queremos colocar o mRowId no pacote para que
o Notepadv2 classe pode salvar as alterações de volta para a nota correta.
1. Criar um Bundle e colocar o título e corpo de texto para ele usar as constantes
definidas em Notepadv2 como chaves:
@ Override
protegidos onCreate void (savedInstanceState Bundle) {
super.onCreate (savedInstanceState);
setContentView (R.layout.note_edit);
= null mRowId;
Bundle getIntent extras = () getExtras ().;
if (extras! = null) {
String title = extras.getString (NotesDbAdapter.KEY_TITLE);
corpo String extras.getString = (NotesDbAdapter.KEY_BODY);
extras.getLong mRowId = (NotesDbAdapter.KEY_ROWID);
if (título! = null) {
mTitleText.setText (título);
}
if (corpo! = null) {
mBodyText.setText (corpo);
}
}
Etapa 11
O Todo-Importante Arquivo Manifest Android
O arquivo AndroidManifest.xml é a maneira em que o Android vê o seu pedido. Este arquivo
define a categoria do aplicativo, onde ele mostra-se (ou mesmo se ele aparece) na tela do
menu ou configurações, quais as actividades, serviços e provedores de conteúdo que define, o
que intenções ele pode receber, e muito mais.
Há um manifesto editor incluído no Eclipse plugin que torna muito mais fácil editar o
arquivo AndroidManifest, e vamos usar isso.Se preferir editar o arquivo diretamente ou
não estiver usando o plugin do Eclipse, consulte a caixa no final para obter
informações sobre como fazer isso sem usar o editor de manifesto novo.
Etapa 12
Agora executá-lo!
Agora você deve ser capaz de adicionar notas reais a partir do menu, bem como
eliminar uma já existente. Observe que, a fim de eliminar, primeiro você deve usar os
controles direcionais no dispositivo para destacar a nota. Além disso, a seleção de um
título da nota da lista deve abrir o editor de notas para permitir que você editá-lo.Prima
confirmar quando terminar para salvar as alterações de volta para o banco de dados.
Agora tente modificar uma nota, e então apertar o botão de volta no emulador, em vez
de o botão confirmar (o botão voltar está abaixo do botão do menu). Você verá uma
mensagem de erro surgir. É evidente que a nossa aplicação ainda tem alguns
problemas. Pior ainda, se você fez algumas alterações e aperte o botão para trás,
quando você voltar para o bloco de olhar para a nota que você mudou, você vai achar
que todas as suas alterações tenham sido perdidos. No próximo exercício, vamos
corrigir esses problemas.
Quando estiver pronto, passe para oExercício 3 Tutorial onde você irá corrigir os
problemas com o botão voltar e perdeu edições através da introdução de um ciclo de
vida adequado para a atividade Noteedit.
↑ Ir para o topo
← Voltar para o bloco de notas Tutorial
Bloco de Notas Exercício 3
Neste exercício, você irá usar callbacks evento do ciclo de vida para armazenar e
recuperar dados de estado do aplicativo.Este exercício demonstra:
Passo 1
Importação Notepadv3 em Eclipse. Se você ver um erro
sobreAndroidManifest.xml, ou alguns problemas relacionados com um arquivo zip
Android, clique direito sobre o projeto e selecione Android Ferramentas> Corrigir
Project Properties no menu de contexto.O ponto de partida para este exercício é
exatamente de onde paramos no final do Notepadv2.
O aplicativo atual tem alguns problemas - apertar o botão de volta ao editar as causas
de uma falha, e tudo o que acontece durante a edição fará com que as edições sejam
perdidas.
Para corrigir isso, vamos passar a maioria das funcionalidades para criar e editar a
nota para a classe Noteedit, e introduzir um ciclo de vida completo de edição de notas.
2. Também vamos nos livrar das propriedades que estavam sendo passados
na extras Bundle, que estávamos usando para definir o título e corpo de texto editar
os valores na interface do usuário. Então delete:
if (título! = null) {
mTitleText.setText (título);
}
if (corpo! = null) {
mBodyText.setText (corpo);
}
Passo 2
Criar um campo de classe para umNotesDbAdapter no topo da classe Noteedit:
mDbHelper.open ();
Etapa 3
Em NoteEdit , precisamos verificar osavedInstanceState para o mRowId , no caso de
edição de nota contém um estado salvo no pacote, que deve se recuperar (o que
aconteceria se a nossa atividade perdeu o foco e depois reiniciado).
= null mRowId;
com esta:
Etapa 4
Em seguida, é preciso preencher os campos com base na mRowId se temos que:
populateFields ();
Etapa 5
Livrar-se da criação de pacote e as configurações de valor Bundle
doonClick() método do manipulador. A atividade não precisa retornar qualquer
informação extra para o chamador. E porque já não temos a intenção de voltar, vamos
usar a versão mais curta do setResult():
super.onCreate (savedInstanceState);
setContentView (R.layout.note_edit);
mTitleText = (EditText) findViewById (R.id.title);
mBodyText = (EditText) findViewById (R.id.body);
populateFields ();
});
Passo 6
Definir o populateFields() método.
Como já vimos, o modelo Android é baseado em torno de atividades de chamar uns aos
outros.Quando uma atividade chama outra, a actividade actual é interrompida pelo menos, e
pode ser morto por completo, se o sistema começa a funcionar com poucos recursos. Se isso
acontecer, a sua actividade terá o suficiente para armazenar o estado a voltar mais tarde, de
preferência no mesmo estado em que estava quando foi morto.
O Android tem um ciclo de vida definido assim . Os eventos do ciclo pode acontecer mesmo se
você não está entregando o controle para outra atividade de forma explícita. Por exemplo,
talvez uma chamada para o aparelho. Se isso acontecer, e sua atividade está em execução,
que será trocada quando a atividade assume a chamada.
a. onSaveInstanceState() :
@ Override
protegidos onSaveInstanceState void (outState Bundle) {
super.onSaveInstanceState (outState);
savestate ();
outState.putSerializable (NotesDbAdapter.KEY_ROWID,
mRowId);
}
@ Override
OnPause protected void () {
super.onPause ();
savestate ();
}
c. onResume() :
@ Override
onResume protected void () {
super.onResume ();
populateFields ();
}
Passo 8
Definir o saveState() método para colocar os dados para o banco de dados.
if (mRowId == null) {
id = longo mDbHelper.createNote (título, corpo);
if (id> 0) {
mRowId = id;
}
Else {}
mDbHelper.updateNote (título, mRowId, corpo);
}
}
Passo 9
Agora puxe o código de tratamento prévio da onActivityResult() método
naNotepadv3 classe.
@ Override
protegidos onActivityResult void (requestCode int, int resultCode,
a intenção Intent) {
super.onActivityResult (requestCode, resultCode intenção);
fillData ();
}
Porque a outra classe agora faz o trabalho, tudo isso tem que fazer é atualizar os
dados.
Etapa 10
Também remove as linhas que definem o título eo corpo
do onListItemClick()método (mais uma vez que já não são necessários, apenas
os mRowId é):
Cursor mNotesCursor = c;
c.moveToPosition (posição);
e também remover:
Executá-lo! (Usar Executar como -> Androiddo aplicativo no menu da direita, clique em
projeto de novo)
Quando estiver pronto, passe para o Tutorial de crédito extra de exercícios, onde você
pode usar o depurador Eclipse para analisar o ciclo de eventos de vida como eles
acontecem.
Bloco de notas de crédito extra
Neste exercício, você usará o depurador para olhar o trabalho que você fez no
Exercício 3. Este exercício demonstra:
Passo 1
Usando o trabalho Notepadv3 , colocar pontos de interrupção no código no início
doonCreate() , onPause() ,onSaveInstanceState() eonResume() métodos
na NoteEditclasse (se você não estiver familiarizado com o Eclipse, basta clicar no
estreito borda cinza no lado esquerdo da janela de edição na linha que você quer um
ponto de interrupção e escolha Alternar ponto de interrupção, você deverá ver um
ponto azul aparecer).
Passo 2
Agora inicie o notepad demo no modo de depuração:
Etapa 3
Quando você editar ou criar uma nova nota que você deve ver os pontos de
interrupção ser atropelado e à suspensão da execução.
Etapa 4
Aperte o botão Resume para permitir a execução prosseguir (retângulo amarelo com
um triângulo verde à sua direita na barra de ferramentas Eclipse perto do topo).
Etapa 5
Experimente um pouco com os botões de confirmar e voltar, e tentar pressionando
Home e fazer mudanças outro modo. Veja o que os eventos de ciclo de vida são
gerados e quando.