Como falar sobre os principais componentes do Android em 15 minutos

1. Introdução


Este artigo discutirá como informar uma pessoa que não estava familiarizada com a programação para Android sobre seus principais componentes. Interessar e mostrar que nem tudo é tão difícil quanto muitas pessoas pensam. Ao mesmo tempo, faça isso em 15 minutos e sem entrar em uma explicação de alguma teoria básica que todos possam ler por si mesmos e voltar com perguntas esclarecedoras.


Quando tentei fazer isso pela primeira vez, fiquei desagradavelmente surpresa comigo mesma. Minha explicação "simples e compreensível" tornou-se entediante, dentro da estrutura da qual uma tentativa desesperada de apreender a imensidão e contar em poucas palavras sobre tudo um pouco foi claramente traçada. Escusado será dizer que é provável que essa história não interesse, mas assusta seu interlocutor, enquanto diminui o desejo de fazer algo próprio, mesmo se você já tivesse uma pequena calculadora em seus planos.


Não é segredo que um grande número de artigos sobre esse tópico seja publicado na Internet, mas, no meu caso, a narrativa será um pouco diferente: haverá apenas prática visual, sem definições e outros detalhes. Ou seja, olhamos - vemos - comentamos o que está acontecendo. Parece, na minha opinião, tudo é bastante simples e claro, os trechos de código também são pequenos e muito simples, prontos para uso rápido em seu próprio projeto. Parece-me que essa abordagem fornece uma visão geral bastante ampla das ferramentas clássicas do Android e, ao escrever o primeiro aplicativo, em vez das perguntas "o que devo usar", haverá perguntas mais específicas "como exatamente devo usar o componente X". E já todos os detalhes sobre essa pessoa poderão descobrir por si mesmos - se quiserem.


Então vamos lá!


Aprendendo os componentes


Instale o aplicativo, inicie-o e ... por enquanto, basta que a MainActivity seja aberta diante de nós. A pergunta "por que é exatamente" será respondida mais tarde.


Primeiro, vamos considerar de onde vem - from main_activity.xml, onde todos os elementos da interface são declarados. Eles são publicados no LinearLayout, portanto, é improvável que surjam perguntas aqui.


Ver código
<LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Android Demo Application" /> <TextView android:id="@+id/textView3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" 1" /> <Button android:id="@+id/buttonShowToast" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" Toast" /> ... </LinearLayout> 

Componentes simples


Torrada


Ver imagem


Agora vamos para MainActivity.java e o primeiro botão de sua interface - "Show Toast" (notificação pop-up).
Localize o identificador do botão em main_activity.xml e acesse o OnClickListener em MainActivity.java.


Ver código
 Button btn = findViewById(R.id.buttonShowToast); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(), "This is a Toast", Toast.LENGTH_LONG).show(); } }); 

Acontece que, para exibir uma notificação pop-up, basta uma linha de código! Ótimo, não é?


Interação com outra atividade


Ver imagem

Primeira atividade

Segunda atividade


Agora vamos tentar ir para algum lugar fora da página principal do aplicativo. Por exemplo, para outra página desse tipo! Vá para "Interação com outra atividade" - e entramos em outra atividade com outros controles. Como atividades diferentes em um aplicativo transferem dados entre si? Aqui está a hora de falar sobre dois mecanismos diferentes: um armazenamento constante de valores - shared_prefs, bem como startActivityForResult / onActivityResult (eu não queria inserir isso no início, mas ainda assim brevemente: se você iniciar uma nova atividade de uma atividade aberta usando startActivityForResult, depois que a segunda atividade for concluída será chamado onActivityResult na primeira atividade. Não se assuste se isso ainda não estiver claro).
E, claro, demonstre na prática!


Entrada em shared_prefs:


Ver código
 String valueToSave = "test"; SharedPreferences.Editor editor = getSharedPreferences("demoapp", MODE_PRIVATE).edit(); editor.putString("myValue", valueToSave); editor.apply(); 

Lendo de shared_prefs:


