Persistência de Dados Com Realm no Android - Parte 3
(2142)
CategoriasAndroid, Design, Protótipo
AutorVinÃcius Thiengo
VÃdeo aulas186
Tempo15 horas
ExercÃciosSim
CertificadoSim
CategoriaEngenharia de Software
Autor(es)Vlad Khononov
EditoraAlta Books
Edição1ª
Ano2024
Páginas320
Opa, blz?
Na parte 3 da série Persistência Local de Dados com Realm Library no Android, é apresentada a implementação dos métodos que vão permitir a inserção dinâmica do bloco de Views responsável por permitir a entrada de cada nota para cada disciplina cursada pelo estudante. A Activity que receberá as modificações é a AddUpdateStudentActivity junto ao novo adapter DisciplineSpinnerAdapter.
O primeiro passo é adicionar o layout box_discipline_grade.xml que terá o conjunto Spinner (onde vem as disciplinas já cadastradas no APP), EditText (a nota do aluno na disciplina) e Button (permitirá a inclusão de um listesner para a remoção do box de nota), segue código:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:textSize="18sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/bt_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Atualizar"
android:textSize="12sp" />
<Button
android:id="@+id/bt_remove"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Remover"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
O passo 2 é atualizar o layout activity_add_update_student.xml que terá a parte de notas e o button que permitirá o user / professor adicionar outras disciplinas e notas ao aluno, segue código:
<?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">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:gravity="center"
android:padding="5dp"
android:text="Novo estudante"
android:textSize="18sp" />
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginTop="10dp"
android:hint="Nome" />
<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>
<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>
Note que temos um ScrollView para manter a possibilidade do user adicionar quantas disciplinas forem necessárias (tendo em mente que haverá muitas disciplinas e não disciplinas repetidas para cada aluno) sem colocar o conteúdo abaixo do button "ADD" da Activity AddUpdateStudentsActivity.
Logo como sendo o primeiro e único filho do ScrollView, temos o View LinearLayout que será o container chave para que possamos adicionar mais box_discipline_grade.xml de forma dinâmica na tela. O LinearLayout e o button bt_add são os elementos chave, sempre um novo bloco de nota entra acima desse button.
Segue código do método createGradeForView() de AddUpdateStudentActivity, que junto ao método getDisciplinePosition() adiciona a Activity um novo bloco de notas vazio ou um já preenchido quando em modo update:
private void createGradeForView( View view, RealmResults<Discipline> disciplines, Grade grade ){
LayoutInflater inflater = this.getLayoutInflater();
LinearLayout llChild = (LinearLayout) inflater.inflate(R.layout.box_discipline_grade, null);
Spinner spDiscipline = (Spinner) llChild.findViewById(R.id.sp_discipline);
spDiscipline.setAdapter( new DisciplineSpinnerAdapter( this, disciplines ));
if( grade != null ){
spDiscipline.setSelection(getDisciplinePosition(disciplines, grade.getDiscipline()));
}
EditText etGrade = (EditText) llChild.findViewById(R.id.et_grade);
if( grade != null ){
etGrade.setText(String.valueOf(grade.getGrade()));
}
View btRemove = llChild.findViewById(R.id.bt_remove);
btRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callRemoveGrade( v );
}
});
float scale = getResources().getDisplayMetrics().density;
int margin = (int)( 5 * scale + 0.5f );
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins( margin, margin, margin, margin );
llChild.setLayoutParams( layoutParams );
LinearLayout llParent = (LinearLayout) view.getParent();
llParent.addView( llChild, llParent.getChildCount() - 1 );
}
Note que devido a perda de propriedades no momento de inflar o layout de llChild, propriedades como width, height e margin temos de setar os valores reais para esses atributos novamente via LayoutParams no code.
Segue código do método getDisciplinePosition():
private int getDisciplinePosition( RealmResults<Discipline> disciplines, Discipline discipline ){
for( int i = 0; i < disciplines.size(); i++ ){
if( disciplines.get(i).getId() == discipline.getId() ){
return( i );
}
}
return(0);
}
O método acima vai permitir acessar a posição correta da disciplina no Spinner do bloco, em modo update.
Precisamos então da variavel de instancia disciplines, do adapter DisciplineSpinnerAdapter, do método listener callRemoveGrade() que será vinculado ao listener de click do button bt_remove e do outro método listener (que já está vinculado via xml onClick ao button bt_add) callAddGrade().
Primeiro disciplines nas declarações de varaiveis de instancia da Activity:
...
private Realm realm;
private RealmResults<Student> students;
private RealmResults<Discipline> disciplines;
private Student student;
private EditText etName;
...
Logo depois a inicialização de disciplines dentro do onCreate():
...
disciplines = realm.where(Discipline.class).findAll();
Spinner spDiscipline = (Spinner) findViewById(R.id.sp_discipline);
spDiscipline.setAdapter( new DisciplineSpinnerAdapter( this, disciplines ));
View btRemove = findViewById(R.id.bt_remove);
btRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callRemoveGrade( v );
}
});
...
Nessa parte já é colocado também o trecho de código responsável por já colocar um comportamento de click listener no button bt_remove e prencher o Spinner sp_discipline. Ambos são do primeiro bloco de nota (grade) que já vem no layout sem a necessidade de uso do método createGradeForView() para criá-lo.
Segue código do método listener callRemoveGrade():
private void callRemoveGrade( View view ){
LinearLayout llParent = (LinearLayout) view.getParent().getParent();
if( llParent.getChildCount() > 2 ){
llParent.removeView((LinearLayout) view.getParent());
}
}
O que ele recebe como parêmtro é o button de remoção do bloco de nota que teve seu respectivo button de remover clicado, então a chamada view.getParent().getParent() nos permiti acessar o LinearLayout que o primeiro filho do ScrollView (comentado anteriormente) e container dos blocos de notas (LinearLayout) e do button que adiciona mais blocos. Note que a verificação se o número de elementos filhos é maior que 2 nos permite sempre ter na tela de cadastro / update de estudante as views button para adicionar mais blocos de notas e ao menos um bloco de nota que é um LinearLayout e seus views filho. O cast é necessário para a remossão e utilização de métodos especificos não suportados por ViewGroup (retornado por getParent()).
Agora seguimos com o código do método callAddGrade():
public void callAddGrade( View view ){
LinearLayout llParent = (LinearLayout) view.getParent();
if( llParent.getChildCount() - 1 == disciplines.size() ){
Toast.makeText(this, "Máximo de disciplinas atingido", Toast.LENGTH_SHORT).show();
return;
}
createGradeForView( view, disciplines, null );
}
Note que nele verificamos se o total de blocos de notas dentro do LinearLayout container é igual ao tamanho máximo de disciplines, colocamos isso como sendo uma regra de negócio do sistema, não permitir disciplinas repetidas para o mesmo estudante. O - 1 é necessário para não ser contado o button bt_add.
Enfim o código do DisciplineSpinnerAdapter para que seja possível colocar as disciplinas nos spinners de cada bloco de notas, segue código:
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.TextView;
import br.com.thiengo.realmstudents.R;
import br.com.thiengo.realmstudents.domain.Discipline;
import io.realm.RealmBaseAdapter;
import io.realm.RealmResults;
public class DisciplineSpinnerAdapter extends RealmBaseAdapter<Discipline> implements ListAdapter {
public DisciplineSpinnerAdapter(Context context, RealmResults<Discipline> realmResults){
super(context, realmResults, false);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
CustomViewHolder holder;
if( convertView == null ){
convertView = inflater.inflate(R.layout.item_discipline_spinner, parent, false);
holder = new CustomViewHolder();
convertView.setTag( holder );
holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
}
else{
holder = (CustomViewHolder) convertView.getTag();
}
final Discipline d = realmResults.get(position);
holder.tvName.setText(d.getName());
return convertView;
}
private static class CustomViewHolder{
TextView tvName;
}
}
Note que o DisciplineAdapter sem os buttons e com o layout item_discipline_spinner.xml que é o layout item_discipline.xml também sem os buttons:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="3dp">
<TextView
android:textSize="18sp"
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_weight="1" />
</LinearLayout>
Com isso terminamos a parte 3 dessa série no Android. O código completo do projeto pode ser acessado no GitHub: https://github.com/viniciusthiengo/realm-students
Na parte 4 vamos colocar esse form de inserção de estudante para funcionar.
Para acessar o site da library Realm: Documentação Realm Library Android
Segue vídeo de implementação dessa parte 3:
Vlw.
Comentários Facebook