En entradas anteriores se ha visto cómo recoger y usar los recursos de nuestra aplicación, y en esta ocasión vamos a manejar archivos en memoria interna del dispositivo.
En el ejercicio siguiente haremos una aplicación con la que introduciremos 5 tiempos distintos, los guardaremos en un archivo de texto y posteriormente los iremos leyendo para lanzar la alarma pasado el tiempo indicado. Antes partiremos de un estado inicial, en el que todos los tiempos estén marcados a 5 minutos.
Para utilizar como interfaz gráfica podríamos usar algo similar a lo siguiente:

El archivo xml del layout que corresponde a esta interfaz es:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/tvTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tvTitle" /> <TextView android:id="@+id/tv1Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/tvTitle" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tv1Alarma" /> <TextView android:id="@+id/tv2Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/tv1Alarma" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tv2Alarma" /> <TextView android:id="@+id/tv3Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/tv2Alarma" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tv3Alarma" /> <TextView android:id="@+id/tv4Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/tv3Alarma" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tv4Alarma" /> <TextView android:id="@+id/tv5Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/tv4Alarma" android:layout_marginLeft="14dp" android:layout_marginTop="14dp" android:text="@string/tv5Alarma" /> <EditText android:id="@+id/et1Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/tv1Alarma" android:layout_alignBottom="@+id/tv1Alarma" android:layout_marginLeft="14dp" android:layout_marginRight="10dp" android:maxLength="2" android:layout_toRightOf="@+id/tv1Alarma" android:ems="10" android:inputType="number" /> <EditText android:id="@+id/et2Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/tv2Alarma" android:layout_alignBottom="@+id/tv2Alarma" android:layout_marginLeft="14dp" android:layout_marginRight="10dp" android:maxLength="2" android:layout_toRightOf="@+id/tv2Alarma" android:ems="10" android:inputType="number" /> <EditText android:id="@+id/et3Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/tv3Alarma" android:layout_alignBottom="@+id/tv3Alarma" android:layout_marginLeft="14dp" android:layout_marginRight="10dp" android:maxLength="2" android:layout_toRightOf="@+id/tv3Alarma" android:ems="10" android:inputType="number" /> <EditText android:id="@+id/et4Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/tv4Alarma" android:layout_alignBottom="@+id/tv4Alarma" android:layout_marginLeft="14dp" android:layout_marginRight="10dp" android:maxLength="2" android:layout_toRightOf="@+id/tv4Alarma" android:ems="10" android:inputType="number" /> <EditText android:id="@+id/et5Alarma" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/tv5Alarma" android:layout_alignBottom="@+id/tv5Alarma" android:layout_marginLeft="14dp" android:layout_marginRight="10dp" android:maxLength="2" android:layout_toRightOf="@+id/tv5Alarma" android:ems="10" android:inputType="number" /> <Button android:id="@+id/btActivar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv5Alarma" android:layout_below="@+id/et5Alarma" android:layout_marginTop="14dp" android:text="@string/btActivar" android:onClick="onClick" /> <TextView android:id="@+id/tvTiempoRestante" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/btActivar" android:layout_below="@+id/btActivar" android:layout_marginTop="20dp" android:text="Tiempo Restante" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/tvAlarmRestantes" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tvTiempoRestante" android:layout_below="@+id/tvTiempoRestante" android:layout_marginTop="15dp" android:text="Alarmas Restantes" android:textAppearance="?android:attr/textAppearanceLarge" /> </RelativeLayout>
Una vez que ya tenemos nuestra interfaz lista, empecemos con la lógica de nuestra Activity. En primer lugar necesitaremos utilizar los EditText que mostrarán los tiempos de las alarmas, para ello crearemos las instancias de los objetos y en nuestro método onCreate haremos una llamada a un método que los inicializará:
private EditText et1Alarma, et2Alarma, et3Alarma, et4Alarma, et5Alarma; private TextView tvTiempoRestante, tvAlarmRestantes; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); instanciarComponentes(); } private void instanciarComponentes() { et1Alarma = (EditText) findViewById(R.id.et1Alarma); et2Alarma = (EditText) findViewById(R.id.et2Alarma); et3Alarma = (EditText) findViewById(R.id.et3Alarma); et4Alarma = (EditText) findViewById(R.id.et4Alarma); et5Alarma = (EditText) findViewById(R.id.et5Alarma); tvAlarmRestantes = (TextView) findViewById(R.id.tvAlarmRestantes); tvTiempoRestante = (TextView) findViewById(R.id.tvTiempoRestante); }
Una vez instanciados los componentes que vamos a utilizar, pasaremos instanciar una serie de variables que necesitaremos para almacenar las alarmas, controlar si ya hay una alarma en curso, controlar por qué alarma vamos, y el nombre del archivo txt que utilizaremos. Las declararemos junto con los componentes anteriores, al principio de la clase:
private final static String FILE = "alarmas.txt"; private ArrayList<Integer> tiempos; private int numAlarmas, numAlarmaActual; boolean alarmaFinalizada;
También escribiremos un método que instancie estas variables, al que se llamará también desde onCreate:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); instanciarComponentes(); instanciarVariables(); } private void instanciarVariables() { tiempos = new ArrayList<Integer>(); numAlarmas = 0; numAlarmaActual = 0; alarmaFinalizada = true; }
Y por último tenemos que establecer el tiempo inicial, para eso comprobaremos si el archivo de alarmas ya existe, si existe leemos las alarmas y las mostramos en los EditText, de lo contrario lo creamos. Para ello crearemos un nuevo método, que también llamaremos desde onCreate, a su vez este nuevo método hará uso de otros dos métodos, uno que rellenará los EditText, y otro que creará el archivo de texto de ser necesario:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); instanciarComponentes(); instanciarVariables(); establecerTiempoInicial(); } private void establecerTiempoInicial() { // Comprobamos si existe el archivo if (existsFile(FILE)) { // En el caso de que exista, intentamos rellenar los EditText, si no // se rellenan de forma correcta, el archivo.txt estaba corrupto. if (!rellenarEditTexts()) { // Avisamos al usuario de que el archivo era corrupto. Toast.makeText(AlarmasMain.this, "Archivo corrupto, reiniciando parámetros...", Toast.LENGTH_LONG).show(); // Creamos de nuevo el archivo. crearArchivoAlarmas(); // Rellenamos los EditText con los valores asignados por defecto // en el archvio txt. rellenarEditTexts(); } } else { // En el caso de que no existiera el archivo txt lo creamos y rellenamos // los EditText. crearArchivoAlarmas(); rellenarEditTexts(); } } private void crearArchivoAlarmas() { try { // Creamos un objeto OutputStreamWriter, que será el que nos permita // escribir en el archivo de texto. Si el archivo no existía se creará // automáticamente. // La ruta en la que se creará el archivo será /ruta de nuestro programa/data/data/ OutputStreamWriter outSWMensaje = new OutputStreamWriter( openFileOutput(FILE, Context.MODE_PRIVATE)); // Escribimos los 5 tiempos iniciales en el archivo. outSWMensaje.write("5\n5\n5\n5\n5\n"); // Cerramos el flujo de escritura del archivo, este paso es obligatorio, // de no hacerlo no se podrá acceder posteriormente al archivo. outSWMensaje.close(); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } private boolean rellenarEditTexts() { try { // Creamos un objeto InputStreamReader, que será el que nos permita // leer el contenido del archivo de texto. InputStreamReader archivo = new InputStreamReader( openFileInput(FILE)); // Creamos un objeto buffer, en el que iremos almacenando el contenido // del archivo. BufferedReader br = new BufferedReader(archivo); // Por cada EditText leemos una línea y escribimos el contenido en el // EditText. String texto = br.readLine(); et1Alarma.setText(texto); texto = br.readLine(); et2Alarma.setText(texto); texto = br.readLine(); et3Alarma.setText(texto); texto = br.readLine(); et4Alarma.setText(texto); texto = br.readLine(); et5Alarma.setText(texto); // Cerramos el flujo de lectura del archivo. br.close(); return true; } catch (Exception e) { return false; } }
El método que comprueba si existe o no el archivo sería así:
public boolean existsFile(String fileName) { for (String tmp : fileList()) { if (tmp.equals(fileName)) return true; } return false; }
Por último sólo nos falta implementar el botón, para que inicie el proceso de lanzar nuestras alarmas una vez que haya transcurrido el tiempo indicado, este botón comprobará si los EditText contienen texto, actualizará el archivo de texto con los valores de las alarmas para una siguiente ejecución, y se iniciará el proceso de lanzamiento de alarmas:
public void onClick(View v) { if (et1Alarma.getText().length() != 0 && et2Alarma.getText().length() != 0 && et3Alarma.getText().length() != 0 && et4Alarma.getText().length() != 0 && et5Alarma.getText().length() != 0) { tiempos.add(Integer.parseInt(et1Alarma.getText().toString())); tiempos.add(Integer.parseInt(et2Alarma.getText().toString())); tiempos.add(Integer.parseInt(et3Alarma.getText().toString())); tiempos.add(Integer.parseInt(et4Alarma.getText().toString())); tiempos.add(Integer.parseInt(et5Alarma.getText().toString())); actualizarArchivoAlarmas(); lanzarAlarma(); } }
Por último los métodos actualizarArchivoAlarmas y lanzarAlarma harían lo siguiente:
private void actualizarArchivoAlarmas() { try { OutputStreamWriter outSWMensaje = new OutputStreamWriter( openFileOutput(FILE, Context.MODE_PRIVATE)); // Por cada tiempo escrito en los EditText escribimos una línea // en el archivo de alarmas. for (int i : tiempos) { outSWMensaje.write(i + "\n"); } outSWMensaje.close(); } catch (Exception e) { Log.e(TAG, e.getMessage()); Toast.makeText(this, "No se pudo crear el archivo de alarmas";, Toast.LENGTH_LONG).show(); } } private void lanzarAlarma() { // Sacamos el tiempo restante para lanzar la alarma actual. int i = tiempos.get(numAlarmaActual); // Controlamos la alarma que tiene que sonar numAlarmaActual++; // Variable para controlar cuándo ha finalizado una alarma, para poder // lanzar la siguiente. alarmaFinalizada = false; // Actualizamos el texto de las alarmas restantes. tvAlarmRestantes.setText("Alarmas restantes: " + numAlarmas); // Instanciamos un nuevo contador, que se lanzará con el tiempo debido. CountDownTimer timer = new CountDownTimer(i * 60 * 1000, 100) { @Override public void onTick(long millisUntilFinished) { // Actualizamos el tiempo restante para la nueva alarma. tvTiempoRestante.setText(String .valueOf(millisUntilFinished / 1000) + "s"); } @Override public void onFinish() { // Al finalizar reproducimos un archivo de audio guardado en la // carpeta raw. MediaPlayer mp = MediaPlayer.create(AlarmasMain.this, R.raw.r2d2); mp.start(); // Creamos un AlertDialog que avise de la llegada de la alarma. AlertDialog.Builder alertDialog; alertDialog = new AlertDialog.Builder(AlarmasMain.this); alertDialog.setTitle("Alarma"); alertDialog.setMessage("Es la hora!!"); // Creamos un botón en el AlertDialog, que será el que nos permita // reanudar el tiempo de la siguiente alarma. alertDialog.setPositiveButton("Ok", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Cuando se pulse el botón se marca la alarma como // finalizada, se actualizan las alarmas restantes y // en el caso de no ser la última alarma se vuelve a // ejecutar el método lanzarAlarma. alarmaFinalizada = true; numAlarmas--; tvAlarmRestantes.setText"Alarmas restantes: " + numAlarmas); if (numAlarmaActual < tiempos.size()) lanzarAlarma(); } }); // Mostramos el AlertDialog al usuario. alertDialog.show(); } }; // Una vez creado el temporizador lo iniciamos. timer.start(); }
Y con esto ya podemos crear un sencillo programa de alarmas leyendo y escribiendo en archivos de texto.
Descargas
Puedes ver el resultado del ejemplo en tu móvil descargando nuestra aplicación desde Google Play.
Se puede descargar el proyecto completo aquí.
Latest posts by IAvilaE (see all)
- Programación Android, Cómo usar SwipeRefreshLayout - 26 April 2015
- Programación Android, Gson – Librería para parsear documentos JSON - 13 February 2015
- Programación Android, Cómo usar múltiples Fragments II - 24 January 2015
hola como se podria colocar una archivo txt en la memoria interna con informacion y validara con algun datos y sino fuera igual detubiera la aplicacion
hola, gracias por tu blog, mira lo que pasa es que acabo de hacer una aplicacion que toma unos datos desde un txt, eso ya lo logré, pero ahora quiero que el apk instale no solo el software sino tambien los archivos de texto, ¿de casualidad sabes como hacerlo?
gracias
Tendrías que añadir los ficheros a assets en el proyecto y copiarlos mediante código en la carpeta que desees.
Un saludo!
Hola como puedo crear una lista de archivos sin que el primero sobreescriba al primero?
“Texto.txt” despues que cree uno : “Texto(1).txt”
Mi recomendación es que para esos casos uses el formato nombre+timestamp, así nunca se sobrescribirá el archivo.
Un saludo.
Hola, gracias por le tuto… miren que estoy programando una alarma para una hora espeficica, del dia… pero no esta funcionando.
el siguiente metodo intenta agendar la alarma… pero esta no se esta lanzando a la hora indicada, sino q esta lanzandose cuando se abre el app. Creo es xq el scheduleNotification es llamado desde el onCreate del MainActivity…
Que me pueden sugerir?
public void scheduleNotification(Context context , Notification notification, int hour, int minute ,long delay) {
//Creo el log
Log.i(“MainAct”, “Agendo Notificacion “+hour+”:”+minute + “, cada “+ delay );
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
long futureInMillis = SystemClock.elapsedRealtime() + delay;
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), delay, pendingIntent);
}
But is not working. For example is working only if you lunch the app., and after frequency-minuts, but not in the exact time.
any suggestion?
Gracias, funciona perfecto, explicas excelente XD
Gracias a ti por el comentario, me alegro de que te haya servido de ayuda.
Un saludo.