Ver código
 SharedPreferences prefs = getSharedPreferences("demoapp", MODE_PRIVATE); String storedValue = prefs.getString("myValue", "NOT_FOUND"); 

Um exemplo com onActivityResult - veja na fonte do aplicativo.


Salvando e restaurando configurações


Ver imagem


Desde que mencionamos shared_prefs, vamos terminar com eles. Vamos para "Salvando e restaurando configurações", onde é apresentado um cartão típico de uma conta típica com vários tipos de campos (observe que o tipo deles é definido por apenas uma variável - uma opção). Vamos salvar o conteúdo desses campos em shared_prefs e depois restaurá-los. Até agora, um botão separado, sem onResume - ainda não os encontramos!
Salvar:


Ver código
 SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); EditText et = findViewById(R.id.editTextName); String name = et.getText().toString(); editor.putString("name", name); editor.apply(); 

Restauramos:


Ver código
 SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); EditText et = findViewById(R.id.editTextName); et.setText(prefs.getString("name", "")); ... 

Menu simples


Ver imagem


A próxima seção é um menu simples. Aprendemos com isso que não há nada complicado - basta definir onCreateOptionsMenu e preenchê-lo com a estrutura de my_menu.xml.


Ver código
 @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.my_menu, menu); return true; } 

Menu pop-up


Imediatamente após isso - um botão de menu pop-up. Já é mais interessante que o anterior, mesmo com a presença de configurações de memória e a presença de submenus.
O código do menu pop-up pode ser visualizado no código-fonte do aplicativo.


Leitor de áudio


Ver imagem


Usando o exemplo do Audio Player, além do fato de não haver nada complicado na reprodução de música, você pode demonstrar a ligação do seekBar a algo, nesse caso, à posição atual do media player. No controle de volume - também nada sobrenatural. O bônus mostra um erro. Abra a atividade com o media player, inicie a reprodução e pressione o botão "Voltar". A música continua a tocar e não pode mais ser interrompida ... O problema! Como resolvê-lo - descobriremos um pouco mais tarde.
O código do reprodutor de áudio pode ser encontrado no código fonte do aplicativo.


Navegador da Web


Bem, na conclusão da primeira parte, mostramos que também não há nada de divino no navegador.


Ver imagem


Ver código
 WebView view = findViewById(R.id.webView); view.setWebViewClient(new WebViewClient()); view.getSettings().setJavaScriptEnabled(true); view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); view.loadUrl("https://google.com"); 

A próxima parte já é mais difícil.


Serviços e notificações


BroadcastReceiver


Ver imagem


Lembre-se de como passamos o resultado de uma atividade para outra. De alguma forma (ainda não sabemos como), descobriu-se que, quando a segunda atividade foi encerrada, o resultado passou para o onActivityResult da primeira. Mas podemos transferir o resultado para qualquer lugar em nosso aplicativo? Sim, podemos anunciar e registrar um ouvinte que nos ouve de qualquer lugar do programa. Esse ouvinte é chamado de BroadcastReceiver.


Ver código
 public BroadcastReceiver MyReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getApplicationContext(), "Broadcast receiver: received!", Toast.LENGTH_LONG).show(); } }; 

Aqui você não pode fazer sem intenções, mas no nível mais primitivo: por enquanto, o fato de serem suficientes para nós é enviado para um determinado barramento comum e, de acordo com uma ação predeterminada, o BroadcastReceiver nos ouvirá onde quer que estejamos.


Ver código
 IntentFilter filter = new IntentFilter(); filter.addAction("MyCustomActionName"); registerReceiver(MyReceiver, filter); sendBroadcast(new Intent("MyCustomActionName")); 

No momento, temos uma idéia básica do que é o receptor, mas por que ele é necessário não está claro: isso é normal e agora ficará mais fácil.


Serviço simples


Ver imagem


