Persistência de Dados Com Realm no Android - Parte 1

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Persistência de Dados Com Realm no Android - Parte 1

Persistência de Dados Com Realm no Android - Parte 1

Vinícius Thiengo
(11365) (15)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloManual de DevOps: como obter agilidade, confiabilidade e segurança em organizações tecnológicas
CategoriaEngenharia de Software
Autor(es)Gene Kim, Jez Humble, John Willis, Patrick Debois
EditoraAlta Books
Edição
Ano2018
Páginas464
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Opa, blz?

Nesse vídeo dou inicio a uma nova série no blog, dessa vez sobre persistência de dados, mais precisamente sobre a lib Realm (suporte a partir da API 9), que assume o papel de ser a mais eficiente maneira de persistência local no Android (comparando com o SQLite puro e libraries que utilizam o SQLite).

O Realm veio do IOS e já é utilizado em modo de produção desde 2012 por algumas APPs na AppStore. Para o Android ele está disponível desde 2014 com já algumas grandes APPs o utilizando. O uso é bem simples, porém fique atento quanto ao uso dos métodos setters quando utilizando um objeto recuperado da base Realm, pois não há cópia, os objetos têm acesso direto aos dados da base Realm (salva no disco em arquivos .realm) realizando assim uma atualização ao invés de uma simples alteração de dados como em um objeto Java convencional. Com o decorrer do post e vídeo ficará mais tranquilo de entender. Veja um comparativo de inserção de dados:

Note que o Realm é thread safety, ou seja, a atualização de dados na base Realm em uma Thread será refletida em todas as outras Threads (vinculadas ao Looper), caso a Thread não esteja vinculada ao Looper será necessário chamar o método refresh() para evitar o uso de dados antigos aumentando as chances de ter problemas de memory leak, por exemplo. Caso o problema de memory leak venha a acontecer e seja com isso utilizado um bloco try...catch para manter a APP funcionando, terá um grande risco de conrromper a base Realm e ai "a coisa fica preta", logo o recomendado pela documentação da library é terminar a APP nesse tipo de exception, OutOfMemoryException. 

Abaixo segue a primeira parte (post) de uma série. Aqui vamos trabalhar a inserção, atualização e remoção de disciplinas em nossa APP de Estudantes (RealmStudents). O primeiro passo é adicionar a library no gradle app level (Module: app) como abaixo: 

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.0'

compile 'io.realm:realm-android:0.84.1'
}

 

Note que aqui vou colocar as partes chaves de utilização da library nesse Android project, para acessar o projeto completo veja no GitHub (https://github.com/viniciusthiengo/realm-students). Segue imagem da estrutura do projeto:

 

O passo 2 é colocar nossa classe do domínio do problema com as configurações exatas para ser utilizada como parte integrante do Realm scheme: 

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Discipline extends RealmObject {
public static final String ID = "br.com.thiengo.realmstudents.domain.RealmObject.ID";

@PrimaryKey
private long id;
private String name;


public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name == null ? "" : name;
}

public void setName(String name) {
this.name = name;
}
}

 

Note que a constante configurada na classe Discipline será utilizada posteriormente para que seja possível enviar o id da disciplina que será atualizada na entidade de atualização da APP, via Intnent. O annotation @PrimaryKey é da library Realm e faz o que o nome diz, coloca o atributo abaixo como sendo o Primary Key na "tabela" / objeto de Discipline no Realm, implicitamente o atributo que é @PrimaryKey é também @Index (que permite uma busca mais rápida apesar de a inserção e atualização serem mais lentas) e @Required (que obriga a definição de valor, porém como está sendo utilizado em um tipo primitivo, esses já iniciam com um valor, exceto String que inicia como null). Ponto negativo a ser notado nessa parte é que a principio não é possível a utilização de algo equivalente ao AUTO_INCREMENT do SQL e também não é possível utilizar @primeryKey composta.

