Iniciando Base Realm Com Dados JSON - Parte 7

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 /Iniciando Base Realm Com Dados JSON - Parte 7

Iniciando Base Realm Com Dados JSON - Parte 7

Vinícius Thiengo
(3285) (14)
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ítuloCraftsmanship Limpo: Disciplinas, Padrões e ética
CategoriaDesenvolvimento Web
Autor(es)Robert C. Martin
EditoraAlta Books
Edição
Ano2023
Páginas416
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 7 da série Persistência de Dados com Realm Library no Android é apresentada uma maneira de já iniciar a base Realm com dados vindos de um arquivo JSON. Procedimento comum quando temos uma base de dados remota onde alguns dados que não sofrem atualizações com frequencia são necessários também na base local, estados e cidades de um país, por exemplo.

Na aplicação de exemplo temos um mini projeto PHP que somente tem nossa base de dados rodando com MySQL e os arquivos JSON das tabelas gerados pela IDE utilizada, PHPStorm.

O primeiro passo é visualizar como está o mapeamento objeto-relacional, as tabelas de nossa base de dados remota (no servidor Web):

Note que a tabela rs_grade tem um relacionamento forte com as tabelas rs_student e rs_discipline, logo não há registro em rs_grade sem sem ter um student e uma discipline vinculados a ele. Essa é também a lógica utilizada na APP Java API, porém por causa dessa mapemento objeto-relacional teremos de realizar algumas modificações no arquivo JSON de students.json.

O próxima passo é gerar os arquivos JSON das tabelas de nossa base remota, abaixo segue os dados JSON de rs_address e rs_discipline:

address.json

[{
"id": 1,
"street": "Rosalinas",
"neighborhood": "Eldorado",
"city": "Serra",
"state": "Espírito Santo",
"country": "Brasil"
},
{
"id": 2,
"street": "Tartálias",
"neighborhood": "Sebastião",
"city": "Vitória",
"state": "Espírito Santo",
"country": "Brasil"
},
{
"id": 3,
"street": "Bem-te-vis",
"neighborhood": "José Alves",
"city": "São Paulo",
"state": "São Paulo",
"country": "Brasil"
},
{
"id": 4,
"street": "Quadras Uno",
"neighborhood": "Tuliverdes",
"city": "Rio de Janeiro",
"state": "Rio de Janeiro",
"country": "Brasil"
},
{
"id": 5,
"street": "Moconhas",
"neighborhood": "Itaparica",
"city": "Vila Velha",
"state": "Espírito Santo",
"country": "Brasil"
},
{
"id": 6,
"street": "Sexta-quinta",
"neighborhood": "Rosangela",
"city": "Cariacica",
"state": "Espírito Santo",
"country": "Brasil"
},
{
"id": 7,
"street": "Carajós",
"neighborhood": "Tulipas",
"city": "Ipatinga",
"state": "Minas Gerais",
"country": "Brasil"
},
{
"id": 8,
"street": "Sizenando",
"neighborhood": "Laranjeiras",
"city": "Serra",
"state": "Espírito Santo",
"country": "Brasil"
}
]

 

discipline.json

[{
"id": 1,
"name": "Mathmatics"
},
{
"id": 2,
"name": "History"
},
{
"id": 3,
"name": "Science"
},
{
"id": 4,
"name": "Biomedical Engineering"
},
{
"id": 5,
"name": "Statistics"
},
{
"id": 6,
"name": "Business"
},
{
"id": 7,
"name": "Chemistry"
},
{
"id": 8,
"name": "Art"
},
{
"id": 9,
"name": "Biology"
},
{
"id": 10,
"name": "Anthropology"
}
]

 

No arquivo a seguir foi necessário incluir novamente os dados de rs_discipline, isso para no Android poder manter as relações corretas entre Student, Grade e Discipline. Veja também que cada grade está vinculada já a seu respectivo Student, novamente para não termos problemas com as composições no Java API no Android, segue students.json:

[{
"id": 1,
"name": "Jorge Vasconcelos",
"email": null,
"grades": [{
"id": 5,
"grade": 55,
"discipline": {
"id": 9,
"name": "Biology"
}
},
{
"id": 9,
"grade": 99,
"discipline": {
"id": 7,
"name": "Chemistry"
}
}]
},
{
"id": 2,
"name": "Juliana Cunha",
"email": null,
"grades": [{
"id": 3,
"grade": 91,
"discipline": {
"id": 5,
"name": "Statistics"
}
},
{
"id": 10,
"grade": 65,
"discipline": {
"id": 3,
"name": "Science"
}
}]
},
{
"id": 3,
"name": "Fernanda Oliveira",
"email": null,
"grades": [{
"id": 1,
"grade": 89,
"discipline": {
"id": 2,
"name": "History"
}
}]
},
{
"id": 4,
"name": "Carlos Alves",
"email": null,
"grades": [{
"id": 4,
"grade": 90,
"discipline": {
"id": 10,
"name": "Anthropology"
}
}]
},
{
"id": 5,
"name": "Adriana Solimões",
"email": null,
"grades": [{
"id": 7,
"grade": 100,
"discipline": {
"id": 6,
"name": "Business"
}
}]
},
{
"id": 6,
"name": "Kelly Sózer",
"email": null,
"grades": [{
"id": 8,
"grade": 97.5,
"discipline": {
"id": 8,
"name": "Art"
}
}]
},
{
"id": 7,
"name": "Rodney Silva",
"email": null,
"grades": [{
"id": 6,
"grade": 69.5,
"discipline": {
"id": 4,
"name": "Biomedical Engineering"
}
}]
},
{
"id": 8,
"name": "Muhammed Salim",
"email": null,
"grades": [{
"id": 2,
"grade": 67.5,
"discipline": {
"id": 1,
"name": "Mathmatics"
}
}]
}
]

 

Agora já no projeto Android no AndroidStudio temos de criar o assets folder, como no vídeo, altere o modo de visualização da hierarquia do projeto para utilizar o modo "Project" ao invés de "Android". Veja a figura abaixo:

Logo depois vá em: app > src > main. Então com o botão direito do mause clique em main e clique em "New directory", coloque "assets" e ok.

Agora crie dentro do folder assets três arquivos: address.json, disciplines.json e students.json

Copie os conteúdos desses arquivos apresentados anteriormente e cole nesses novos arquivos do folder assets, cada um em seu respectivo arquivo JSON.

Voltando a hierarquia de projeto ao modo "Android" teremos o folder assets como a figura abaixo:

O próximo passo é criar o método init() na MainActivity para que seja possível iniciar a base Realm com os dados dos arquivos JSON logo na primeira entrada do user a APP. Segue código do método:

...
private void init( Realm realm ){
SharedPreferences sp = getPreferences(MODE_PRIVATE);

if( sp.getInt("flag", 0) == 0 ){
Log.i("LOG", "init()");
sp.edit().putInt("flag", 1).apply();

try{
AssetManager assetManager = getAssets();
InputStream is = null;

realm.beginTransaction();

/* DISCIPLINES */
is = assetManager.open("disciplines.json");
realm.createOrUpdateAllFromJson(Discipline.class, is);

/* ADDRESS */
is = assetManager.open("address.json");
realm.createAllFromJson( Address.class, is );

/* STUDENTS */
is = assetManager.open("students.json");
realm.createOrUpdateAllFromJson( Student.class, is );

realm.commitTransaction();

}
catch( Exception e ){
e.printStackTrace();
realm.cancelTransaction();
}
}
else{
RealmResults<Student> students = realm.where(Student.class).findAll();
for( Student s : students ){
Address a = realm.where(Address.class).equalTo("id", s.getId()).findFirst();
Log.i("LOG", "Student: "+s.getName());
Log.i("LOG", "Street: "+a.getStreet());
}
}
}
...

 