Vá diretamente para o serviço, onde o BroadcastReceiver encontrará seu aplicativo completo. E, em vez de tentar dizer em poucas palavras o que é um serviço Android, proponho iniciar a demonstração imediatamente. Execute o serviço, que inicia seu trabalho em segundo plano. Junto com isso, registraremos dois Receptores: um em Atividade e outro em Serviço.
O Receptor em Serviço é necessário para demonstrar que, apesar da execução em segundo plano, sempre podemos acessá-lo na Atividade.


Ver código
 public BroadcastReceiver MyServiceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getApplicationContext(), "Toast from Service: I hear you!", Toast.LENGTH_LONG).show(); } }; 

O receptor em atividade é necessário para exibir os resultados do serviço no TextView.


Ver código
 public BroadcastReceiver MyPrintReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(getApplicationContext(), "pong", Toast.LENGTH_SHORT).show(); TextView tv = findViewById(R.id.textViewSimpleServiceStatus); String msg = intent.getStringExtra("msg"); tv.setText(msg); } }; 

E, para um entendimento completo, ao enviar uma mensagem do serviço para a Activity, exibiremos o Toast ("ping"). E quando recebermos a mensagem na Atividade e realmente desenharmos o valor no TextView, exibiremos Toast ("pong").
Deixe que a principal tarefa do serviço seja enviar esses "pings" para a atividade, e a tarefa da atividade é simplesmente exibi-los em sua interface.