O passo 3 é acessar a base Realm em nossa MainActivity para que possamos colocar no button "Disciplinas" de nosso layout o número de disciplinas ativas. Vamos acessar também o método where() que vai permitir buscar os resultados de acordo com a classe definida como parâmetro (Discipline.class, em nosso exemplo) e com os condicionais setados (não utilizados ainda nessa Activity):

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import br.com.thiengo.realmstudents.domain.Discipline;
import io.realm.Realm;
import io.realm.RealmResults;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();

Button btDisciplines = (Button) findViewById(R.id.bt_disciplines);

Realm realm = Realm.getInstance(this);
RealmResults<Discipline> disciplines = realm.where(Discipline.class).findAll();

btDisciplines.setText( "Disciplinas ("+disciplines.size()+")" );
realm.close();
}



public void callDisciplines( View view){
Intent it = new Intent(this, DisciplinesActivity.class);
startActivity(it);
}


public void callStudents( View view){ }

}

 

Com isso conseguimos já lançar nossa APP de exemplo no emulador e consequentemente acessar o local onde o arquivo.realm foi criado e visualizar se o acesso as disciplinas para retornar o número total ocorreu ou não: 

 

Para acessar o local do arquivo.realm vá em Tools > Android > Android Device Monitor, depois na parte esquerda da box aberta clique no device que está utilizando no exemplo, então na parte direita, no top, clique na aba "File Explorer", no conteúdo apresentado abaixo siga o caminho data/data/nomeDoPackageDeSeuProject/files/ então terá acesso a algo similar ao apresentado na figura abaixo:

Segue o layout da MainActivity (activity_main.xml):

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="APP Realm Students"
android:textSize="18sp" />

<LinearLayout
android:layout_gravity="bottom"
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<Button
android:id="@+id/bt_disciplines"
android:text="Disciplinas"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:onClick="callDisciplines"/>

<Button
android:id="@+id/bt_students"
android:text="Estudantes"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:onClick="callStudents"/>

</LinearLayout>
</FrameLayout>

 

O passo 4 é configurarmos a Activity responsável por apresentar a lista de disciplinas já salvas em nossa base Realm. Vamos começar pelo layout que será utilizado na Activity DisciplinesActivity (activity_disciplines):

<?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="vertical">

<ListView
android:id="@+id/lv_disciplines"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:onClick="callAddDiscipline"
android:text="Add disciplina" />

</LinearLayout>

 

Abaixo segue a configuração de classe já com Realm sendo utilizado junto ao RealmResults e a ListView do layout:

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ListView;

import br.com.thiengo.realmstudents.adapter.DisciplineAdapter;
import br.com.thiengo.realmstudents.domain.Discipline;
import io.realm.Realm;
import io.realm.RealmChangeListener;
import io.realm.RealmResults;

public class DisciplinesActivity extends AppCompatActivity {

private Realm realm;
private RealmResults<Discipline> disciplines;
private RealmChangeListener realmChangeListener;
private ListView lvDisciplines;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_disciplines);

realm = Realm.getInstance(this);

realmChangeListener = new RealmChangeListener() {
@Override
public void onChange() {
((DisciplineAdapter) lvDisciplines.getAdapter()).notifyDataSetChanged();
}
};

realm.addChangeListener(realmChangeListener);
disciplines = realm.where( Discipline.class ).findAll();


lvDisciplines = (ListView) findViewById(R.id.lv_disciplines);
lvDisciplines.setAdapter( new DisciplineAdapter( this, disciplines, false ));
}


@Override
protected void onDestroy() {
realm.removeAllChangeListeners();
realm.close();
super.onDestroy();

}



public void callAddDiscipline( View view){
Intent it = new Intent( this, AddUpdateDisciplineActivity.class );
startActivity(it);
}
}

 

Note o method callAddDiscipline() setado para que seja possível acessar a Activity que permitirá novas disciplinas e note também o adapter DisciplineAdapter sendo setado junto ao ListView lvDisciplines, esse adapter é o nosso próximo passo, segue o código completo da classe DisciplineAdapter que extends RealmBaseAdapter<Discipline> e implementa a interface ListAdapter:

import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.TextView;