Note que no código acima foi necessária utilização do SharedPreferences para ser possível verificar se foi ou não a primeira vez que a APP foi aberta pelo user, caso sim (igual a 0) o script da continuidade com a abertura dos arquivos dentro do assets folder e então preenchendo a base Real.

A variavel assetsManager do tipo AssetsManager vai permitir o acesso aos arquivos .json, a variavel is do tipo InputStream vai permitir setar o conteúdo no Realm.

A utilização do método createOrUpdateAllFromJson() é necessária somente para as entidades que têm o annotation @PrimaryKey setado (nesse exemplo), pois caso não tenha o @PrimaryKey o update não é permitido (problema não detectado a tempo no vídeo anterior), logo no caso de Address temos de utilizar createAllFromJson().

No caso de não ser mais a primeira vez que a APP é aberta, então o script apresenta o nome do Student e o nome da rua do endereço dele.

Para chamar o método init() vamos ao onCreate() da MainActivity e logo abaixo da linha que inicializa o Realm colocaremos essa chamada a init(), segue código:

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

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

Realm realm = Realm.getDefaultInstance();
init( realm );

...

 

 O projeto completo pode ser acessado no GitHub: https://github.com/viniciusthiengo/realm-students

Segue vídeo de implementação da parte 7 da série:

Vlw.

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

Persistência de Dados Com Realm no Android - Parte 3Persistência de Dados Com Realm no Android - Parte 3Android
Persistência de Dados Com Realm no Android - Parte 4Persistência de Dados Com Realm no Android - Parte 4Android
Persistência de Dados Com Realm no Android - Parte 5Persistência de Dados Com Realm no Android - Parte 5Android
Migração de Dados. Realm Library no Android - Parte 6Migração de Dados. Realm Library no Android - Parte 6Android

Compartilhar

Comentários Facebook