Ver código
 Handler handler = new Handler(); runnable = new Runnable() { public void run() { if (running) { printMsg("Service is still running " + running); handler.postDelayed(runnable, 5000); //   } else { printMsg("Service exited"); } } }; handler.postDelayed(runnable, 5000); 

Um exemplo da operação do manipulador será considerado em detalhes posteriormente, no momento, é apenas um meio de enviar ping a cada 5 segundos.


E agora, depois de iniciar o serviço, vemos o Toast ("Serviço criado!") E enviamos notificações de ping-pong. E no TextView as mensagens de serviço começaram a chegar.


Ótimo, execução em segundo plano que vimos. Agora feche o aplicativo! Nas versões mais recentes do Android, veremos o seguinte: o serviço foi reiniciado (o Toast ("Serviço criado!") Aparecerá) e enviará "pings". Ao mesmo tempo, não há "pongs" - afinal, não há mais atividade que os processe! Depois de alguns segundos, pings também pararam no meu smartphone. O serviço está sendo destruído. Abra as configurações de energia, desative a otimização para a nossa aplicação e faça o procedimento novamente. Agora o serviço não é destruído e, mesmo após o encerramento do programa, vemos "pings" de entrada estáveis. Mas, é claro, não há garantia aqui, e esse serviço não vai durar muito. Do ponto de vista do desenvolvedor, isso pode ser terrível, mas vamos olhar através dos olhos de um usuário simples: queremos que um aplicativo funcione em segundo plano tão livremente e com impunidade, consumindo uma bateria? Dificilmente. Como, então, trabalhar totalmente em segundo plano?


Para fazer isso, você só precisa notificar o usuário sobre isso. Esse é um requisito obrigatório do Android, que, na presença de um canal de notificação, permite iniciar não apenas o habitual, mas o serviço Foreground, que funcionará totalmente em segundo plano sem o risco de ser eliminado do nada.
Adicione ao nosso onCreate de nosso serviço:


Ver código
 String CHANNEL_ID = "my_channel_01"; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT); ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("") .setContentText("").build(); startForeground(1, notification); 

E vamos executá-lo com o comando:


Ver código
 startForegroundService(new Intent(getApplicationContext(), TestServiceForeground.class)); 

Voltaremos ao nosso aplicativo de demonstração, retornaremos as configurações de economia de energia ao seu estado original. E agora lançaremos o serviço em primeiro plano. Fechando o aplicativo quando o serviço está em execução, observamos que o serviço não está mais sendo reiniciado e não está sendo destruído, mas simplesmente continua estável a funcionar em segundo plano, enviando seus "pings" a cada 5 segundos. Ao mesmo tempo, um ícone de notificação ficará suspenso nas notificações.


Ver imagem


O usuário poderá ocultar essas notificações, se desejar, mas você não poderá ocultá-las programaticamente no momento da criação do canal de notificação.


Botão flutuante (sobreposição)


Ver imagem


Sabendo o que é um serviço, você pode passar para o uso mais simples e óbvio - trabalhando com botões flutuantes. Nos Androids atuais, você não pode simplesmente declarar direitos de renderização de sobreposições assim: é necessário pedir explicitamente ao usuário permissão "Acima de todas as janelas". Em seguida, clicamos em Draw Overlay e vemos um ícone flutuante, atrás do qual realmente existe um serviço que escuta cliques nele.


Enviando notificações


Ver imagem


Outro recurso importante que provavelmente será útil na maioria dos aplicativos Android é o envio de notificações ao usuário. Vamos dar uma breve olhada em como isso funciona. Para começar (nos atuais Androids), precisamos criar um canal de notificação - sim, sim, um daqueles que geralmente estão disponíveis em grande número em aplicativos modernos.


Ver código
 private void createNotificationChannel() { try { CharSequence channelName = CHANNEL_ID; String channelDesc = "channelDesc"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { int importance = NotificationManager.IMPORTANCE_LOW; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, channelName, importance); channel.setDescription(channelDesc); NotificationManager notificationManager = getSystemService(NotificationManager.class); assert notificationManager != null; NotificationChannel currChannel = notificationManager.getNotificationChannel(CHANNEL_ID); if (currChannel == null) { notificationManager.createNotificationChannel(channel); Toast.makeText(getApplicationContext(), "channel created", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(), "channel exists", Toast.LENGTH_SHORT).show(); } } } catch (Exception e) { } } 

Bem, então você pode enviar notificações para ele sem restrições.


Ver código
 public void setNotify() { try { Intent snoozeIntent = new Intent("ActionFromNotify"); PendingIntent snoozePendingIntent = PendingIntent.getBroadcast(this, 0, snoozeIntent, 0); String title = "Start"; Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.drawable.ic_launcher_background, title, snoozePendingIntent).build(); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("MyNotification") .setContentText("Text here") .setPriority(NotificationCompat.PRIORITY_LOW) .setContentIntent(null) .setOngoing(true) //   .setSound(null) .addAction(action); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); int notificationId = (int) (System.currentTimeMillis() / 4); notificationManager.notify(notificationId, mBuilder.build()); } catch (Exception e) { Log.e("error", e.toString()); } } 

Serviço com o envio de notificações


Ver imagem


O envio de notificações diretamente da atividade, você vê, não é muito impressionante. Ainda estamos acostumados a outra coisa. Mas o que sabemos sobre a execução em segundo plano até agora? Só que existem serviços. Portanto, não vamos nos apressar e criar um serviço simples (nem mesmo o Primeiro Plano - por simplicidade) que envia uma nova notificação a cada 5 segundos. Concordo, isso já é mais bonito e mais impressionante do que apenas enviar notificações por um botão.


Como uma breve pausa após serviços aparentemente complicados (se você nunca os conheceu antes), consideraremos quatro controles que são fáceis de entender. E, novamente, voltamos ao material complexo - aos fluxos.


Componentes adicionais


Tabela de dados


Ver imagem


Vamos começar nossa pausa com a tabela de dados. O estudo do código fonte é deixado para o leitor.


Janela com guias


Ver imagem


A próxima parada é uma janela com guias. Com a ajuda de um simples TabView, você pode colocar várias atividades em uma tela.


Ver código
 public class TabsActivity extends TabActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tabs_activity); //  TabHost TabHost tabHost = getTabHost(); TabHost.TabSpec tabSpec; tabSpec = tabHost.newTabSpec("tag1"); tabSpec.setIndicator(""); tabSpec.setContent(new Intent(this, SaveRestorePrefsActivity.class)); tabHost.addTab(tabSpec); tabSpec = tabHost.newTabSpec("tag2"); tabSpec.setIndicator(""); tabSpec.setContent(new Intent(this, FloatingMenuActivity.class)); tabHost.addTab(tabSpec); ... } } 

Exibição de objetos de estrutura: fragmento e tabela


A saída dos objetos de estrutura pode ser feita com fragmentos e uma tabela.
É assim que o preenchimento de fragmentos se parece


Ver imagem


E então a mesa


Ver imagem


Ciclo de Vida da Atividade


Ver imagem


Terminando gradualmente nossa pausa, prosseguimos para o ciclo de vida da atividade. Aqui está a hora de descobrir que existem vários outros métodos além do onCreate. Um pequeno pedaço de código e notificações pop-up primeiro ajudarão a entendê-los melhor do que qualquer explicação.


Ver código
 @Override protected void onResume() { super.onResume(); Toast.makeText(getApplicationContext(), "onResume -    ", Toast.LENGTH_SHORT).show(); } @Override protected void onDestroy() { super.onDestroy(); Toast.makeText(getApplicationContext(), "onDestroy -  ", Toast.LENGTH_SHORT).show(); } @Override protected void onPause() { super.onPause(); Toast.makeText(getApplicationContext(), "onPause -      ", Toast.LENGTH_SHORT).show(); } 

O mesmo se aplica a OnTouchListener'ov e onTextChanged.


Ver código
 CheckBox cb = findViewById(R.id.checkBoxChangeExample); cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { printMsg("CheckBox - OnCheckedChangeListener: new value is checked = " + isChecked); } }); SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarChangeExample); seekBar.setMax(100); seekBar.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Integer progress = ((SeekBar)v).getProgress(); printMsg("SeekBar - OnTouchListener: new value is = " + progress.toString()); return false; } }); 