import br.com.thiengo.realmstudents.AddUpdateDisciplineActivity;
import br.com.thiengo.realmstudents.R;
import br.com.thiengo.realmstudents.domain.Discipline;
import io.realm.Realm;
import io.realm.RealmBaseAdapter;
import io.realm.RealmResults;

public class DisciplineAdapter extends RealmBaseAdapter<Discipline> implements ListAdapter {
public DisciplineAdapter( Context context, RealmResults<Discipline> realmResults, boolean automaticUpdate ){
super(context, realmResults, automaticUpdate);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
CustomViewHolder holder;

if( convertView == null ){
convertView = inflater.inflate(R.layout.item_discipline, parent, false);
holder = new CustomViewHolder();
convertView.setTag( holder );

holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
holder.btUpdate = (Button) convertView.findViewById(R.id.bt_update);
holder.btRemove = (Button) convertView.findViewById(R.id.bt_remove);
}
else{
holder = (CustomViewHolder) convertView.getTag();
}

final Discipline d = realmResults.get(position);
holder.tvName.setText( d.getName() );

holder.btUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent it = new Intent(context, AddUpdateDisciplineActivity.class);
it.putExtra(Discipline.ID, d.getId());
context.startActivity(it);
}
});

holder.btRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Realm realm = Realm.getInstance(context);
realm.beginTransaction();
d.removeFromRealm();
realm.commitTransaction();
realm.close();
}
});

return convertView;
}

private static class CustomViewHolder{
TextView tvName;
Button btUpdate;
Button btRemove;
}
}

 

O button btUpdate é apensa responsável por também chamar a Activity de AddUpdateDisciplineActivity, como o button Add de DisciplinesActivity, porém o button btRemove já realiza uma alteração na base Realm, logo temos de chamar o método que permite a remoção do dado entre a chamada do método beginTransaction() e commitTransaction(), caso contrário uma exception é gerada e nada é alterado.

Note que os objetos não são cópias de dados que foram recuperados da base Realm, na verdade são utilizados objetos de classes Realm proxies que sobrescrevem os métodos getters e setters e que permitem o acesso direto aos dados na base Realm, ou seja, os objetos Real em si são vazios, por isso eles são ainda mais leves que os objetos convencionais Java. A problemática pode morar no momento de utilizar um método set no decorrer do código, pois como o objeto proxy acessa e atualiza os dados diretamente na base Realm, o acesso aos métodos setters do objeto devem ser realizados entre as chamadas de métodos beginTransaction() e commitTransaction() (cancelTransaction() também pode ser utilizado caso for necessária essa ação), como no modo remover apresentado no código acima, caso isso não seja seguido uma IllegalStateException será gerada com a seguinte mensagem: Changing Realm data can only be done from inside a transaction.

Finalizado esse passo, o que devemos fazer agora é implementar a Activity que permite adicionar e atualizar disciplinas na APP, caso contrário não será possível visualizá-las.

No passo 5 segue implementação da Activity AddUpdateDisciplineActivity e layout activity_add_update_discipline.xml, começando por esse último:

<?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="Nova disciplina"
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" />

<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="callAddUpdateDiscipline"
android:text="Add" />

</RelativeLayout>

 

Segue código da Activity AddUpdateDisciplineActivity:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import br.com.thiengo.realmstudents.domain.Discipline;
import io.realm.Realm;
import io.realm.RealmResults;

public class AddUpdateDisciplineActivity extends AppCompatActivity {

private Realm realm;
private RealmResults<Discipline> disciplines;

private Discipline discipline;
private EditText etName;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_update_discipline);

discipline = new Discipline();
etName = (EditText) findViewById(R.id.et_name);
TextView tvTitle = (TextView) findViewById(R.id.tv_title);
Button btAddUpdate = (Button) findViewById(R.id.bt_add_update);


realm = Realm.getInstance(this);
disciplines = realm.where( Discipline.class ).findAll();

if( getIntent() != null && getIntent().getLongExtra( Discipline.ID, 0 ) > 0 ){
discipline.setId( getIntent().getLongExtra( Discipline.ID, 0 ) );

discipline = disciplines.where().equalTo("id", discipline.getId()).findAll().get(0);
etName.setText( discipline.getName() );
tvTitle.setText("Atualizar disciplina");
btAddUpdate.setText( "Update" );
}
}


