Introduccion
Este artículo discutirá cómo decirle a una persona que previamente no estaba familiarizada con la programación para Android, sobre sus componentes principales. Interesar y demostrar que no todo es tan difícil como mucha gente piensa. Al mismo tiempo, hágalo en 15 minutos y sin entrar en una explicación de alguna teoría básica que todos puedan leer por sí mismos y volver con preguntas aclaratorias.
Cuando intenté hacer esto por primera vez, me sorprendió desagradablemente. Mi explicación "simple y comprensible" se convirtió en aburrida, en cuyo marco se trazó claramente un intento desesperado por captar la inmensidad y contar en pocas palabras todo lo que un poco estaba claro. No es necesario decir que es probable que una historia de este tipo no interese, sino que asusta a su interlocutor, al tiempo que disminuye el deseo de hacer algo por su cuenta, incluso si anteriormente tenía una pequeña calculadora en sus planes.
No es ningún secreto que una gran cantidad de artículos sobre este tema se publican en Internet, pero en mi caso la narración será ligeramente diferente: solo habrá práctica visual, sin definiciones y otros detalles. Es decir, miramos, vemos, comentamos lo que está sucediendo. Parece, en mi opinión, todo es bastante simple y claro, los fragmentos de código también son pequeños y muy simples, listos para su uso rápido en su propio proyecto. Me parece que este enfoque ofrece una visión general bastante amplia de las herramientas clásicas de Android, y al escribir la primera aplicación, en lugar de las preguntas "qué debo usar", habrá preguntas más específicas "cómo exactamente debería usar el componente X". Y ya todos los detalles sobre esta persona podrán descubrirlos por sí mismos, si así lo desean.
¡Entonces vamos!
Aprendiendo los componentes
Instale la aplicación, ejecútela y ... por ahora, es suficiente que MainActivity se haya abierto antes que nosotros. La pregunta "por qué es exactamente" se responderá más adelante.
En primer lugar, veamos de dónde proviene: de main_activity.xml, donde se declaran todos los elementos de la interfaz. Están publicados en LinearLayout, por lo que es poco probable que surjan preguntas aquí.
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
Tostadas
Ahora vamos a MainActivity.java y al primer botón de su interfaz: "Mostrar tostadas" (notificación emergente).
Encuentre el identificador del botón en main_activity.xml y vaya a su OnClickListener en 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(); } });
Resulta que para mostrar una notificación emergente, ¡una línea de código es suficiente! Genial, ¿no es así?
Interacción con otra actividad
Ver imagenPrimera actividad

Segunda actividad

