
Persistência de Dados Com Realm no Android - Parte 4
(2191)

CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim

CategoriaEngenharia de Software
Autor(es)Lucedile Antunes, Marcel Spadoto
EditoraLiterare Books International
Edição1ª
Ano2021
Páginas280
Opa, blz?
Nessa parte 4 da série Persistência Local com a Library Realm no Android são apresentados os scripts necessários para a obtenção das disciplinas e notas de cada bloco de nota vinculado ao estudante em formulário e então persistir esses dados na base Real junto ao estudante.
O modelo adotado para trabalho com notas é de sempre adicionar novas notas na base Realm, mesmo quando em modo update. Devido ao índice utilizado ser do tipo long (), essa escolha não foi adotado como problema e sim a mais simples e que responde bem ao que estamos construindo nessa APP. Uma outra opção para inserção de notas (grades) é utilizando também a library criada por Douglas Nassif (https://gist.github.com/douglasjunior/a6ed80a691957208deec). Note que as atualizações de código serão feitas na Activity AddUpdateStudentActivity.
O primeiro passo é criarmos um método que vai percorrer todo o layout depois de passarmos como parâmetro a View (button) que aciona o listener de inserção de estudante (além das disciplinas em disciplines), no caso vamos trabalhar o método getGradesFromView() apresentado abaixo:
private List<Grade> getGradesFromView( View view, RealmResults<Discipline> disciplines ){
List<Grade> list = new LinkedList<>();
RelativeLayout rlParent = (RelativeLayout) view.getParent();
for( int i = 0; i < rlParent.getChildCount(); i++ ){
if( rlParent.getChildAt( i ) instanceof ScrollView){
ScrollView scrollView = (ScrollView) rlParent.getChildAt( i );
LinearLayout llChild = (LinearLayout) scrollView.getChildAt( 0 );
for( int j = 0; j < llChild.getChildCount(); j++ ){
if( llChild.getChildAt( j ) instanceof LinearLayout ){
Spinner spDiscipline = (Spinner) llChild.getChildAt( j ).findViewById(R.id.sp_discipline);
EditText etGrade = (EditText) llChild.getChildAt( j ).findViewById(R.id.et_grade);
Grade g = new Grade();
if( realm.where(Grade.class).findAll().size() > 0 ){
g.setId( realm.where(Grade.class).findAll().where().findAllSorted("id", RealmResults.SORT_ORDER_DESCENDING).get(0).getId() + 1 + j );
}
else{
g.setId(1);
}
Discipline d = new Discipline();
d.setId( disciplines.get( spDiscipline.getSelectedItemPosition() ).getId() );
d.setName(disciplines.get(spDiscipline.getSelectedItemPosition()).getName());
g.setDiscipline(d);
g.setGrade(Double.parseDouble(etGrade.getText().toString()));
list.add( g );
}
}
}
}
return( list );
}
O RealtiveLayout rlParent é o root do layout activity_add_update_student.xml, temos de acessá-lo primeiro pois a view que é passado como parâmtero é o button bt_add_update (o button ADD na imagem abaixo):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<Button
android:id="@+id/bt_add_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="5dp"
android:onClick="callAddUpdateStudent"
android:text="Add" />
</RelativeLayout>
Esse button é filho direto do layout root, com acesso ao root é possível percorrer todas as outras Views que são filhas diretas dele. O código faz essa parte no primeiro loop do trecho abaixo:
...
for( int i = 0; i < rlParent.getChildCount(); i++ ){
if( rlParent.getChildAt( i ) instanceof ScrollView){
ScrollView scrollView = (ScrollView) rlParent.getChildAt( i );
LinearLayout llChild = (LinearLayout) scrollView.getChildAt( 0 );
for( int j = 0; j < llChild.getChildCount(); j++ ){
if( llChild.getChildAt( j ) instanceof LinearLayout ){
Spinner spDiscipline = (Spinner) llChild.getChildAt( j ).findViewById(R.id.sp_discipline);
EditText etGrade = (EditText) llChild.getChildAt( j ).findViewById(R.id.et_grade);
Grade g = new Grade();
if( realm.where(Grade.class).findAll().size() > 0 ){
g.setId( realm.where(Grade.class).findAll().where().findAllSorted("id", RealmResults.SORT_ORDER_DESCENDING).get(0).getId() + 1 + j );
}
else{
g.setId(1);
}
Discipline d = new Discipline();
d.setId( disciplines.get( spDiscipline.getSelectedItemPosition() ).getId() );
d.setName(disciplines.get(spDiscipline.getSelectedItemPosition()).getName());
g.setDiscipline(d);
g.setGrade(Double.parseDouble(etGrade.getText().toString()));
list.add( g );
}
}
}
}
...
Então é verificado se é um ScrollView, pois ele é o filho direto que nos permitirá chegar até os LinearLayouts que contém os Spinners e EditTexts com disciplinas e notas respectivamente. Acessando o ScrollView podemos ir diretamente ao acesso ao LinearLayout container dos blocos de notas e button bt_add, pois sabemos ele é o único filho direto do ScrollView, vejo esse trecho do layout activity_add_update_student.xml:
...
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bt_add_update"
android:layout_below="@+id/et_name"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/box_discipline_grade" />
<Button
android:id="@+id/bt_add"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="5dp"
android:background="#dddddd"
android:gravity="center"
android:onClick="callAddGrade"
android:text="Add"
android:textColor="#000" />
</LinearLayout>
</ScrollView>
...
Logo depois é verificar se é um LinearLayout, pois tem a possibilidade de ser um button (bt_add), se sim, é acessar o Spinner e EditText pelos ids. Note que para gerar um novo Grade id é verificado se há alguma Grade na base Realm, se sim então pegamos o de maior id (utilizando os métodos de busca e sort do Realm), acessamos esse maior id + 1 + j. O "j" é necessário, pois ainda não estamos adionando a grade (nota) na base, e sim na lista que será vinculada ao estudante na base, logo para garantir que se tiver mais de uma nota vinculada ao aluno, elas tenham ids distintos e únicos, o "j" será o contador que permitirá essa unicidade.
Com isso vamos para a parte 2 do código é que inserir essas grades na variavel grades do student, isso será realizado no método callAddUpdateStudent():
public void callAddUpdateStudent( View view ){
String label = "atualizado";
if( student.getId() == 0 ){
students.sort( "id", RealmResults.SORT_ORDER_DESCENDING );
long id = students.size() == 0 ? 1 : students.get(0).getId() + 1;
student.setId( id );
label = "adicionado";
}
try{
realm.beginTransaction();
student.setName(etName.getText().toString());
realm.copyToRealmOrUpdate(student);
realm.commitTransaction();
student = realm.where(Student.class).equalTo("id", student.getId()).findFirst();
realm.beginTransaction();
student.getGrades().clear();
student.getGrades().addAll( getGradesFromView( view, disciplines ) );
realm.commitTransaction();
Toast.makeText(AddUpdateStudentActivity.this, "Estudante " + label, Toast.LENGTH_SHORT).show();
finish();
}
catch(Exception e){
e.printStackTrace();
Toast.makeText(AddUpdateStudentActivity.this, "Falhou!", Toast.LENGTH_SHORT).show();
}
}
O trecho de código:
...
student = realm.where(Student.class).equalTo("id", student.getId()).findFirst();
realm.beginTransaction();
student.getGrades().clear();
student.getGrades().addAll( getGradesFromView( view, disciplines ) );
realm.commitTransaction();
...
É responsável por acessar o estudante recém inserido / atualizado, dessa forma, mesmo que a varivel grades do student esteja null, o retorno de Realm é com ele vazia e não null, ou seja, podemos acessar os métodos de RealmList<Grade> grades sem problemas de ter um NullPointerException, já que obtemos os dados da base Realm. Depois disso é entre begindTransaction() e commitTransaction() limpar todas as grades vinculadas ao user com o trecho student.getGrades().clear(); e então pegar as novas atribuições via trecho student.getGrades().addAll( getGradesFromView( view, disciplines ) );
Assim é salvo / atualizado primeiro o student e depois inseridas as notas a ele. Assim concluímos essa parte 4 da série. Porém ainda persisti um bug, tente acessar a atualização de qualquer um dos esrudantes que adicionou, o que terá é que não serão apresentadas as notas salvas, não porque elas não foram salvas, mas sim porque devemos construir essa parte quando for um mode update. Uma das partes da parte 5.
O código completo do projeto pode ser acessado no GitHub: https://github.com/viniciusthiengo/realm-students
Para acessar o site da library Realm: Documentação Realm Library Android
Segue vídeo de implementação da parte 4:
Vlw
Comentários Facebook