public void callAddUpdateDiscipline( View view ){
String label = "atualizada";
if( discipline.getId() == 0 ){
disciplines.sort( "id", RealmResults.SORT_ORDER_DESCENDING );
long id = disciplines.size() == 0 ? 1 : disciplines.get(0).getId() + 1;
discipline.setId( id );
label = "adicionada";
}

try{
realm.beginTransaction();
discipline.setName(etName.getText().toString() );
realm.copyToRealmOrUpdate(discipline );
realm.commitTransaction();

Toast.makeText(AddUpdateDisciplineActivity.this, "Disciplina "+label, Toast.LENGTH_SHORT).show();
finish();
}
catch(Exception e){
e.printStackTrace();
Toast.makeText(AddUpdateDisciplineActivity.this, "Falhou!", Toast.LENGTH_SHORT).show();
}
}


@Override
protected void onDestroy() {
super.onDestroy();
}
}

 

No onCreate() temos além do acesso a instancias necessárias no contexto do código utilizado na Activity, a verificação do getIntent() para identificar se é uma atualização que está sendo acionada, quando o button btUpdate do DisciplineAdapter é acionado. Nesse script também já estamos utilizando uma forma de condicional para filtrar os dados que estão no conjunto disciplines, que foi preenchido pela busca similar a realizada na MainActivity (realm.where( Discipline.class ).findAll()). O método equalTo nos permite informa o campo / coluna no Realm scheme que queremos igualdade ao valor informado como segundo parâmetro. Dessa forma, no exemplo, vamos obter a disciplina correta no momento de atualização e assim já deixar o campo nome pré-preenchido.

Não coloquei no exemplo, mas o equalTo() pode ser utilizado com um terceiro parâmetro que indica se é para levar em consideração se caixa alta ou não, útil quando comparação com String. No caso utilizaria RealmQuery.CASE_INSENSITIVE para quando a caixa não tem importância e RealmQuery.CASE_SENSITIVE quando tem.

Note que o discipline.setName() já está sendo utilizado entre a chamada dos métodos beginTransaction() e commitTransaction(), isso porque caso seja um update, a variável de instancia discipline terá um objeto retornado da base Realm e não um criado no modelo convencional de objetos Java (new Discipline()), logo o set deve ser entre esses métodos de transaction, caso que não é necessário se for uma inserção de disciplina, pois o que temos é sim o RealmObject (Discipline extends ele), porém não acessando a base Realm, até porque ele ainda não foi inserido, por a necessidade então do método copyToRealmOrUpdate() que recebe como parâmetro um objeto que extends RealmObject e então verifica se já existe algum objeto com o mesmo primaryKey (em nosso exemplo é o campo id), caso sim esse objeto é atualizado na base Realm, caso contrário ele é inserido.

Anterior a inserção temos um script que é responsável por verificar se discipline tem ou não um id igual a 0, caso sim isso indica que devemos ordenar nossa lista de resultados (RealmResult) para que então possamos verificar se há algum item dentro da lista, se sim, colocamos o id desse item na posição 0 que tem o maior id da lista (devido a ordenação utilizada o de maior id é o primeiro da lista) somado a 1 na variável local id, se a lista está vazia, apenas colocamos 1 na variável local, pois é a primeira disciplina a ser inserida.

Inserindo a disciplina ou atualizando temos o feedback em um Toast, como nas figuras abaixo: 

Depois já é possível acessar disciplinas em DisciplinesActivity como apresentado abaixo e também utilizar as funcionalidades de remoção e update: 

Note que se adicionarmos algum outro atributo a classe Discipline, termos um problema de imcompatibilidade de schema no Realm, pois o Realm utiliza nossas entidades que extends RealmObject para construir e acessar o schema, se fizermos a alteração de adicionar o atributo grade (nota) na classe Discipline como abaixo:

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;


