O aplicativo nem sempre consiste em uma única tela. Por exemplo, criamos um muito programa útil e o usuário quer saber quem é o autor. Ele clica no botão “Sobre” e chega a uma nova tela com informações úteis sobre a versão do programa, o autor, o endereço do site, quantos gatos o autor tem, etc. Pense em uma tela de atividade como uma página da Web com um link para outra página. Se você olhar para o código no arquivo MainActivity.java das lições anteriores, você verá que nossa classe Atividade principal também se aplica a Atividade(ou seus herdeiros) ou, para ser mais preciso, é herdado dele.
Classe pública MainActivity estende AppCompatActivity
Como você pode imaginar, devemos criar uma nova classe que possa se parecer com Atividade principal e, de alguma forma, mude para ele ao clicar no botão.
Para o experimento, pegaremos o programa da primeira lição e usaremos o botão para experimentos (ou criaremos novo projeto com um botão na tela). A seguir, vamos criar nova forma mostrar informação útil. Por exemplo, vamos mostrar ao usuário o que o gato faz quando vai para a esquerda e para a direita. Concordo, é muito informação importante, que dá a chave para desvendar o universo.
Vamos criar uma nova atividade manualmente, embora o estúdio tenha templates prontos. Mas não há nada complicado e para uma melhor compreensão é útil fazer tudo à mão.
Vamos criar um novo arquivo de marcação XML activity_about.xml na pasta resolução/layout. Clique com o botão direito na pasta esquema e escolha de menu contextual Novo | Arquivo de recurso de layout. Uma caixa de diálogo aparecerá. Digite o nome do arquivo no primeiro campo atividade_sobre. No segundo, você precisa inserir o elemento raiz. Por padrão está lá Layout de restrição. Apague o texto e digite visualização de rolagem. Basta digitar alguns caracteres para que o estúdio sugira opções prontas, você pode pressionar Enter imediatamente sem esperar a entrada completa da palavra:
Obtemos o espaço em branco correspondente, no qual inserimos o elemento visualização de texto.
As informações serão recuperadas dos recursos, ou seja, de um recurso de string sobre_texto. Agora está destacado em vermelho, sinalizando a ausência de informações. poderia ser pressionado Alt+Enter e digite o texto na caixa de diálogo. Mas para o nosso exemplo, esse método não funcionará, pois nosso texto será de várias linhas, usando caracteres de controle. Então vamos fazer diferente. Vamos abrir o arquivo res/valores/strings.xml e digite o seguinte texto manualmente:
Usamos as tags de formatação de texto HTML mais simples, como , , . Para o nosso exemplo, basta colocar em negrito as palavras que se referem ao gato e à direção do movimento. Para traduzir o texto em nova linha use símbolos \n. Vamos adicionar outro recurso de string para o título da nova tela:
Entendido com marcação. Em seguida, você precisa criar uma classe para a janela SobreActivity.java. Escolha no menu arquivo | Novo | classe Java e preencha os campos obrigatórios. A princípio, basta especificar apenas o nome. Em seguida, lide com outros campos.
Vamos à preparação.
Agora a sala de aula está quase vazia. Vamos adicionar o código manualmente. A classe deve herdar da classe abstrata Atividade ou seus parentes FragmentActivity, AppCompatActivity etc. Adicionando estende Atividade. A classe de atividade deve ter um método onCriar(). Coloque o cursor do mouse dentro da classe e selecione no menu código | Métodos de substituição(Ctrl+O). Na caixa de diálogo, estamos procurando a classe desejada, você pode digitar os primeiros caracteres no teclado para pesquisa rápida. No método criado, você precisa chamar o método setContentView(), que carregará a marcação preparada na tela. Teremos essa opção.
Pacote en.alexanderklimov.helloworld; import android.app.Activity; importar android.os.Bundle; /** * Criado por Alexander Klimov em 01/12/2014. */ public class AboutActivity extends Activity ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Agora começa o mais importante. Nossa tarefa é passar para uma nova tela quando um botão é clicado na primeira tela. Vamos voltar para a aula Atividade principal. Vamos escrever o manipulador de clique do botão:
Public void onClick(View view) ( Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Aqui eu usei o método de manipulação de clique de botão descrito na lição.
Para iniciar uma nova tela, você precisa criar uma instância da classe Intenção e especifique a classe atual no primeiro parâmetro, e a classe para a transição no segundo, temos isso Sobre a atividade. Depois disso, o método é chamado startActivity(), que abre uma nova tela.
Se agora você tentar testar o aplicativo no emulador, receberá uma mensagem de erro. O que fizemos de errado? Perdemos um passo importante. Você precisa registrar um novo Atividade no manifesto AndroidManifest.xml. Encontre este arquivo em seu projeto e clique duas vezes nele. A janela de edição do arquivo será aberta. Adicionar uma nova etiqueta
É aqui que o recurso string é útil about_title. Execute o aplicativo, clique no botão e obtenha a janela Sobre o programa. Assim, aprendemos como criar uma nova janela e chamá-la com um clique de botão. E um programa mega conveniente apareceu à nossa disposição - agora sempre haverá uma dica do que o gato faz quando vai para a esquerda.
Mais uma vez, chamo sua atenção para o fato de que a segunda classe de atividade criada deve ser herdada da classe Atividade ou similar ( Listar atividade etc.), ter um arquivo de marcação XML (se necessário) e ser escrito no manifesto.
Após chamar o método startActivity() uma nova atividade será iniciada (neste caso Sobre a atividade), ele ficará visível e será movido para o topo da pilha que contém os componentes em execução. Ao chamar um método Finalizar() da nova atividade (ou quando a tecla de retrocesso do hardware for pressionada) ela será fechada e removida da pilha. O desenvolvedor também pode navegar para a atividade anterior (ou qualquer outra) usando o mesmo método startActivity().
Criando uma terceira tela - um caminho para os preguiçosos
Programadores, como gatos, são criaturas preguiçosas. Lembre-se sempre que para a atividade você precisa criar marcação e uma classe que herda de Atividade, e depois não se esqueça de registrar a classe no manifesto - ah, que diabos.
Neste caso, selecione no menu arquivo | Novo | atividade | atividade básica(ou outro padrão). Em seguida, a janela familiar para criar uma nova atividade aparecerá. Preencha os campos obrigatórios.
Clique no botão Terminar e a atividade estará pronta. Para verificar isso, abra o arquivo de manifesto e verifique a nova entrada. Não estou falando de arquivos de classe e marcação, eles aparecerão na sua frente.
Adicione você mesmo um novo botão na tela da atividade principal e escreva o código para navegar até a atividade criada.
A princípio, aconselho você a criar manualmente todos os componentes necessários para uma nova atividade para entender a relação entre a classe, marcação e manifesto. E quando você colocar as mãos nele, poderá usar o assistente de criação de atividades para acelerar as coisas.
Passando dados entre atividades
Usamos o exemplo mais simples para chamar outra tela de atividade. Às vezes, é necessário não apenas chamar uma nova tela, mas também transferir dados para ela. Por exemplo, nome de usuário. Neste caso, você precisa usar uma área especial extraData, que a classe tem Intenção.
Região extraDataé uma lista de pares valor chave, que é passado junto com a intenção. Strings são usadas como chaves, e para valores você pode usar quaisquer tipos de dados primitivos, arrays de primitivos, objetos de classe pacote e etc
Para passar dados para outra atividade, use o método putExtra():
Intent.putExtra("Chave", "Valor");
A atividade de recebimento deve chamar algum método apropriado: getIntExtra(), getStringExtra() etc.:
Int contagem = getIntent().getIntExtra("nome", 0);
Vamos refazer o exemplo anterior. Já temos três atividades. A primeira atividade terá dois campos de texto e um botão. A aparência pode ser a seguinte:
Na segunda atividade Segunda atividade definir o elemento visualização de texto, no qual exibiremos o texto recebido da primeira atividade. Vamos escrever o seguinte código para o método onCriar() na segunda atividade.
@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String gift = "donut hole"; TextView infoTextView = (TextView)findViewById( R .id.textViewInfo); infoTextView.setText(user + ", você recebeu " + presente); )
Se agora executarmos o programa e simplesmente chamarmos a segunda janela, conforme descrito na primeira parte do artigo, veremos a inscrição padrão ZhYvotnoe, você recebeu um buraco de rosquinha. Concordo, é uma pena receber essas mensagens.
Corrigimos a situação. Adicione código à primeira atividade:
Public void onClick(View view) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Intent intent = new Intent(MainActivity.this, SecondActivity. class); // envia o texto do primeiro campo de texto para a chave de nome de usuário intent.putExtra("username", userEditText.getText().toString()); // envia o texto do segundo campo de texto para a chave de presente intent.putExtra("presente ", giftEditText.getText().toString()); startActivity(intent); )
Colocamos em um recipiente de objeto especial Intenção duas chaves com valores retirados de campos de texto. Quando o usuário insere dados nos campos de texto, eles cairão nesse contêiner e serão passados para a segunda atividade.
A segunda atividade deve estar pronta para receber mensagens calorosamente como segue (destacada em negrito).
// Valores padrão String user = "LIFE"; String presente = "buraco de rosquinha"; usuário = getIntent().getExtras().getString("username"); presente = getIntent().getExtras().getString("presente"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , você recebeu " + presente);
Agora a mensagem não parece tão ofensiva, mas até agradável para alguns. Em exemplos complexos, é desejável adicionar validação durante o processamento de dados. Há situações em que você inicia uma segunda atividade com dados vazios como nulo, que pode travar o aplicativo.
No nosso caso, sabemos que estamos esperando por um valor de string, então o código pode ser reescrito assim:
intenção intenção = getIntent(); usuário = intent.getStringExtra("username");
Usuário = getIntent().getStringExtra("username");
O programa tem uma desvantagem - não está claro de quem recebemos saudações. Qualquer macaco bem-educado não aceitará um presente de uma fonte anônima. Portanto, como lição de casa, adicione outro campo de texto para inserir o nome do usuário que está enviando a mensagem.
O Google recomenda usar o seguinte formato para chaves: o nome do seu pacote como prefixo, seguido pela própria chave. Nesse caso, você pode ter certeza de que a chave é exclusiva ao interagir com outros aplicativos. Aproximadamente assim:
Final pública static String USER = "ru.alexanderklimov.myapp.USER";
Quem incriminou o gato Vaska - recuperamos o resultado
Nem sempre é suficiente simplesmente passar dados para outra atividade. Às vezes, você precisa obter informações de outra atividade quando ela é fechada. Se antes usávamos o método startActivity(Intent intent), então existe um método relacionado startActivityForResult(Intent intent, int RequestCode). A diferença entre os métodos está no parâmetro extra código de solicitação. É basicamente apenas um número inteiro que você pode pensar em si mesmo. É necessário para distinguir de quem veio o resultado. Digamos que você tenha cinco telas adicionais e atribua valores de 1 a 5 a elas, e a partir desse código você pode determinar qual resultado precisa processar. Você pode usar o valor -1, então será equivalente a chamar o método startActivity(), ou seja não teremos nenhum resultado.
Se você estiver usando o método startActivityForResult(), então você precisa substituir o método no código para receber o resultado onActivityResult() e processar o resultado. Confuso? Vamos dar uma olhada em um exemplo.
Digamos que você seja um detetive. Foram recebidas informações de que dois pedaços de salsicha e outros produtos foram roubados da mesa de uma pessoa influente no restaurante. A suspeita recaiu sobre três suspeitos - um corvo, uma porra de cachorro e gato Vaska.
Um dos visitantes forneceu uma série de fotos de seu iPhone do pontão:
Há também depoimento de outra testemunha: E Vaska ouve e come.
Criamos um novo projeto Sherlock com duas atividades. Na primeira tela haverá um botão para mudar para a segunda tela e um rótulo de texto que exibirá o nome do ladrão.
A segunda tela terá um grupo de botões de opção:
Como estaremos aguardando uma resposta da segunda tela, precisamos usar o método startActivityForResult() na primeira tela onde passaremos a variável CHOOSE_THIEF como parâmetro código de solicitação.
estático final privado int CHOOSE_THIEF = 0; public void onClick(View v) ( Intent questionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Olhe para o código. Quando o botão for clicado, vamos trabalhar com a segunda tela Escolher Atividade e inicie a segunda tela aguardando o resultado.
Passamos para a segunda tela e escreveremos o código para a segunda atividade.
Public final static String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(Visualizar v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Fucking Dog"); break; case R.id .radioCrow: answerIntent.putExtra(THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra(THIEF, "Przewalski's Horse"); break; default: break; ) setResult(RESULT_OK, answerIntent); final (); )
Tudo é simples aqui, quando o detetive seleciona o nome do criminoso, então através do método putExtra() passamos o nome da chave e seu valor.
Por conveniência, após a seleção, fechamos imediatamente a segunda janela e passamos o valor antes de fechar RESULT_OK para deixar claro que a escolha foi feita. Caso o usuário feche a tela através do botão Voltar, o valor será passado RESULT_CANCELED.
Método setResult() recebe dois parâmetros: o código resultante e o próprio resultado, representado como uma intenção. O código resultante diz com qual resultado a atividade terminou, como regra, é Activity.RESULT_OK, ou Activity.RESULT_CANCELED. Em alguns casos, você precisa usar seu próprio código de retorno para lidar com opções específicas do aplicativo. Método setResult() suporta qualquer valor inteiro.
Se você passar dados explicitamente pelo botão, seria bom adicionar um método Finalizar() para fechar a segunda atividade como desnecessária. Se a transição ocorrer através do botão Voltar, isso não é necessário.
Se a atividade foi fechada pelo usuário quando o botão Voltar do hardware foi pressionado ou se o método Finalizar() foi chamado antes do método setResult(), o código resultante será definido como RESULT_CANCELED e a intenção retornada mostrará o valor nulo.
Voltamos à primeira tela. A primeira tela está aguardando uma resposta da segunda tela, então você precisa adicionar um método ao código onActivityResult().
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == CHOOSE_THIEF) ( if (resultCode == RESULT_OK) ( String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // apaga texto ) ) )
O método espera dados de entrada com código CHOOSE_THIEF, e se esses dados chegarem, extrai o valor da chave Escolha Atividade. LADRÃO usando o método getStringExtra. Emitimos o valor resultante para visualização de texto(variável infoTextView). Se voltamos à tela através do botão Voltar, simplesmente apagamos o texto.
Quando a atividade filho é fechada dentro do componente pai, o manipulador é acionado onActivityResult(). Manipulador onActivityResult() recebe vários parâmetros.
- Código de solicitação. O código usado para iniciar a atividade que retorna o resultado
- O código resultante. Um código de resultado definido pela atividade filha que indica como a atividade filha terminou. Pode ser qualquer valor inteiro, mas geralmente Activity.RESULT_OK, ou Activity.RESULT_CANCELED
- Dados. A intenção usada para empacotar os dados retornados. Dependendo da finalidade da atividade filha, ela pode incluir um caminho de URI representando o conteúdo selecionado. Alternativamente (ou adicionalmente), uma atividade filho pode retornar informações como valores simples envolvidos em um parâmetro de intenção extras
Se a atividade filha terminou inesperadamente, ou se nenhum código de resultado foi especificado antes de fechá-la, este parâmetro se tornará igual a Activity.RESULT_CANCELED.
Iniciamos o projeto, clicamos no botão e vamos para a segunda tela. Lá selecionamos uma das opções. Se você selecionar um corvo, a tela será fechada e o nome do criminoso será exibido na primeira tela. Se você selecionar um cachorro, seu nome será exibido.
A propósito, se você selecionar um gato, seu nome não será exibido! Verifique e veja por si mesmo. Você vai perguntar por quê? Watson elementar! O infrator não levou em conta um detalhe importante. O restaurante estava sob vigilância de câmeras de vídeo, e a gravação mostrou quem realmente roubou a salsicha e incriminou o gato. Vaska, espera!
P.S. Se a princípio algo parecia incompreensível, com a prática muita coisa ficará clara. A passagem de dados entre telas é comum em aplicativos e você estudará o exemplo mais de uma vez.
P.P.S. O melhor peixe é a salsicha. Conhecendo essa fraqueza, não foi difícil enquadrar o gato.
Usando filtros
No artigo, mostrei uma forma comum de mudar para outra atividade, quando no método startActivity() a classe atual e a classe para transição são indicadas. A propósito, a classe de atividade não precisa fazer parte do seu aplicativo. Se você souber o nome de uma classe de outro aplicativo, poderá alternar para isso também. Mas você pode alternar para outra atividade de uma maneira diferente.
Menos comum na prática, mas útil. Digamos que você já tenha uma segunda atividade. No manifesto, adicione um filtro especial a ele:
E lançamos a segunda atividade através de um clique de botão desta forma.
Public void onClick(View view) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
Vamos substituir uma string longa por uma constante.
Final estático público String ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(View view) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Então, o que fizemos. Para a segunda atividade, registramos um filtro e especificamos um nome para ação no atributo android:nome. Por conveniência, coloquei nele o nome completo da atividade com o nome do pacote. Construtor de classe Intenção tem várias versões sobrecarregadas. Em uma versão, você pode especificar uma string para a ação. Indicamos nossa ação criada, que fica registrada na segunda atividade. O sistema examina os manifestos de todos os aplicativos instalados durante a operação. Ao procurar uma correspondência, o sistema encontra nosso filtro e inicia a atividade desejada.
Pelo mesmo princípio, você pode iniciar outras atividades. Veja um exemplo. Se você copiar o exemplo para si mesmo e consultar a documentação para android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, você verá que este código corresponde a uma constante de string public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Compare com o nosso código. Você pode supor que a atividade de configurações para o modo offline tenha essa linha no filtro.
Filtrar nome da categoria android.intent.category.DEFAULT informa ao sistema para executar a ação padrão, que é iniciar a atividade. Existem outros nomes que ainda não nos interessam.
E agora uma pergunta complicada. O que acontece se você criar outra atividade e especificar o mesmo filtro da segunda atividade? E vamos verificar. Crie uma terceira atividade para você e copie o bloco com o filtro da segunda atividade para ele.
Clicamos no botão na primeira atividade. O sistema solicitará que você selecione a opção desejada.
Se você selecionar o item SEMPRE então da próxima vez você não terá que escolher. Para redefinir a seleção, vá para as propriedades do aplicativo em Configurações e encontre o botão limpar padrões.
Iniciar uma atividade pelo nome
No construtor Intenção O segundo parâmetro é a classe. Mas vamos supor que exista algum tipo de banco de dados onde os nomes das atividades são indicados e precisamos iniciar a atividade desejada pelo seu nome. Podemos obter a própria classe com base na variável string e iniciar a atividade.
Try ( // Nome completo da classe de atividade String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // obtém o objeto Class Class>minhaClasse = Class.forName(activityName); Intent intent = new Intent(this, myClass); startActivity(intenção); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
De alguma forma eu tinha a tarefa de transferir dados do serviço para a atividade. A busca por uma solução no SDK padrão começou, mas como não havia tempo, tomei uma decisão ruim na forma de usar um banco de dados. Mas a questão ficou em aberto e depois de um tempo descobri uma forma mais correta que está no SDK - usando as classes Message, Handler, Messenger.
Idéia
Precisamos transferir dados da atividade para o serviço e vice-versa. Como podemos fazer isso? Para resolver nosso problema, já temos tudo o que precisamos. Tudo o que é necessário é vincular o serviço à atividade usando bindService, passar os parâmetros necessários e um pouco de mágica na forma de usar as classes Message. E a mágica é usar variáveis de instância Message e, em particular, replyTo. Precisamos dessa variável para que possamos acessar a instância do serviço Messanger da atividade e no serviço para a instância do Messanger da atividade. Na verdade, não é tão simples. Pelo menos para minha mente não tão talentosa. Em parte estou apenas melhorando a documentação que já existe - Serviços Além disso, há um bom exemplo no StackOverflow. De qualquer forma, espero que o artigo seja útil para pelo menos alguém e não trabalhei em vão.
Exemplo
Como exemplo, vamos implementar um serviço que irá incrementar e decrementar o valor do contador e retornar o resultado em uma atividade, em um TextView. Vou omitir o código do layout, porque existem dois botões e um campo de texto - tudo é simples.
Implementação
Aqui está o código de ativação completo:
Classe pública MainActivity estende Activity ( public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final mensageiro mensageiro= new Mensageiro(new IncomingHandler()); Messenger paraServiceMessenger; @Override public void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt); bindService(new Intent(this, TestService.class ), (testServConn = new TestServiceConnection()), Context.BIND_AUTO_CREATE); ) @Override public void onDestroy()( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(View button)( Message msg = Message. get(null, TestService.COUNT_PLUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(View button)( Message msg = Message.obtain(null, TestService.COUNT_MINUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) private class IncomingHandler extends Handler ( @Override public void handleMessage(Message msg)( switch (msg.what) ( case TestServic e.GET_COUNT: Log.d(TAG, "(atividade)... obter contagem"); testTxt.setText(""+msg.arg1); parar; ) ) ) classe privada TestServiceConnection implementa ServiceConnection ( @Override public void onServiceConnected(nome do componente, serviço IBinder) ( toServiceMessenger = new Messenger(service); //send valor inicial contador Mensagem msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = mensageiro; msg.arg1 = 0; //nosso contador try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
Deixe-me explicar. Ao criar uma atividade, ligamos imediatamente ao serviço implementando a interface ServiceConnection e enviamos uma mensagem para o serviço “definir o valor do contador” nela, passando zero e criando um toServiceMessanger, passando a interface IBinder para o construtor. A propósito, esta instância deve ser retornada no serviço, caso contrário haverá NPE. Com a ajuda desta classe, enviamos mensagens para o serviço. E aqui é mágica - na variável replyTo salvamos nossa outra instância do Messenger - aquela que recebe uma resposta do servidor e é por meio dela que a comunicação com a atividade será realizada.
Para receber uma mensagem do serviço, usamos nosso Handler e simplesmente procuramos as variáveis que precisamos e fazemos ações nelas. Ao clicar no botão (métodos countIncrClick, countDecrClick) enviamos solicitações ao serviço, especificando a ação desejada na variável msg.what.
Pacote com.example.servicetest; importar android.app.Service; import android.content.*; import android.os.*; importar android.os.Process; importar android.util.Log; classe pública TestService estende Serviço ( public static final int COUNT_PLUS = 1; public static final int COUNT_MINUS = 2; public static final int SET_COUNT = 0; public static final int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; Messenger messenger; Messenger toActivityMessenger; @Override public void onCreate()( super.onCreate(); HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread.getLooper()); mensageiro = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int flags, int startId) ( return START_STICKY; ) //manipulador de mensagem activity private class IncomingHandler extends Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Message msg)( //super.handleMessage(msg); toActivityMess enger = msg.replyTo; switch (msg.what) ( case SET_COUNT: count = msg.arg1; Log.d(MainActivity.TAG, "(service)...set count"); break; case COUNT_PLUS: count++; Log.d(MainActivity.TAG , "(service)...count plus"); break; case COUNT_MINUS: Log.d(MainActivity.TAG, "(service)...count minus"); count--; break; ) //enviando o contador valor na atividade Mensagem outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = contagem; outMsg.replyTo = mensageiro; try ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) ) )
Tudo por analogia com a lógica da atividade. Eu nem sei se preciso explicar alguma coisa. O único ponto é que eu imediatamente envio a solicitação de volta para a atividade no handleMessage, usando a variável magic replyTo para isso e puxando o Messenger desejado acima. E o segundo ponto que já mencionei é:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
sem a qual tudo cairá. É esta instância de interface que será passada para o ServiceConnection
Conclusão
Contudo. Um exemplo artificial da interação entre uma atividade e um serviço. Parece-me uma interação bastante não trivial, embora possa parecer diferente para alguém.
Dúvidas, esclarecimentos, etc. Pode haver imprecisões sobre quaisquer aspectos, então sinta-se à vontade para escrever e corrigir.
Espero que o post tenha sido útil para os leitores.
Olá.
É necessário transferir os dados recebidos através da UART para a Atividade. Isso pode ser feito criando um thread na Activity para organizar um loop while (!isInterrupted()) e ler dados do buffer UART. Depois disso, chamando a thread de UI da Activity - MainActivity.this.runOnUiThread(new Runnable() , execute as ações necessárias com esta Activity. Mas se chamarmos outras Activities da Activity principal, então a thread organizada não permite passar dados para as atividades recém-criadas. Se eu entendi corretamente que para que os dados do fluxo sejam transferidos para qualquer atividade, o fluxo deve ser criado não na atividade, mas no serviço.
Pergunta: os dados vieram via UART, no thread (que é criado no Servce) é necessário transferir dados para a Activity, que agora está ativa, como isso pode ser feito e é feito?
1 resposta
Em cada Activity, crie um Handler. No método onResume() desta Activity, bindService() é feito. Lá, um dos parâmetros é a interface ServiceConnection. Implemente-o com pelo menos a mesma Activity. Implemente o método onServiceConnected() nele. Nesse callback, o próprio Service vem como um dos parâmetros. Portanto, chame este serviço de seu próprio método setHandler(). Passe lá o Handler que está na Activity atual. Mas jogue os dados recebidos via UART no serviço neste manipulador. A propósito, o Handler tradicionalmente é executado no thread principal, portanto, runOnUiThread não precisará ser executado.