Comentários Blog (14)

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...
08/01/2016
Bom dia.
Gostaria de saber como criar um aplicativo que sincroniza com banco de dados remoto, ou rest, pois até agora o unico banco que faz isso é o couchbase, gostaria de ter um app com dados offline.
Obrigado
Responder
Vinícius Thiengo (0) (0)
09/01/2016
Fala Ricardo, blz?
O que terá de fazer é utilizar uma base local como o SQLite ou Realm e utilizar uma library de conexão remota para manter enviando e obtendo dados de sua base remota. A library que indico é o Retrofit 2.0 (http://www.thiengo.com.br/library-retrofit-2-no-android ).

Pode utilizar em apoio um script de push message (http://www.thiengo.com.br/gcm-downstream-messages-push-message-android-parte-1 ), dessa forma sempre que houver conteúdo novo no server, seu servidor pode informar as APPs por meio de push message e então é iniciado a sincronização no background. Abraço
Responder
11/01/2016
Obrigado pela resposta. Porém gostaria de tirar um duvida. Quando eu uso o retrofit ele baixa só conteúdo novo ou baixa por completo novamente. Porque supomos que o conteúdo é grande gostaria que baixa-se  somente conteúdos novos para economizar dados.
Responder
Vinícius Thiengo (0) (0)
11/01/2016
Fala Ricardo, blz?
Isso é lógica de programação, suas chamadas via Retrofit apenas enviam dados para poder filtrar quais dados serão retornados.

Ex. : Em sua primeira requisição, como ainda não havia nenhum item em sua lista, o Retrofit envio como parâmetro para seu servidor um dado de nome "id" com valor igual a "0". Porém na segunda requisição (quando o user rolou a lista para cima) seu script no Android obteve o id do ultimo item apresentado em sua lista em então o Retrofit fez a requisição enviando esse id como parâmetro de entrada no servidor (linguagem backend com base de dados). Na base de dados, se esse valor for diferente de 0 seu script deve retornar somente os itens de id menor que o enviado. Assim vc somente carrega os que ainda não foram carregados no Android. Para pegar os mais atuais é somente inverter para obter os ids maiores que o id do primeiro item na lista no Android. Abraço
Responder
05/01/2016
Muito bom seu tutorial. porem gostaria de pedir um tutorial com a explicação de como faço para aumentar a capacidade ou habilitar a permissão do Android para aqueles app robustos, ou que ocupam muita memória. Ou se puder me auxiliar meu app sempre estoura a memória em alguns dispositivos quando recebo um XML.
Responder
Vinícius Thiengo (1) (0)
05/01/2016
Fala Augusto, blz?
Na verdade, se me lembro bem, a liberação é para quando sua APP tem mais que 50MB e está sendo disponibilizada na PlayStore.

Nesse contexto vc developer tem de criar algumas assinaturas de conteúdo externo para então assim que o user baixar sua APP, o próprio código da APP inicia o download do conteúdo excedente.

Em seu caso o problema de vazamento de memória deve ser contornado pelo developer, ainda não consumi nenhum conteúdo que permite liberar a APP em utilizar mais memória que o próprio Android permite por APP em foreground / background.

Como citou "recebo", estou assumindo que depois de baixar um conteúdo grande (em bytes) a APP cai no conhecido memory leak ou OutOfMemmoryException.

Nesse contexto recomendo que utilize uma library que lhe permita já ir consumindo os dados que estão sendo baixados e então ir colocando os mesmo em uma base local, fora da memória, Realm, por exemplo. Dê uma olhada nesse conteúdo (http://www.donnfelker.com/hi-performance-json-parsing-in-android/?utm_source=Android+Weekly&utm_campaign=12e9466a17-Android_Weekly_185&utm_medium=email&utm_term=0_4eb677ad19-12e9466a17-337895073 ).

Outra maneira é tentar mudar para json ao invés de xml, pois o parse xml é mais pesado que o do json. Outra é dividir essa única chamada para um grande arquivo e várias chamadas menores que irão trazer partes desse arquivo maior. Abraço
Responder
06/01/2016
Vlw Obrigadão pelas dicas.
Responder
Johnathan (1) (0)
30/11/2015
Olá Thiengo você sabe se existe alguma lib relacionada a vedas
Responder
Vinícius Thiengo (0) (0)
30/11/2015
Johnathan,
API de vendas, conheço algumas que trabalham com pagamentos, dê uma olhada nessa busca no Android Arsenal (https://android-arsenal.com/search?q=sell ).

Veja tb as opções de API de vendas no Google nesse link (https://developers.google.com/products/ ), clique em "Payments". Abraço
Responder
Alessandro (2) (0)
25/11/2015
Excelente tutorial.

Lembro que tu comento nos primeiro vídeos desta série sobre sobre o RecyclerView. Achei nas notícias do Realm esse tutorial. https://realm.io/news/android-recycler-view/

Obrigado e continue um excelente trabalho
Responder
Alessandro (1) (0)
26/11/2015
Bom dia. Tu sabe me dizer se pretendem adicionar um adapter do recyclerview, pois essa lib que mandei não funciona como esperado.

Obrigado
Att
Responder
Vinícius Thiengo (0) (0)
26/11/2015
Alessandro, estou sem essa informação, mas diga, qual foi o problema?
Responder
Alessandro (1) (0)
26/11/2015
Opa, eu estou usando essa lib https://github.com/florent37/MaterialViewPager , porem ela só funciona com o RecyclerView (no próprio github da lib fala que foi removido o suporte a listview na versão 1.0.4). Também não consegui fazer funcionar corretamente com o primeiro link que te mandei.

Entrei em contato com os desenvolvedores do Realm, e eles vão adicionar suporte ao RecyclerView.

RETORNO DELES "Yes, it is definitely something we want to add, but we are waiting for fine-grained notifications #989 to be completed before we can add the proper functionality. It is also being tracked here #972 , so i'll close this as an duplicate."


Obrigado pela atenção
Responder
Vinícius Thiengo (0) (0)
26/11/2015
Vamos aguardar então.
Responder