public class Discipline extends RealmObject {
public static final String ID = "br.com.thiengo.realmstudents.domain.RealmObject.ID";

@PrimaryKey
private long id;
private String name;
private double grade;


public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name == null ? "" : name;
}

public void setName(String name) {
this.name = name;
}

public double getGrade() {
return grade;
}

public void setGrade(double grade) {
this.grade = grade;
}
}

 

E tentarmos roda a APP, teremos uma RealmMigrationNeededException com a seguinte mensagem: RealmMigration must be provided. Que na verdade o que está dizendo é que ou nós provemos uma classe de migração de dados (explicada nos próximos posts) para que a base Realm seja reconstruída sem perder os dados já existentes, ou nós simplesmente deletamos a atual e criamos uma nova com o novo schema. Nesse primeiro post vamos optar pela versão mais simples que é deletar a base Realm existente e então criar uma nova.

Comece essa configuração criando o package "application" e então criando a classe CustomApplication com o seguinte código: 

import android.app.Application;

import io.realm.Realm;
import io.realm.RealmConfiguration;

public class CustomApplication extends Application {
@Override
public void onCreate() {
super.onCreate();

RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
.name("realm-students.realm")
.deleteRealmIfMigrationNeeded()
.build();

Realm.setDefaultConfiguration( realmConfiguration );
}
}

 

O que estamos fazendo é criando uma configuração personalizada e padrão para a utilização da base Realm em nossa APP. O método name é opcional, utilizei para deixar o arquivo.realm com o mesmo nome da APP e não default (esse persiste, pois quando colocamos um name distinto do anterior, o anterior não é sobrescrito e sim continua no diretório, caso seja necessário futuramente para acesso a mais de uma base Realm na APP, caso não seja, delete). O método deleteRealmIfMigrationNeeded() faz o que o nome indica, deleta a base Realm da configuração utilizada caso uma novo schema seja necessário, todos os dados salvos serão também deletados.

Depois da inserção do script acima no projeto é necessário atualizar a tag <application> no AndroidManifest.xml, colocando o atributo name para apontar para nossa CustomApplication: 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="br.com.thiengo.realmstudents">

<application
android:name=".application.CustomApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".DisciplinesActivity" />
<activity android:name=".AddUpdateDisciplineActivity"></activity>
</application>

</manifest>

 

Agora em todo o código do projeto, onde houver a chamada realm.getInstance(this) deverá ser trocada por realm.getDefaultInstance(). Caso isso não seja realizado o erro de inconsistência de schema será ainda printado.

Conclusão

Segundo o site do Realm ele é bem mais rápido que as outras alternativas, incluindo o SQLite no modo raw (sem utilização de libraries intermediárias), SharedPreferences não é considerado nessa comparação. Não fiz ainda teste de carga, mas a não utilização de uma grande quantidade de código para realizar um simples select ou insertion é a principio o grande diferencial, fora que não há necessidade de permissions e nem mesmo de uma configuração complexa, mesmo quando queremos fornecer nossa própria configuração. A documentação apesar de não disponível ainda em português está bem completa e concisa quanto aos exemplos disponibilizados no GitHub da library. A library ainda tem alguns pontos que estão sendo amadurecidos segundo a documanetação (Migração de dados, por exemplo), mas mesmo assim o custo / beneficio ainda achei bastante a favor do uso da library. Para quem está começando será ainda mais fácil trabalhar persistência local e para quem já conhece, vale o teste, pois tende a ser bem mais rápido e leve que as versões com SQLite.

Para complementar o conteúdo do vídeo, se ainda está no inicio do Android ou não conhece o BaseAdapter e a classe Application, veja os vídeos abaixo:

Utilizando BaseAdapter Para Personalização Completa da ListView

Application Class no Android, Entendendo e Utilizando

O projeto completo se encontra no Github: https://github.com/viniciusthiengo/realm-students

Segue site da library:

Realm para Android

