{"id":1701,"date":"2018-11-08T12:49:23","date_gmt":"2018-11-08T18:49:23","guid":{"rendered":"http:\/\/naps.com.mx\/blog\/?p=1701"},"modified":"2018-11-14T15:08:58","modified_gmt":"2018-11-14T21:08:58","slug":"creacion-de-una-aplicacion-padre-hijo-en-realm-con-android","status":"publish","type":"post","link":"https:\/\/naps.com.mx\/blog\/creacion-de-una-aplicacion-padre-hijo-en-realm-con-android\/","title":{"rendered":"Creaci\u00f3n de una aplicaci\u00f3n padre-hijo en Realm con Android"},"content":{"rendered":"<p><em><strong>Realizaremos una aplicaci\u00f3n padre-hijo en Realm utilizando Android. La aplicaci\u00f3n crea \u201ctableros\u201d (padre) al que se le pueden a\u00f1adir una o varias \u201cnotas\u201d (hijo).<\/strong><\/em><\/p>\n<p><em><strong><span class=\"Apple-converted-space\">\u00a0<\/span><\/strong><\/em><!--more--><\/p>\n<h2>Aplicaci\u00f3n padre-hijo en Realm<\/h2>\n<p>En art\u00edculos anteriores comenzamos la creaci\u00f3n de una aplicaci\u00f3n que crea \u201ctableros\u201d donde a cada tablero se le pueden a\u00f1adir \u201cnotas\u201d. Queremos realizar \u00e9sta t\u00edpica aplicaci\u00f3n padre-hijo en <a href=\"https:\/\/realm.io\">Realm<\/a> con Android.<\/p>\n<p>Puedes consultar nuestra aplicaci\u00f3n que ya crea \u201ctableros\u201d en el siguiente enlace:<\/p>\n<p><a href=\"http:\/\/naps.com.mx\/blog\/agregar-y-mostrar-datos-en-realm-con-android\/\">[Agregar y mostrar datos en Realm con Android]<\/a><\/p>\n<div id=\"attachment_1714\" style=\"width: 450px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/11-aplicacion-padre-hijo-en-Realm.jpeg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1714\" class=\"size-full wp-image-1714\" src=\"http:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/11-aplicacion-padre-hijo-en-Realm.jpeg\" alt=\"aplicacion padre-hijo en Realm\" width=\"440\" height=\"732\" srcset=\"https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/11-aplicacion-padre-hijo-en-Realm.jpeg 440w, https:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/11-aplicacion-padre-hijo-en-Realm-180x300.jpeg 180w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/a><p id=\"caption-attachment-1714\" class=\"wp-caption-text\">Aplicacion padre-hijo en Realm<\/p><\/div>\n<p>Si deseas ver el funcionamiento hasta ahora puedes dar clic <a href=\"http:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/09-gip_tableros.gif\">aqu\u00ed<\/a>.<\/p>\n<p>Ahora deseamos crear \u201cnotas\u201d para cada elemento \u201ctablero\u201d en la aplicaci\u00f3n.<\/p>\n<h2>Creaci\u00f3n del activity NoteActivity<\/h2>\n<p>En la carpeta <em>activities<\/em> da clic derecho y elige<strong> New-&gt;Activity-&gt;Empty Activity<\/strong><\/p>\n<p>En Activity Name escribe: <strong>NoteActivity<\/strong><\/p>\n<p>Lo que deseamos hacer es que cuando haga clic en un elemento \u201ctablero\u201d abra ese <strong>NoteActivity<\/strong>. Adem\u00e1s debemos pasarle el \u201c<em>id<\/em>\u201d del \u201ctablero\u201d seleccionado.<\/p>\n<h2>Enlazar \u00a0NoteActivity desde MainActivity<\/h2>\n<p>Vamos a <strong>MainActivity<\/strong>.<\/p>\n<p>Tenemos<span class=\"Apple-converted-space\">\u00a0 <\/span>actualmente la declaraci\u00f3n de clase de la siguiente manera:<\/p>\n<pre class=\"lang:java decode:true \">public class MainActivity extends AppCompatActivity<\/pre>\n<p>Vamos a modificar esa declaraci\u00f3n implementando lo siguiente:<\/p>\n<pre class=\"lang:java decode:true \">public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener<\/pre>\n<p>Ahora agregaremos un <em>listener<\/em> a <em>listview<\/em> (la siguiente l\u00ednea va en <strong>onCreate<\/strong>, despu\u00e9s de agregar el listview<\/p>\n<pre class=\"lang:java decode:true \">listview.setOnItemClickListener(this);<\/pre>\n<p>Debemos implementar el m\u00e9todo que se requiere:<\/p>\n<pre class=\"lang:java decode:true\">    @Override\r\n    public void onItemClick(AdapterView&lt;?&gt; adapterView, View view, int position, long id) {\r\n\r\n        \/\/ Creamos un intent que va desde MainActivity hacia NoteActivity\r\n        Intent intent = new Intent(MainActivity.this, NoteActivity.class);\r\n         \/\/ A\u00f1adimos el id del item pulsado\r\n        intent.putExtra(\"id\", boards.get(position).getId());\r\n        startActivity(intent);\r\n    }\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h2>Dise\u00f1o del layout activity_note.xml<\/h2>\n<p>El archivo activity_note.xml es donde creamos el dise\u00f1o de NoteActivity. Abrimos el archivo activity_note.xml. El c\u00f3digo que utilizaremos es el siguiente:<\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\r\n&lt;android.support.constraint.ConstraintLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    xmlns:app=\"http:\/\/schemas.android.com\/apk\/res-auto\"\r\n    xmlns:tools=\"http:\/\/schemas.android.com\/tools\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    tools:context=\"com.example.gibgarcia.gibdata.activities.NoteActivity\"&gt;\r\n\r\n\r\n    &lt;ListView\r\n        android:id=\"@+id\/listViewNote\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"match_parent\"\r\n        android:layout_marginBottom=\"8dp\"\r\n        android:layout_marginTop=\"8dp\"\r\n        app:layout_constraintBottom_toBottomOf=\"parent\"\r\n        app:layout_constraintTop_toTopOf=\"parent\"\r\n        app:layout_constraintEnd_toEndOf=\"parent\"\r\n        tools:layout_editor_absoluteX=\"2dp\" \/&gt;\r\n\r\n    &lt;android.support.design.widget.FloatingActionButton\r\n        android:id=\"@+id\/fabAddNote\"\r\n        android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:src=\"@drawable\/ic_fab_add\"\r\n\r\n        android:layout_marginBottom=\"8dp\"\r\n        android:layout_marginEnd=\"8dp\"\r\n        app:layout_constraintBottom_toBottomOf=\"@+id\/listViewNote\"\r\n        app:layout_constraintEnd_toEndOf=\"@+id\/listViewNote\" \/&gt;\r\n\r\n&lt;\/android.support.constraint.ConstraintLayout&gt;<\/pre>\n<p>Como puedes observar, contiene un <strong>ListView<\/strong> (donde ir\u00e1n apareciendo las \u00abnotas\u00bb, y un <strong>Floating Action Button<\/strong> (para crear nuevas \u00abnotas\u00bb).<\/p>\n<h2>Creamos el layout list_view_note_item<\/h2>\n<p>Vamos a crear un <em>layout<\/em> (un dise\u00f1o xml) para cada elemento \u00abnota\u00bb que ir\u00e1 apareciendo a medida que se van creando.<\/p>\n<p>En la carpeta de <em>layout<\/em>, damos clic derecho, elegiomos New-&gt; Layout Resource file.<\/p>\n<p>En File Name escribimos <strong>list_view_note_item<\/strong><\/p>\n<p>El c\u00f3digo para este layout ser\u00eda:<\/p>\n<pre class=\"lang:xhtml decode:true \">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;\r\n&lt;android.support.constraint.ConstraintLayout\r\n    xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    android:orientation=\"vertical\"\r\n    android:padding=\"15dp\"&gt;\r\n\r\n    &lt;TextView\r\n        android:id=\"@+id\/TextViewNoteDescription\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n\r\n    \/&gt;\r\n\r\n    &lt;TextView\r\n        android:id=\"@+id\/TextViewNoteCreatedAt\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:gravity=\"right\"\r\n        android:textSize=\"10dp\"\r\n        android:textStyle=\"italic\"\r\n\r\n        \/&gt;\r\n\r\n\r\n&lt;\/android.support.constraint.ConstraintLayout&gt;<\/pre>\n<h2>Crear la clase NoteAdapter<\/h2>\n<p>Un NoteAdapter nos permitir\u00e1 crear un adaptador que ser\u00e1 utilizado en el ListView que muestra todas las \u00abnotas\u00bb. Dise\u00f1aremos nuestro NoteAdapter bajo la t\u00e9cnica de ViewHolder para optimizar el rendimiento de nuestra aplicaci\u00f3n.<\/p>\n<p>Da clic derecho sobre <em>Adapters<\/em> luego<strong> New-&gt;JavaClass<\/strong><\/p>\n<p>En Name, escribimos <strong>NoteAdapter<\/strong> que es el nombre de la clase.<\/p>\n<p>El c\u00f3digo de NoteAdapter ser\u00e1:<\/p>\n<pre class=\"lang:java decode:true \">package com.example.gibgarcia.gibdata.adapters;\r\n\r\nimport android.content.Context;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\nimport android.widget.BaseAdapter;\r\nimport android.widget.TextView;\r\n\r\nimport com.example.gibgarcia.gibdata.R;\r\nimport com.example.gibgarcia.gibdata.models.Note;\r\n\r\nimport org.w3c.dom.Text;\r\n\r\nimport java.text.DateFormat;\r\nimport java.text.SimpleDateFormat;\r\nimport java.util.List;\r\n\r\n\/**\r\n * Created by gibgarcia on 07\/11\/18.\r\n *\/\r\n\r\npublic class NoteAdapter extends BaseAdapter  {\r\n    private Context context;\r\n    private List&lt;Note&gt; list;\r\n    private int layout;\r\n\r\n\r\n    public NoteAdapter(Context context, List&lt;Note&gt; notes, int layout) {\r\n        this.context = context;\r\n        this.list = notes;\r\n        this.layout = layout;\r\n    }\r\n\r\n    @Override\r\n    public int getCount() {\r\n        return list.size();\r\n    }\r\n\r\n    @Override\r\n    public Note getItem(int position) {\r\n        return list.get(position);\r\n    }\r\n\r\n    @Override\r\n    public long getItemId(int id) {\r\n        return id ;\r\n    }\r\n\r\n    @Override\r\n    public View getView(int position, View convertView, ViewGroup viewGroup) {\r\n        ViewHolder vh;\r\n        if (convertView == null){\r\n            convertView = LayoutInflater.from(context).inflate(layout, null);\r\n            vh = new ViewHolder();\r\n            vh.description = (TextView) convertView.findViewById(R.id.TextViewNoteDescription);\r\n            vh.createdAt= (TextView) convertView.findViewById(R.id.TextViewNoteCreatedAt);\r\n            convertView.setTag(vh);\r\n        }else{\r\n            vh = (ViewHolder) convertView.getTag();\r\n        }\r\n\r\n        Note note  = list.get(position);\r\n        vh.description.setText(note.getDescription());\r\n        DateFormat df = new SimpleDateFormat(\"dd\/MM\/yyyy\");\r\n        String date = df.format(note.getCreatedAt());\r\n        vh.createdAt.setText(date) ;\r\n        return convertView ;\r\n    }\r\n\r\n    public class ViewHolder{\r\n        TextView description;\r\n        TextView createdAt;\r\n\r\n    }\r\n}\r\n<\/pre>\n<h2>C\u00f3digo de NoteActivity<\/h2>\n<p>Por \u00faltimo, te dejo el c\u00f3digo de la clase NoteActivity (que creamos al principio de \u00e9ste art\u00edculo). Esta clase crea las notas y refresca el adaptador.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:java decode:true \">package com.example.gibgarcia.gibdata.activities;\r\n\r\nimport android.content.DialogInterface;\r\nimport android.support.design.widget.FloatingActionButton;\r\nimport android.support.v7.app.AlertDialog;\r\nimport android.support.v7.app.AppCompatActivity;\r\nimport android.os.Bundle;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.widget.EditText;\r\nimport android.widget.ListView;\r\nimport android.widget.Toast;\r\n\r\nimport com.example.gibgarcia.gibdata.R;\r\nimport com.example.gibgarcia.gibdata.adapters.NoteAdapter;\r\nimport com.example.gibgarcia.gibdata.models.Board;\r\nimport com.example.gibgarcia.gibdata.models.Note;\r\n\r\nimport io.realm.Realm;\r\nimport io.realm.RealmChangeListener;\r\nimport io.realm.RealmList;\r\nimport io.realm.RealmResults;\r\n\r\npublic class NoteActivity extends AppCompatActivity implements RealmChangeListener&lt;Board&gt;{\r\n    private ListView listView;\r\n    private FloatingActionButton fab;\r\n    private NoteAdapter adapter;\r\n    private RealmList&lt;Note&gt; notes;\r\n    private Realm realm;\r\n\r\n    private int boardId;\r\n    private Board board;\r\n\r\n\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        setContentView(R.layout.activity_note);\r\n\r\n        realm = Realm.getDefaultInstance();\r\n        if (getIntent().getExtras()!= null)\r\n            boardId = getIntent().getExtras().getInt(\"id\");\r\n        board = realm.where(Board.class).equalTo(\"id\", boardId).findFirst();\r\n        board.addChangeListener(this);\r\n        notes = board.getNotes();\r\n        this.setTitle(board.getTitle());\r\n\r\n        fab = (FloatingActionButton) findViewById(R.id.fabAddNote);\r\n        listView = (ListView) findViewById(R.id.listViewNote);\r\n        adapter = new NoteAdapter(this, notes, R.layout.list_view_note_item);\r\n        listView.setAdapter(adapter);\r\n        fab.setOnClickListener(new View.OnClickListener() {\r\n            @Override\r\n            public void onClick(View view) {\r\n                showAlertForCreatingNote(\"Agregue una nueva nota\", \"Escriba una nueva nota para \" + board.getTitle()+\".\") ;\r\n            }\r\n        });\r\n    }\r\n\r\n    public void showAlertForCreatingNote(String title, String message){\r\n        \/\/Creo un builder para construir un cuadro de dialogo personalizado\r\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\r\n        \/\/Si los parametros title y message no vienen vac\u00edos, los utilizo para mi cuadro\r\n        if (title != null) builder.setTitle(title);\r\n        if (message != null) builder.setMessage(message);\r\n        \/\/ Creo una vista usando el layout dialog_create_board\r\n        View viewInflated = LayoutInflater.from(this).inflate(R.layout.dialog_create_note, null);\r\n        \/\/ Asigno esa vista al builder\r\n        builder.setView(viewInflated);\r\n        final EditText input = (EditText) viewInflated.findViewById(R.id.editTextNewNote);\r\n\r\n        \/\/ Tendremos un bot\u00f3n que dice Agregar y que al dale clic...\r\n        builder.setPositiveButton(\"Agregar\", new DialogInterface.OnClickListener() {\r\n            @Override\r\n            public void onClick(DialogInterface dialogInterface, int i) {\r\n                \/\/ ... extrae el texto escrito en el EditText llamado editTextNewNote\r\n                String note = input.getText().toString().trim();\r\n                \/\/ Si el usuario escribe algo, se utiliza para crear una nota, si no, error.\r\n                if (note.length() &gt; 0)\r\n                    createNewNote(note);\r\n                else\r\n                    Toast.makeText(getApplicationContext(), \"Debe escribir algo\", Toast.LENGTH_LONG).show();\r\n\r\n            }\r\n        });\r\n        \/\/ Muestro el cuadro de dialogo creado.\r\n        AlertDialog dialog = builder.create();\r\n        dialog.show();\r\n    }\r\n\r\n    public void createNewNote(String note){\r\n        realm.beginTransaction();\r\n        Note _note = new Note(note);\r\n        realm.copyToRealm(_note);\r\n        board.getNotes().add(_note);\r\n        realm.commitTransaction();\r\n    }\r\n\r\n    @Override\r\n    public void onChange(Board element) {\r\n        adapter.notifyDataSetChanged();\r\n    }\r\n}\r\n<\/pre>\n<p>Con esto tenemos todo lo necesario para desarrollar nuestra aplicaci\u00f3n padre-hijo en Realm.<\/p>\n<p>Si deseas ver el comportamiento de la aplicaci\u00f3n hasta este punto, da clic <a href=\"http:\/\/naps.com.mx\/blog\/wp-content\/uploads\/2018\/11\/10-gif-nota.gif\">aqu\u00ed<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Realizaremos una aplicaci\u00f3n padre-hijo en Realm utilizando Android. La aplicaci\u00f3n crea \u201ctableros\u201d (padre) al que se le pueden a\u00f1adir una o varias \u201cnotas\u201d (hijo). \u00a0<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"amp_status":"","footnotes":""},"categories":[234],"tags":[198,235,243],"class_list":["post-1701","post","type-post","status-publish","format-standard","hentry","category-aplicaciones-moviles","tag-android","tag-desarrollo-de-aplicaciones-moviles","tag-realm"],"_links":{"self":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/comments?post=1701"}],"version-history":[{"count":12,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1701\/revisions"}],"predecessor-version":[{"id":1728,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/posts\/1701\/revisions\/1728"}],"wp:attachment":[{"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/media?parent=1701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/categories?post=1701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/naps.com.mx\/blog\/wp-json\/wp\/v2\/tags?post=1701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}