Realizaremos una aplicación padre-hijo en Realm utilizando Android. La aplicación crea “tableros” (padre) al que se le pueden añadir una o varias “notas” (hijo).
En artículos anteriores comenzamos la creación de una aplicación que crea “tableros” donde a cada tablero se le pueden añadir “notas”. Queremos realizar ésta típica aplicación padre-hijo en Realm con Android.
Puedes consultar nuestra aplicación que ya crea “tableros” en el siguiente enlace:
[Agregar y mostrar datos en Realm con Android]
Si deseas ver el funcionamiento hasta ahora puedes dar clic aquí.
Ahora deseamos crear “notas” para cada elemento “tablero” en la aplicación.
En la carpeta activities da clic derecho y elige New->Activity->Empty Activity
En Activity Name escribe: NoteActivity
Lo que deseamos hacer es que cuando haga clic en un elemento “tablero” abra ese NoteActivity. Además debemos pasarle el “id” del “tablero” seleccionado.
Vamos a MainActivity.
Tenemos actualmente la declaración de clase de la siguiente manera:
public class MainActivity extends AppCompatActivity
Vamos a modificar esa declaración implementando lo siguiente:
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener
Ahora agregaremos un listener a listview (la siguiente línea va en onCreate, después de agregar el listview
listview.setOnItemClickListener(this);
Debemos implementar el método que se requiere:
@Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { // Creamos un intent que va desde MainActivity hacia NoteActivity Intent intent = new Intent(MainActivity.this, NoteActivity.class); // Añadimos el id del item pulsado intent.putExtra("id", boards.get(position).getId()); startActivity(intent); }
El archivo activity_note.xml es donde creamos el diseño de NoteActivity. Abrimos el archivo activity_note.xml. El código que utilizaremos es el siguiente:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.gibgarcia.gibdata.activities.NoteActivity"> <ListView android:id="@+id/listViewNote" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:layout_editor_absoluteX="2dp" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fabAddNote" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_fab_add" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" app:layout_constraintBottom_toBottomOf="@+id/listViewNote" app:layout_constraintEnd_toEndOf="@+id/listViewNote" /> </android.support.constraint.ConstraintLayout>
Como puedes observar, contiene un ListView (donde irán apareciendo las “notas”, y un Floating Action Button (para crear nuevas “notas”).
Vamos a crear un layout (un diseño xml) para cada elemento “nota” que irá apareciendo a medida que se van creando.
En la carpeta de layout, damos clic derecho, elegiomos New-> Layout Resource file.
En File Name escribimos list_view_note_item
El código para este layout sería:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="15dp"> <TextView android:id="@+id/TextViewNoteDescription" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/TextViewNoteCreatedAt" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:textSize="10dp" android:textStyle="italic" /> </android.support.constraint.ConstraintLayout>
Un NoteAdapter nos permitirá crear un adaptador que será utilizado en el ListView que muestra todas las “notas”. Diseñaremos nuestro NoteAdapter bajo la técnica de ViewHolder para optimizar el rendimiento de nuestra aplicación.
Da clic derecho sobre Adapters luego New->JavaClass
En Name, escribimos NoteAdapter que es el nombre de la clase.
El código de NoteAdapter será:
package com.example.gibgarcia.gibdata.adapters; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.example.gibgarcia.gibdata.R; import com.example.gibgarcia.gibdata.models.Note; import org.w3c.dom.Text; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; /** * Created by gibgarcia on 07/11/18. */ public class NoteAdapter extends BaseAdapter { private Context context; private List<Note> list; private int layout; public NoteAdapter(Context context, List<Note> notes, int layout) { this.context = context; this.list = notes; this.layout = layout; } @Override public int getCount() { return list.size(); } @Override public Note getItem(int position) { return list.get(position); } @Override public long getItemId(int id) { return id ; } @Override public View getView(int position, View convertView, ViewGroup viewGroup) { ViewHolder vh; if (convertView == null){ convertView = LayoutInflater.from(context).inflate(layout, null); vh = new ViewHolder(); vh.description = (TextView) convertView.findViewById(R.id.TextViewNoteDescription); vh.createdAt= (TextView) convertView.findViewById(R.id.TextViewNoteCreatedAt); convertView.setTag(vh); }else{ vh = (ViewHolder) convertView.getTag(); } Note note = list.get(position); vh.description.setText(note.getDescription()); DateFormat df = new SimpleDateFormat("dd/MM/yyyy"); String date = df.format(note.getCreatedAt()); vh.createdAt.setText(date) ; return convertView ; } public class ViewHolder{ TextView description; TextView createdAt; } }
Por último, te dejo el código de la clase NoteActivity (que creamos al principio de éste artículo). Esta clase crea las notas y refresca el adaptador.
package com.example.gibgarcia.gibdata.activities; import android.content.DialogInterface; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import com.example.gibgarcia.gibdata.R; import com.example.gibgarcia.gibdata.adapters.NoteAdapter; import com.example.gibgarcia.gibdata.models.Board; import com.example.gibgarcia.gibdata.models.Note; import io.realm.Realm; import io.realm.RealmChangeListener; import io.realm.RealmList; import io.realm.RealmResults; public class NoteActivity extends AppCompatActivity implements RealmChangeListener<Board>{ private ListView listView; private FloatingActionButton fab; private NoteAdapter adapter; private RealmList<Note> notes; private Realm realm; private int boardId; private Board board; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_note); realm = Realm.getDefaultInstance(); if (getIntent().getExtras()!= null) boardId = getIntent().getExtras().getInt("id"); board = realm.where(Board.class).equalTo("id", boardId).findFirst(); board.addChangeListener(this); notes = board.getNotes(); this.setTitle(board.getTitle()); fab = (FloatingActionButton) findViewById(R.id.fabAddNote); listView = (ListView) findViewById(R.id.listViewNote); adapter = new NoteAdapter(this, notes, R.layout.list_view_note_item); listView.setAdapter(adapter); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showAlertForCreatingNote("Agregue una nueva nota", "Escriba una nueva nota para " + board.getTitle()+".") ; } }); } public void showAlertForCreatingNote(String title, String message){ //Creo un builder para construir un cuadro de dialogo personalizado AlertDialog.Builder builder = new AlertDialog.Builder(this); //Si los parametros title y message no vienen vacíos, los utilizo para mi cuadro if (title != null) builder.setTitle(title); if (message != null) builder.setMessage(message); // Creo una vista usando el layout dialog_create_board View viewInflated = LayoutInflater.from(this).inflate(R.layout.dialog_create_note, null); // Asigno esa vista al builder builder.setView(viewInflated); final EditText input = (EditText) viewInflated.findViewById(R.id.editTextNewNote); // Tendremos un botón que dice Agregar y que al dale clic... builder.setPositiveButton("Agregar", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { // ... extrae el texto escrito en el EditText llamado editTextNewNote String note = input.getText().toString().trim(); // Si el usuario escribe algo, se utiliza para crear una nota, si no, error. if (note.length() > 0) createNewNote(note); else Toast.makeText(getApplicationContext(), "Debe escribir algo", Toast.LENGTH_LONG).show(); } }); // Muestro el cuadro de dialogo creado. AlertDialog dialog = builder.create(); dialog.show(); } public void createNewNote(String note){ realm.beginTransaction(); Note _note = new Note(note); realm.copyToRealm(_note); board.getNotes().add(_note); realm.commitTransaction(); } @Override public void onChange(Board element) { adapter.notifyDataSetChanged(); } }
Con esto tenemos todo lo necesario para desarrollar nuestra aplicación padre-hijo en Realm.
Si deseas ver el comportamiento de la aplicación hasta este punto, da clic aquí.