Vlw. Segue vídeo de implementação.

 

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Injeção de Dependência Com a lib Dagger 2 no AndroidInjeção de Dependência Com a lib Dagger 2 no AndroidAndroid
Library Retrofit 2 no AndroidLibrary Retrofit 2 no AndroidAndroid
Sites, Canais e Blogs Gringos Para Estudar Desenvolvimento AndroidSites, Canais e Blogs Gringos Para Estudar Desenvolvimento AndroidAndroid
Sistema de Permissões em Tempo de Execução, Android MSistema de Permissões em Tempo de Execução, Android MAndroid

Compartilhar

Comentários Facebook

Comentários Blog (15)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
Tarcisio Cesar Mapa Santos (1) (0)
09/04/2018
Opa Thiengo, primeiramente gostaria de agradecer seus artigos, são claros, objetivos e auxiliam muito pra quem quer aprender mais. Uma pergunta, estou em dúvida entre Realm e Firebase, estou desenvolvendo uma aplicação com propósito apenas local de primeiro momento, porém futuramente poderá se compartilhar os conteudos entre contatos. Qual me indica à utilizar?
Responder
Vinícius Thiengo (1) (0)
13/04/2018
Tarcisio, tudo bem?

Para um aplicativo com persistência somente local, para este início: recomendo o Realm ou o SQLite.

Quando houver a necessidade de uma base compartilhada, recomendo o uso do Firebase caso seja evidente que o domínio do problema do aplicativo seja um que possa obter dezenas de milhares de usuários.

Sendo assim, com o Firebase você não teria de "quebrar a cabeça" tendo de trabalhar também com a escalabilidade do banco de dados: expansão horizontal ou vertical.

No caso do Firebase a preocupação seria somente com os pagamentos, mas isso você terá de fazer independente da base de dados remota que utilizar.

Se o domínio indicar que é improvável que o aplicativo chegue a ter milhares de acessos simultâneos, seguramente manteria o uso de uma base remota como o MySQL.

Ok, e sobre o Realm?

Entre o Realm remoto e o Firebase, fico com o Firebase. Mas recomendo que pergunte nos fóruns Android sobre o Realm remoto, pois eu ainda não o utilizei.

Abraço.
Responder
Tarcísio (1) (0)
15/04/2018
Blz, vou verificar sobre o Realm remoto para mais informações. Sobre o MySQL vc diz pra mim utilizar ele com uma API ou tem algo remoto também? Pergunto pois não conheço MySQL pra Android.
Responder
Vinícius Thiengo (0) (0)
15/04/2018
Tarcísio,

Isso, pois não há drivers de conexão direta com o MySQL, não de maneira nativa ao Android. No caso você utilizaria, por exemplo, uma API como o Retrofit que se conectaria com o backend Web.

Lá um algoritmo construído com linguagem a suporte Web (PHP, Python, Java, ?) obteria a requisição Android, buscaria / enviaria dados ao MySQL e assim retornaria a resposta ao Android.

Tenho um conteúdo completo onde há um aplicativo Android se comunicando com um backend Web em Apache, PHP e MySQL:

https://www.thiengo.com.br/fcm-android-dominio-do-problema-implementacao-e-testes-com-servidor-de-aplicativo-parte-1

Veja se lhe dá um suporte sobre como prosseguir com seu app caso não opte pelo Realm ou Firebase.

Abraço.
Responder
23/10/2017
Olá, Thiengo. Caso tivermos um banco Realm com algumas tabelas já populadas com as informações "padrões" necessárias e quisermos publicar o app, como aproveitar essas informações para os demais usuários, ou seja, os usuários já terem as tabelas populadas com as informações que temos localmente em um dispositivo?
Responder
Vinícius Thiengo (0) (0)
24/10/2017
Ricardo, tudo bem?

Há mais de uma maneira de conseguir isso. A seguir coloco o roteiro de um caminho comum com o SQLite:

- Crie uma classe que é responsável por ter todos os objetos que contém os dados que deverão ser colocados em base assim que o aplicativo é iniciado pela primeira vez;

- Crie a classe / algoritmo responsável por obter os objetos da classe anterior, inicializar a base de dados e colocar todos os dados iniciais nela;