Execução atrasada, paralela e regular


Passamos para a parte mais difícil da história - execução adiada e paralela.


Execução atrasada: manipulador


Ver imagem


Vamos começar o mergulho com Handler. O que é um manipulador com todos os detalhes - uma pessoa mais tarde lerá ela mesma, não a privaremos desse prazer. Mas, como estamos considerando isso, é importante saber o principal - que ele permite que você execute uma tarefa pendente e não o faz paralelamente.
Mostre isso. Vamos criar um manipulador, adicione a tarefa "para gerar o Toast em 5 segundos". Vimos que o Toast foi retirado e não houve necessidade de pausa (pausa na execução de todo o programa).


Ver código
 Handler handler = new Handler(); Runnable r = new Runnable() { public void run() { Toast.makeText(getApplicationContext(), "Delayed task executed", Toast.LENGTH_SHORT).show(); } }; handler.postDelayed(r, 5000); 

Agora adicione uma tarefa cíclica ao manipulador:


Ver código
 Runnable r = new Runnable() { public void run() { Toast.makeText(getApplicationContext(), "Delayed task executed", Toast.LENGTH_SHORT).show(); handler.postDelayed(this, 5000); //   } }; handler.postDelayed(r, 5000); 

Depois de garantir que ele seja executado a cada 5 segundos, limpe o manipulador


Ver código
 handler.removeCallbacksAndMessages(null); 

Resta demonstrar que a execução de tarefas do Handler não ocorre em paralelo. A maneira mais fácil de mostrar isso é carregando algo pesado e ao mesmo tempo simples. Como ... enquanto (verdadeiro) sem dormir! Dez segundos, para não matar completamente o aplicativo.


Ver código
 Runnable r = new Runnable() { public void run() { long initTime = System.currentTimeMillis(); boolean timeElapsed = false; while(!timeElapsed){ if(System.currentTimeMillis() - initTime > 10000 ){ timeElapsed = true; //   ,   ! (  ,    ).         sleep } } } }; Toast.makeText(getApplicationContext(), "Hard Delayed task started", Toast.LENGTH_SHORT).show(); handler.postDelayed(r, 100); 

Ao iniciar essa tarefa, vemos que o aplicativo não responde aos nossos cliques por esses 10 segundos - ele está completamente ocupado processando nosso ciclo complexo. A segunda conclusão que se segue deste exemplo é que você não pode executar tarefas que consomem muitos recursos no mesmo encadeamento da interface. O thread da interface do usuário deve estar sempre livre e suas funções devem ser trabalhadas o mais rápido possível. Algumas operações no fluxo da interface do usuário são explicitamente proibidas: por exemplo, o Android travará o aplicativo se ele tentar acessar a Internet no fluxo da interface do usuário.


Execução simultânea: fluxo


Ver imagem


A questão lógica agora é como criar novos threads e trabalhar em paralelo?
Mostramos a criação do fluxo e o fato de sua operação paralela. Vamos criar um fluxo e carregá-lo com a mesma tarefa, por isso, no caso do habdler, ficamos com uma interface inativa por 10 segundos.


Ver código
 Thread thread = new Thread() { @Override public void run() { try { sendMsgUsingBroadcast("Thread started"); long initTime = System.currentTimeMillis(); boolean timeElapsed = false; while(!timeElapsed){ if(System.currentTimeMillis() - initTime > 10000 ){ timeElapsed = true; } } sendMsgUsingBroadcast("Thread stopped"); } catch (Exception e) { sendMsgUsingBroadcast("Thread error " + e.toString()); } } }; thread.start(); 

Criado, carregado - e a interface funciona! A execução do encadeamento ocorre em paralelo.
A próxima pergunta é como controlar o fluxo. É importante entender que um encadeamento será concluído apenas quando todo o seu código-fonte for executado. Você não pode simplesmente pegar e matar o fluxo. É hora de pensar em shared_prefs e aplicar a variável para sincronização: deixe a variável running = true ser definida junto com o início do fluxo. Em cada uma de suas iterações, o encadeamento verifica se running == true está sendo executado e, se não, conclui sua execução.


Ver código
 Thread thread = new Thread() { @Override public void run() { try { sendMsgUsingBroadcast("Thread started"); SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); while (true) { if (!prefs.getBoolean("running", false)) { break; } else { try { Thread.sleep(100); } catch (Exception e) {} } } sendMsgUsingBroadcast("Thread stopped"); } catch (Exception e) { sendMsgUsingBroadcast("Thread error " + e.toString()); } } }; thread.start(); 

Então, avançamos alguns passos e agora sabemos não apenas sobre o serviço, mas também sobre o manipulador e o fluxo. Parece que essas ferramentas são suficientes para começar a escrever um aplicativo que possui uma das funções da notificação regular do usuário. Mas eles têm uma característica: todos eles estão unidos pelo fato de não perdermos o controle por um segundo e sempre são forçados a estar em algum tipo de ciclo interminável que dorme a maior parte do tempo e ocasionalmente acorda para verificar se algumas condições são atendidas para entender - deduzir aviso do usuário ou durma novamente por um longo tempo. Isso adiciona uma dor de cabeça: e se nosso serviço ou aplicativo matar o otimizador de bateria, e por que consumimos tantos recursos de smartphones por causa de um pequeno apito não tão necessário? , , , - , ?


: AlarmManager


AlarmManager.



, — sendBroadcast Action, BroadcastReceiver!


BroadcastReceiver, , , :


 public class MyAlarmServiceReceiver extends BroadcastReceiver { private String CHANNEL_ID = "MyNotificationsChannel"; @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "MyAlarmServiceReceiver onReceive", Toast.LENGTH_SHORT).show(); setNotify("Notify from AlarmManager", context); } } 

AlarmManager Receiver 15 :


 AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); Intent intent = new Intent(AlarmActivity.this, MyAlarmServiceReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 1); calendar.set(Calendar.MINUTE, 10); //alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 1 * 60 * 1000, pendingIntent); // not repeating - just one run, if needed alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent); 

: 15 .


( ) .




Logcat Reader , .
( ) , .


 String LOG_TAG = "MYDEMOAPP"; Log.i(LOG_TAG, "Test info log"); Log.d(LOG_TAG, "Test debug log"); Log.e(LOG_TAG, "Test error log"); 

, , MainActivity, , .


Código fonte




Conclusão


, Android. , , , : , . , , - Android-.

Source: https://habr.com/ru/post/pt483878/


All Articles