Ahora intentemos ir a algún lugar fuera de la página principal de la aplicación. Por ejemplo, a otra página de este tipo! Vaya a "Interacción con otra actividad" y entramos en otra actividad con otros controles. ¿Cómo las diferentes actividades en una aplicación transfieren datos entre ellos? Este es el momento de hablar sobre dos mecanismos diferentes: un almacenamiento constante de valores: shared_prefs, así como startActivityForResult / onActivityResult (no quería insertar esto al principio, pero aún brevemente: si inicia una nueva actividad desde una actividad abierta usando startActivityForResult, luego de completar la segunda actividad se llamará aActivityResult en la primera actividad. No se alarme si esto aún no está claro).
Y, por supuesto, demostrar en la práctica!
Entrada en shared_prefs:
Ver código String valueToSave = "test"; SharedPreferences.Editor editor = getSharedPreferences("demoapp", MODE_PRIVATE).edit(); editor.putString("myValue", valueToSave); editor.apply();
Lectura de shared_prefs:
Ver código SharedPreferences prefs = getSharedPreferences("demoapp", MODE_PRIVATE); String storedValue = prefs.getString("myValue", "NOT_FOUND");
Un ejemplo con onActivityResult: consulte el origen de la aplicación.
Guardar y restaurar configuraciones
Como mencionamos shared_prefs, terminemos con ellos. Vamos a "Guardar y restaurar configuraciones", donde se nos presenta una tarjeta típica de una cuenta típica con varios tipos de campos (tenga en cuenta que su tipo se configura con una sola variable: un interruptor). Guardaremos el contenido de estos campos en shared_prefs y luego los restauraremos. Hasta ahora, un botón separado, sin onResume, ¡aún no los hemos alcanzado!
Guardar:
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", "")); ...
Menú simple
La siguiente sección es un menú simple. Aprendemos de él que no tiene nada de complicado: simplemente configure onCreateOptionsMenu y complételo con la estructura 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; }
Menú emergente
Inmediatamente después, un botón de menú emergente. Ya es más interesante que el anterior, incluso con la presencia de memoria de configuración y la presencia de submenús.
El código para el menú emergente se puede ver en el código fuente de la aplicación.
Reproductor de audio
Utilizando el ejemplo del reproductor de audio, además del hecho de que no hay nada complicado en la reproducción de música, puede demostrar la conexión de seekBar a algo, en este caso, a la posición actual del reproductor multimedia. En el control de volumen, tampoco nada sobrenatural. La bonificación muestra un error. Abra la actividad con el reproductor multimedia, inicie la reproducción y presione el botón "Atrás". La música continúa sonando y ya no se puede detener ... ¡El problema! Cómo resolverlo: lo descubriremos un poco más tarde.
El código del reproductor de audio se puede encontrar en el código fuente de la aplicación.
Navegador web
Bueno, en conclusión de la primera parte, mostramos que tampoco hay nada divino en el navegador web.
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");
La siguiente parte ya es más difícil.
Servicios y notificaciones
BroadcastReceiver
Recordemos cómo pasamos el resultado de una actividad a otra. De alguna manera (aún no sabemos cómo) resultó que cuando se cerró la segunda actividad, el resultado voló al resultado onActivityResult de la primera. ¿Pero podemos transferir el resultado a cualquier lugar dentro de nuestra aplicación? Sí, podemos anunciar y registrar un oyente que nos escucha desde cualquier parte del programa. Tal oyente se llama 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(); } };
Aquí no puede prescindir de intenciones, pero al nivel más primitivo: por ahora, el hecho de que sean suficientes para nosotros se envía a un determinado autobús común, y que de acuerdo con una acción predeterminada, BroadcastReceiver nos escuchará dondequiera que estemos.
Ver código IntentFilter filter = new IntentFilter(); filter.addAction("MyCustomActionName"); registerReceiver(MyReceiver, filter); sendBroadcast(new Intent("MyCustomActionName"));
Por el momento, tenemos una idea básica de qué es Receiver, pero no está claro por qué es necesario: esto es normal, y ahora será más fácil.
Servicio simple
Pase sin problemas al servicio, donde BroadcastReceiver encontrará su aplicación completa. Y en lugar de tratar de decir en pocas palabras qué es un servicio de Android, propongo comenzar la demostración de inmediato. Ejecute el servicio, que comienza su trabajo en segundo plano. Junto con esto, registraremos dos receptores: uno en actividad y otro en servicio.
El receptor en servicio es necesario para demostrar que, a pesar de la ejecución en segundo plano, siempre podemos alcanzarlo desde la actividad.
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(); } };
El receptor en actividad es necesario para mostrar los resultados del servicio en 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); } };
Y, para una comprensión completa, al enviar un mensaje del servicio a Activity, mostraremos Toast ("ping"). Y cuando recibamos el mensaje en la Actividad y dibujemos el valor en TextView, mostraremos Toast ("pong").
Deje que la tarea principal del servicio sea enviar tales "pings" a la actividad, y la tarea de la actividad es simplemente mostrarlos en su interfaz.
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);
Un ejemplo de la operación del controlador se considerará en detalle más adelante, por el momento es solo un medio de enviar ping cada 5 segundos.
Y ahora, después de iniciar el servicio, vemos Toast ("¡Servicio creado!") Y enviamos notificaciones de ping-pong. Y en TextView los mensajes del servicio comenzaron a llegar.
Genial, ejecución de fondo que vimos. Ahora cierra la aplicación! En las últimas versiones de Android, veremos lo siguiente: el servicio se ha reiniciado (aparecerá Toast ("¡Servicio creado!") Y enviará "pings". Al mismo tiempo, no hay "pongs", después de todo, ¡no hay más actividad que los procese! Después de unos segundos, los pings también se detuvieron en mi teléfono inteligente. El servicio está siendo destruido. Abra la configuración de energía, apague la optimización para nuestra aplicación y vuelva a realizar el procedimiento. Ahora el servicio no se destruye, e incluso después de que se cierra el programa, vemos "pings" entrantes estables. Pero, por supuesto, no hay garantía aquí, y dicho servicio no durará mucho tiempo. Desde el punto de vista del desarrollador, esto puede ser terrible, pero veámoslo a través de los ojos de un usuario simple: ¿queremos que cualquier aplicación funcione en segundo plano con tanta libertad e impunidad, comiendo una batería? Apenas ¿Cómo, entonces, trabajar completamente en segundo plano?
Para hacer esto, solo necesita notificar al usuario sobre esto. Este es un requisito obligatorio de Android, que, en presencia de un canal de notificación, le permite lanzar no solo lo habitual, sino también el servicio en primer plano, que funcionará completamente en segundo plano sin el riesgo de ser asesinado de la nada.
Agregue a nuestro onCreate de nuestro servicio:
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);
Y lo ejecutaremos con el comando:
Ver código startForegroundService(new Intent(getApplicationContext(), TestServiceForeground.class));
Volveremos a nuestra aplicación de demostración, devolveremos la configuración de ahorro de energía a su estado original. Y ahora lanzaremos el servicio en primer plano. Al cerrar la aplicación cuando el servicio se está ejecutando, observamos que el servicio ya no se reinicia y no se destruye, sino que simplemente sigue funcionando de manera estable en segundo plano, enviando sus "pings" cada 5 segundos. Al mismo tiempo, un icono de notificación colgará en las notificaciones.
El usuario podrá ocultar estas notificaciones si lo desea, pero usted no puede ocultarlas mediante programación al momento de crear el canal de notificación.
Botón flotante (superposición)
Sabiendo lo que es un servicio, puede pasar a su uso más simple y obvio: trabajar con botones flotantes. En los androides actuales, no puede declarar los derechos de representación de superposiciones de esa manera: debe pedirle explícitamente permiso al usuario "Sobre todas las ventanas". Luego hacemos clic en Dibujar superposición y vemos un ícono flotante, detrás del cual realmente hay un servicio que escucha los clics en él.
Enviar notificaciones
Otra característica importante que probablemente sea útil en la mayoría de las aplicaciones de Android es enviar notificaciones al usuario. Veamos brevemente cómo funciona esto. Para comenzar (en los androides actuales), necesitamos crear un canal de notificación: sí, sí, uno de los que generalmente están disponibles en grandes cantidades en las aplicaciones modernas.
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) { } }
Bueno, entonces puedes enviarle notificaciones sin restricciones.
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()); } }
Servicio con envio de notificaciones
Enviar notificaciones directamente desde la actividad, como puede ver, no es muy impresionante. Todavía estamos acostumbrados a algo más. Pero, ¿qué sabemos sobre la ejecución en segundo plano hasta ahora? Solo que hay servicios. Así que no nos apuremos y hagamos un servicio simple (ni siquiera en primer plano, por simplicidad) que envíe una nueva notificación cada 5 segundos. De acuerdo, esto ya es más bonito y más impresionante que solo enviar notificaciones con un botón.
Como breve pausa después de servicios aparentemente complicados (si nunca los ha conocido antes), consideraremos cuatro controles que son fáciles de entender. Y luego volvemos al material complejo, a los flujos.
Componentes adicionales
Tabla de datos
Comencemos nuestra pausa con la tabla de datos. Estudiar el código fuente se deja al lector.
Ventana con pestañas
La siguiente parada es una ventana con pestañas. Con la ayuda de un simple TabView, puede colocar varias actividades en una pantalla.
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); ... } }
Mostrar objetos de estructura: fragmento y tabla
La salida de los objetos de estructura se puede hacer con fragmentos y una tabla.
Así es como se ve el relleno de fragmentos
Y entonces la mesa
Ciclo de vida de la actividad
Gradualmente terminando nuestra pausa, procedemos al ciclo de vida de la actividad. Este es el momento de descubrir que existen otros métodos además de onCreate. Al principio, un pequeño fragmento de código y notificaciones emergentes ayudarán a comprenderlos mejor que cualquier explicación.
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(); }
Lo mismo se aplica a OnTouchListener'ov y 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; } });
Ejecución retrasada, paralela y regular
Pasamos a la parte más difícil de la historia: la ejecución diferida y paralela.
Ejecución retrasada: controlador
Comencemos la inmersión con Handler. Qué es un controlador en todos los detalles: una persona lo leerá más tarde por sí mismo, no lo privaremos de este placer. Pero, dado que lo estamos considerando, es importante saber lo principal: que le permite realizar una tarea pendiente y no lo hace en paralelo.
Muéstralo. Creemos un controlador, agreguemos la tarea "para generar Toast en 5 segundos". Vemos que Toast fue retirado y no se requirieron durmientes (pausas en la ejecución de todo el 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);
Ahora agregue una tarea cíclica al controlador:
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);
Después de asegurarse de que se ejecuta cada 5 segundos, borre el controlador
Ver código handler.removeCallbacksAndMessages(null);
Queda por demostrar que la ejecución de tareas desde Handler no se produce en paralelo. La forma más fácil de mostrar esto es cargándolo con algo pesado y al mismo tiempo simple. Me gusta ... mientras (cierto) sin dormir! Diez segundos, para no matar por completo la aplicación.
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);
Al iniciar dicha tarea, vemos que la aplicación no responde a nuestros clics durante estos 10 segundos: está completamente ocupada procesando nuestro complejo ciclo. La segunda conclusión que se desprende de este ejemplo es que no puede ejecutar tareas intensivas en recursos en el mismo hilo con la interfaz. El subproceso de la interfaz de usuario siempre debe estar libre, y sus funciones deben resolverse lo más rápido posible. Algunas operaciones en la transmisión de la interfaz de usuario están explícitamente prohibidas: por ejemplo, Android bloqueará la aplicación si intenta acceder a Internet en la transmisión de la interfaz de usuario.
Ejecución concurrente: Stream
La pregunta lógica ahora es cómo crear nuevos hilos y trabajar en paralelo.
Mostramos tanto la creación de la secuencia como el hecho de su operación paralela. Vamos a crear una secuencia y cargarla con la misma tarea, por lo que, en el caso de habdler, nos quedamos con una interfaz inactiva durante 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();
Creado, cargado, ¡y la interfaz funciona! La ejecución del hilo ocurre en paralelo.
La siguiente pregunta es cómo controlar el flujo. Es importante comprender que un subproceso se completará solo cuando se ejecute todo su código fuente. No puedes simplemente tomar y matar la transmisión. Es hora de pensar en shared_prefs y aplicar la variable para la sincronización: deje que la variable running = true se configure junto con el inicio de la secuencia. En cada una de sus iteraciones, el hilo verifica si se está ejecutando == verdadero, y si no, completa su ejecución.
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();
Entonces, hemos avanzado unos pasos más y ahora sabemos no solo sobre el servicio, sino también sobre Handler y la transmisión. Parece que estas herramientas son suficientes para comenzar a escribir una aplicación que tenga una de las funciones de notificación regular al usuario. Pero tienen una característica: todos ellos están unidos por el hecho de que no perdemos el control por un segundo, y siempre estamos obligados a estar en algún tipo de ciclo interminable que duerme la mayor parte del tiempo y ocasionalmente se despierta para verificar si se cumplen un par de condiciones para entender, para deducir aviso del usuario o volver a dormir por un largo tiempo. Esto agrega un dolor de cabeza: ¿qué pasa si nuestro servicio o aplicación mata el optimizador de batería, y por qué consumimos tantos recursos de teléfonos inteligentes en aras de un pequeño silbato no tan necesario? , , , - , ?
: 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 fuente
Conclusión
, Android. , , , : , . , , - Android-.