- Utilize o SharedPreferences para saber se é ou não a primeira vez que o aplicativo é iniciado, ou seja, salve um flag boolean nele. Mais sobre o SharedPreferences no link a seguir: https://www.thiengo.com.br/sharedpreferences-no-android-entendendo-e-utilizando

Ricardo, seguindo este roteiro é possível sempre ter os dados iniciais na base Realm do app.

Abraço.
Responder
Luiz Paulo (1) (0)
23/11/2016
Thiengo, tive um problema

Segui o tutorial todo direitinho, o app rodou, consigo adicionar e remover disciplinas, e o problema ta ai, quando abro pela primeira vez e começo a adicionar as disciplinas ele vai normal, mas se, por exemplo, eu adiciono 6 elementos na lista e clico para remover o 2(ou qualquer outro que não seja o penultimo) o ultimo elemento da lista vai pra essa posição. Outro problema é que quando deleto e deixo apenas 2 elementos quando vou adicionar ele sempre substitui o segundo e não adiciona o terceiro. Você teria alguma ideia do por quê?
Responder
Vinícius Thiengo (0) (0)
25/11/2016
Luiz Paulo, tudo bem?

Tentou rodando a APP de exemplo que está no GitHub para saber se ela apresenta os mesmo problemas de lógica?

GitHub: https://github.com/viniciusthiengo/realm-students

Pode ser que tenha esquecido algo em seu código? ou encontrou um belo bug no projeto. Somente não me recordo se corrigi nos vídeos posteriores na série.

Se possível, os acompanhe e veja se já foram corrigidos, pois esse é um problema que deveria ser notado logo, e somente foi reportado agora.

Link série: https://www.youtube.com/playlist?list=PLBA57K2L2RIJz9eAlODBynIfWQgckZaXc

Abraço.
Responder
29/11/2015
Thiengo boa tarde , parabéns pela aula , alterei todo meu projeto de sqlite para realm , realmente não se compara a velocidade , tinha processos meu que levada 12 a 13 segundos, hoje no máximo 1,5 segundos .
Parabéns
Responder
Vinícius Thiengo (1) (0)
29/11/2015
É show de bola mesmo Fabio, ainda não testei com uma massa de dados, mas vc acaba sendo parte da prova de que ele é realmente mais eficiente. Abraço
Responder
29/11/2015
Realmente não se compara , a diferença é tão absurda que até mesmo desconfiei que algo teria acontecido no background.

Aproveitando você vai mostrar como fazer alguma parte de backup e restauração do arquivo .realm ?
Responder
Vinícius Thiengo (1) (0)
30/11/2015
Esse de backup não tinha pensado ainda, vou ver se estendo a série um pouco mais. Abraço
Responder
06/11/2015
E ae Thiengo, tudo em paz?
Estou alterando um projeto que tenho onde um dos grandes problemas é justamente a demora na inserção de muitos dados na mesma chamada. Assim que terminar eu retorno com os resultados.

Estou aguardando a continuação da série ta bem bacana. Parabéns pelos vídeos.
Responder
plinhares9 (3) (0)
03/11/2015
Thiengo, isso é uma alternativa ao SqLite ou os dois trabalham juntos ? Tem alguma grande vantagem de se  utilizar essa lib ?
Responder
Vinícius Thiengo (3) (0)
03/11/2015
Fala plinhares9, blz?
Na verdade é uma alternativa, a principio tb imaginei que utilizava o SQLite no background, como o SugarORM, por exemplo, mas não, ele tem o próprio modelo de persistência, e como apresentado na documentação da library a grande vantagem fica na velocidade. Eu já tive problemas com o SQlite quando com milhares de dados a serem persistidos em uma única chamada. Nos comentários / twittes do @realm, vi um que me surpreendeu (apesar de eu ainda não ter testado a vera com muitos dados) que foi sobre o developer ter diminuido a consulta / inserção de 7 segundos com o SQLite para 0.5 segundos com o Realm... crazy awesome! A outras vantagem é a facilidade de uso com métodos simples e autocomentados (o nome diz o que são / fazem). Abraço
Responder