Tutorial Android paso a paso III: Desarrollo de la aplicación Notepad
En este tercer y último post del tutorial, vamos a practicar el ciclo de vida de la aplicación, y como guardar y recuperar el estado de la aplicación.
Puedes ver los anteriores artículos:
Tutorial Android paso a paso I: Desarrollo de la aplicación Notepad
Tutorial Android paso a paso II: Desarrollo de la aplicación Notepad
Objetivos:
• Conocer los eventos del ciclo de vida de la aplicación.
• Tecnicas para mantener el estado de la aplicación.
Paso 1
La aplicación actual contiene algunos problemas. Para solucionarlo, vamos a mover la funcionalidad de edición de notas a la clase NoteEdit.
1. Eliminar el siguiente código de la clase NoteEdit, que obtiene los datos de la nota a través del Bundle. Vamos a pasar a utilizar la clase DBHelper para obtener los datos directamente de la base de datos.
1 2 3 4 5 | Bundle extras = getIntent().getExtras(); … String title = extras.getString(NotesDbAdapter.KEY_TITLE); String body = extras.getString(NotesDbAdapter.KEY_BODY); mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); |
2. Además, eliminamos la asignación de los datos a la interfaz de usuario
1 2 3 4 5 6 | if (title != null) { mTitleText.setText(title); } if (body != null) { mBodyText.setText(body); } |
Paso 2
Conectamos la clase NoteEdit con la base de datos.
1. Creamos un nuevo atributo:
1 | private NotesDbAdapter mDbHelper; |
2. Conectamos con la base de datos en el constructor, justo después de llamar al constructor padre:
1 2 | mDbHelper = new NotesDbAdapter(this); mDbHelper.open(); |
Paso 3
Pasamos a comprobar el estado de la variable savedInstanceState. Esto sirve para comprobar si tenemos datos guardados en el Bundle, que debemos recuperar (Esto ocurre si la actividad pierde el foco y después se recupera).
1. Reeplazar el siguiente código:
1 2 3 4 5 | mRowId = null; Bundle extras = getIntent().getExtras(); if (extras != null) { mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID); } |
Por este otro
1 2 3 4 5 | mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID) : null; if (mRowId == null) { Bundle extras = getIntent().getExtras(); mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID) : null; } |
Paso 4
Necesitamos completar los campos con los datos de la nota. Llamamos al método populateFields() que completaremos más adelante. Insertarlo justo antes de confirmButton.setOnClickListener():
1 | populateFields(); |
Paso 5
En esta actividad ya no es necesario devolver ningún tipo de datos, ya que vamos a guardar los datos directamente en esta actividad, por lo que es posible simplificar el método onClick() considerablemente:
1 2 3 4 | public void onClick(View view) { setResult(RESULT_OK); finish(); } |
Más adelante veremos como guardar los datos.
Paso 6
Definimos el método populateFields():
1 2 3 4 5 6 7 8 | private void populateFields() { if (mRowId != null) { Cursor note = mDbHelper.fetchNote(mRowId); startManagingCursor(note); mTitleText.setText(note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE))); mBodyText.setText(note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY))); } } |
Paso 7
Implementamos los métodos que gestionan el ciclo de vida de Android. Estos métodos nos permiten guardar y recuperar el estado de la actividad en caso de que esta se cierre o pase a un segundo plano (al recibir una llamada, por ejemplo):
1. onSaveInstanceState(): es llamada por Android cuando la actividad va a ser cerrada. Esto significa que aquí se debe guardar toda la información necesaria para restaurar la actividad en su estado anterior. Podemos pensar que es el método contrario a onCreate(), de hecho el Bundle que construimos en este método, es el que será pasado al método onCreate().
1 2 3 4 5 | @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong(NotesDbAdapter.KEY_ROWID, mRowId); } |
2. onPause(): es llamada cuando la actividad va a terminar (con finish()) o pasar a un segundo plano (con una llamada de teléfono).
1 2 3 4 5 | @Override protected void onPause() { super.onPause(); saveState(); } |
3. onResume(): es llamada al reactivar la actividad. Completamos los campos:
1 2 3 4 5 | @Override protected void onResume() { super.onResume(); populateFields(); } |
Paso 8
Para terminar de completar la clase NoteEdit, ya solo nos queda guardar los datos en la base de datos. Creamos el método saveState():
1 2 3 4 5 6 7 8 9 10 11 12 | private void saveState() { String title = mTitleText.getText().toString(); String body = mBodyText.getText().toString(); if (mRowId == null) { long id = mDbHelper.createNote(title, body); if (id > 0) { mRowId = id; } } else { mDbHelper.updateNote(mRowId, title, body); } } |
Paso 9
Volvemos a la clase Notepadv3. En el método onActivityResult(), teníamos implementado todo lo necesario para recibir los datos de la actividad y guardarla en la base de datos. Como este proceso ya lo realizamos en la clase NoteEdit, solo es necesario que actualizemos la lista con los nuevos datos:
1 2 3 4 5 | @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); fillData(); } |
Paso 10
Finalmente, es esta misma clase, al seleccionar un elemento de la lista, ya no es ncesario pasar todos los datos de la nota, únicamente el id, por lo que el método onListItemClick(), quedaría de la siguiete manera:
1 2 3 4 5 6 7 | @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); Intent i = new Intent(this, NoteEdit.class); i.putExtra(NotesDbAdapter.KEY_ROWID, id); startActivityForResult(i, ACTIVITY_EDIT); } |
Y con este último post hemos terminado el tutorial. Espero que os haya servido de ayuda y, como siempre, cualquier duda o pregunta en los comentarios.
Todavia no lo leeo a detalle pero me parece muy bueno, EXCELENTE TRABAJO.
Esta muy bueno el tutorial, y en el simulador seguro que funciona; pero para llevarlo a un celular como se hace?, en cualquier celular con android funciona? sin importar la version de android?.
Muchas gracias
Hola!
Acabo de terminar el tutorial y está bastante bien, aunque estaría aun mejor si explicases absolutamente todo, es decir, creando un proyecto nuevo desde 0. Si te animas, te lo agradeceré enormemente.
Un saludo.
Buenas,
Muy bueno el tutorial, de gran ayuda para gente que sabe algo de java pero que android se le escapa.
Muchas gracias.
gracias por el tutorial me sirvió mucho
como se despliega la alplicacion, ya sea en un emulador o en el telefono??
Increíble el tutorial. Muchas gracias.
Hola que tal una duda esta muy bueno tu tutorial lo acabo de terminar pero me sale el siguiente error.
Unfortunately, com.android.demo.notepad1 has stopped.
03-06 17:20:35.102: E/AndroidRuntime(605): FATAL EXCEPTION: main
03-06 17:20:35.102: E/AndroidRuntime(605): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=null} to activity {com.android.demo.notepad1/com.android.demo.notepad1.Notepadv1}: java.lang.NullPointerException
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread.deliverResults(ActivityThread.java:2980)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread.access$1100(ActivityThread.java:123)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.os.Handler.dispatchMessage(Handler.java:99)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.os.Looper.loop(Looper.java:137)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread.main(ActivityThread.java:4424)
03-06 17:20:35.102: E/AndroidRuntime(605): at java.lang.reflect.Method.invokeNative(Native Method)
03-06 17:20:35.102: E/AndroidRuntime(605): at java.lang.reflect.Method.invoke(Method.java:511)
03-06 17:20:35.102: E/AndroidRuntime(605): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-06 17:20:35.102: E/AndroidRuntime(605): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-06 17:20:35.102: E/AndroidRuntime(605): at dalvik.system.NativeStart.main(Native Method)
03-06 17:20:35.102: E/AndroidRuntime(605): Caused by: java.lang.NullPointerException
03-06 17:20:35.102: E/AndroidRuntime(605): at com.android.demo.notepad1.Notepadv1.onActivityResult(Notepadv1.java:120)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.Activity.dispatchActivityResult(Activity.java:4649)
03-06 17:20:35.102: E/AndroidRuntime(605): at android.app.ActivityThread.deliverResults(ActivityThread.java:2976)
Saludos muchas gracias.
Esta muy bueno. Estaria mejor si pones imagenes
Hola, un gusto. Desde ya que mil gracias por el tutorial, está muy bien hecho. Quería hacerte unas preguntas:
¿Cómo harías para que ademas de notas se puedan subir fotos (Capturadas por el mismo dispositivo, es decir, que lanze la camara y tome una foto, y la misma quede guardada debajo de las notas)?
Y videos? (De la misma forma, capturadas por el dispositivo celular o tablet que la esté ejecutando)
Estaría mejor si se pudieran ordenar las notas por un lado, las imagenes por otro y los videos por otro, que no parece complicado.
Agradezco tu respuesta, realmente la necesito!
Saludos!
Mati.
Hola!!! tu tutorial me ha ayudado bastante, pero tengo una pregunta ¿las notas que haces con ésta aplicación se pueden visualizar en una computadora?
De antemano, gracias.