API de Endereços Para Pré-Cadastro em APPs Android - Parte 2

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog. Você receberá um email de confirmação. Somente depois de confirma-lo é que poderei lhe enviar os conteúdos exclusivos.

Email inválido.
Blog /Android /API de Endereços Para Pré-Cadastro em APPs Android - Parte 2

API de Endereços Para Pré-Cadastro em APPs Android - Parte 2

Vinícius Thiengo03/01/2017
(1149) (6) (58) (15)
Go-ahead
"Na falta de um foco externo, a mente se volta para dentro de si mesma e cria problemas para resolver, mesmo que os problemas são indefinidos ou sem importância. Se você encontrar um foco, uma meta ambiciosa que parece impossível e força-o a crescer, essas dúvidas desaparecem."
Tim Ferriss
Treinamento Oficial
Android: Prototipagem Profissional de Aplicativos
Black Week
CursoAndroid: Prototipagem Profissional de Aplicativos
CategoriaAndroid
InstrutorVinícius Thiengo
NívelTodos os níveis
Vídeo aulas+ 124
PlataformaUdemy
Acessar Curso
Receitas Android
Capa do livro Receitas Para Desenvolvedores Android
TítuloReceitas Para Desenvolvedores Android
CategoriaDesenvolvimento Android
AutorVinícius Thiengo
Edição
Ano2017
Capítulos20
Páginas934
Acessar Livro
Código Limpo
Capa do livro Refatorando Para Programas Limpos
TítuloRefatorando Para Programas Limpos
CategoriaEngenharia de Software
AutorVinícius Thiengo
Edição
Ano2017
Capítulos46
Páginas598
Acessar Livro
Conteúdo Exclusivo
Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Opa, blz?

Neste artigo damos continuidade a série de dois conteúdos sobre API de endereços no Android, mais precisamente, a API ViaCEP.

É necessário que você já tenha consumido o primeiro artigo da série, artigo também com vídeo. Caso ainda não, acesse ele pelo link a seguir: API de Endereços Para Pré-Cadastro em APPs Android - Parte 1.

A parte um da série tem a discussão sobre a importância de trabalhar bem os formulários no Android, além de algumas outras explicações necessárias para a necessidade de uma API de endereços para pré-cadastro de dados.

Aqui vamos implementar o trecho, do aplicativo de Makertplace, que permite ao usuário buscar o CEP ao invés de somente buscar o endereço utilizando o CEP.

Abaixo os tópicos que serão abordados:

API de endereços com busca por CEPs

A API de endereços que estamos utilizando trabalha também com busca de CEP. O usuário informar a rua, cidade e estado e então uma lista de endereços, incluindo o CEP de cada um, é retornada.

No caso da API do ViaCEP, é retornado no máximo 100 endereços. Veja o exemplo a seguir:

Simples busca por CEPs na API do ViaCEP

[
{
"cep": "29166-767",
"logradouro": "Rua dos Bem-te-vis",
"complemento": "",
"bairro": "Morada de Laranjeiras",
"localidade": "Serra",
"uf": "ES",
"unidade": "",
"ibge": "3205002",
"gia": ""
},
{
"cep": "29168-590",
"logradouro": "Rua dos Bem-te-vis",
"complemento": "",
"bairro": "Porto Canoa",
"localidade": "Serra",
"uf": "ES",
"unidade": "",
"ibge": "3205002",
"gia": ""
},
{
"cep": "29173-517",
"logradouro": "Rua dos Bem-te-vis",
"complemento": "",
"bairro": "Costa Bela",
"localidade": "Serra",
"uf": "ES",
"unidade": "",
"ibge": "3205002",
"gia": ""
}
]

Com zero ou mais endereços, sempre é retornado um array JSON. O que a API não informa é sobre como é feita a ordenação dos endereços. Algo como: o mais relevante primeiro, por exemplo. Esta "não informação" fica como o ponto negativo da documentação dela.

De qualquer forma, apenas precisamos apresentar lista de endereços ao usuário e deixar com que ele escolha o correto.

Projeto de exemplo - Android

Nesta parte dois o conteúdo do artigo tende a ser bem mais enxuto que a parte um. Isso, pois apenas estaremos finalizando a lógica de busca de endereço com a API do ViaCEP, a parte "verbosa" já foi apresentada no artigo um da série.

Ao final deste artigo vamos ter uma nova Activity com o layout similar ao apresentado a abaixo:

Assim podemos prosseguir com as adições e atualizações ao projeto.

Acrescentando classes de negócio no domínio do problema

Vamos precisar adicionar algumas novas classes ao domínio do problema. Classes de negócio referentes as seguintes necessidades:

  • Adaptador e gerenciador de itens de uma lista;
  • Busca remota da lista de CEPs de acordo com os dados de endereço fornecidos em formulário.

Para o primeiro item, vale informar que estaremos trabalhando com um ListView, pois a implementação é mais simples que a de um RecyclerView, além de atender bem aos nossos requisitos neste projeto de exemplo.

Vamos recapitular o resultado de uma consulta por CEPs a API do ViaCEP:

[
{
"cep": "29166-767",
"logradouro": "Rua dos Bem-te-vis",
"complemento": "",
"bairro": "Morada de Laranjeiras",
"localidade": "Serra",
"uf": "ES",
"unidade": "",
"ibge": "3205002",
"gia": ""
}
]

 

Em nosso domínio do problema o usuário terá de entrar com os dados de: rua, cidade e estado. Sabendo disso e tendo em mente que sempre é retornada um array JSON, mesmo que vazio. Podemos assim definir um layout personalizado para os itens da lista, itens que serão, na verdade, os endereços retornados.

Note que não precisamos apresentar os dados de cidade e estado no layout de item. Isso, pois o usuário já terá de fornece-los.

Quanto a rua, vamos sim manter no layout dos itens, pois pode ser que o nome da rua não tenha sido fornecido corretamente e a API tenha retornado um resultado com os nomes possíveis ao nome informado.

Segundo alguns testes realizados, o campo complemento do JSON retornado nunca teve algum valor. Logo, podemos optar pelos seguintes dados no layout de item: cep, rua e bairro.

Assim temos um layout com a seguinte estrutura:

O XML deste logo abaixo, address_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00684c"
android:paddingEnd="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingStart="5dp">

<TextView
android:id="@+id/tv_zip_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:maxLines="1"
android:padding="2dp"
android:textSize="18sp" />

<TextView
android:id="@+id/tv_street"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/tv_zip_code"
android:ellipsize="end"
android:maxLines="1"
android:padding="3dp"
android:textSize="16sp" />

<TextView
android:id="@+id/tv_neighbor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/tv_street"
android:ellipsize="end"
android:maxLines="1"
android:padding="3dp"
android:textSize="16sp" />
</RelativeLayout>

 

Assim podemos partir para a construção do adapter que será utilizado pelo ListView do layout da Activity ZipCodeSearchActivity.

Vamos nomear o adapter de AddressAdapter. Segue apresentação das partes deste adapter.

Primeiro o código comum a adapters de lista, inicialização de atributos e métodos obrigatórios:

public class AddressAdapter extends BaseAdapter {
private List<Address> addresses;
private LayoutInflater inflater;

public AddressAdapter(Context context, List<Address> addresses){
inflater = LayoutInflater.from(context);
this.addresses = addresses;
}

@Override
public int getCount() {
return addresses.size();
}

@Override
public Object getItem(int i) {
return addresses.get( i );
}

@Override
public long getItemId(int i) {
return i;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
...
}
...
}

 

Simples, certo? Caso ainda não conheça o BaseAdapter, logo depois de terminar este artigo, parte dois, acesse o artigo, também com vídeo, que tem aqui no Blog sobre esta classe: Utilizando BaseAdapter Para Personalização Completa da ListView.

E assim o código restante de AddressAdapter, mais precisamente, o código de getView() e a classe interna que nos permite a aplicação do padrão ViewHolder. Segue:

public class AddressAdapter extends BaseAdapter {
...

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;

if( view == null ){
view = inflater.inflate(R.layout.address_item, null);
holder = new ViewHolder();
view.setTag( holder );
holder.setViews( view );
}
else{
holder = (ViewHolder) view.getTag();
}
holder.setData( addresses.get( i ) );

return view;
}

private static class ViewHolder{
TextView tvZipCode;
TextView tvStreet;
TextView tvNeighbor;

void setViews( View view ){
tvZipCode = (TextView) view.findViewById(R.id.tv_zip_code);
tvStreet = (TextView) view.findViewById(R.id.tv_street);
tvNeighbor = (TextView) view.findViewById(R.id.tv_neighbor);
}

void setData( Address address ){
tvZipCode.setText( "CEP: "+address.getCep() );
tvZipCode.setTag( address.getCep() );
tvStreet.setText( "Rua: "+address.getLogradouro() );
tvNeighbor.setText( "Bairro: "+address.getBairro() );
}
}
}

 

Veja em ViewHolder que, para amenizar a codificação em getView(), adicionamos alguns métodos de preenchimento a ela.

Assim terminamos com a classe que responde a primeira necessidade apontada logo no início desta seção.

Nossa segunda tarefa é construir a classe que permitirá a conexão com o servidor da API ViaCEP e também o processamento da resposta desta API. Isso para que seja possível a colocação dos itens no ListView da Activity ZipCodeSearchActivity.

Assim, segue código de ZipCodeRequest (o nome autocomentado, equivalente ao que é requisitado):

public class ZipCodeRequest extends AsyncTask<Void, Void, Void> {
private WeakReference<ZipCodeSearchActivity> activity;

public ZipCodeRequest( ZipCodeSearchActivity activity ){
this.activity = new WeakReference<>( activity );
}

@Override
protected void onPreExecute() {
super.onPreExecute();
activity.get().lockFields( true );
}

@Override
protected Void doInBackground(Void... voids) {

try{
String jsonString = JsonRequest.request( activity.get().getUriRequest() );

JSONArray jsonArray = new JSONArray(jsonString);
Gson gson = new Gson();
activity.get().getAddresses().clear(); /* PARA REAPROVEITAR O OBJETO DE LISTA */

for( int i = 0; i < jsonArray.length(); i++ ){
JSONObject jsonObject = jsonArray.getJSONObject(i);
activity.get().getAddresses().add( gson.fromJson(jsonObject.toString(), Address.class) );
}
}
catch (Exception e){
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Void data) {
super.onPostExecute(data);

if( activity.get() != null ){
activity.get().lockFields( false );
activity.get().updateListView();
}
}
}

 

Primeiro, o código é muito similar ao da classe AddressRequest, apresentada na parte um da série. Segundo, o WeakReference continua sendo utilizado, isso, pois como AddressRequest, ZipCodeRequest também tem um ciclo de vida diferente do da Activity que acionará ele, a ZipCodeSearchActivity.

E terceiro. Bom, para o terceiro vamos recapitular o código Gson sendo utilizado:

...
String jsonString = JsonRequest.request( activity.get().getUriRequest() );

JSONArray jsonArray = new JSONArray(jsonString);
Gson gson = new Gson();
activity.get().getAddresses().clear(); /* PARA REAPROVEITAR O OBJETO DE LISTA */

for( int i = 0; i < jsonArray.length(); i++ ){
JSONObject jsonObject = jsonArray.getJSONObject(i);
activity.get().getAddresses().add( gson.fromJson(jsonObject.toString(), Address.class) );
}
...

 

Note que como desta vez temos como retorno um array JSON, precisamos trabalhar primeiro o array como um simples array JSON para então utilizarmos verdadeiramente o Gson para realizar o parser.

A library Gson tem uma maneira de trabalhar também com lista de dados, assim o uso do JSONArray seria dispensável. Porém, em nosso caso, o código é simples o suficiente para não optarmos pela versão de lista desta library.

Seguindo o conteúdo, mais precisamente o conteúdo da Activity ZipCodeSearchActivity, você entenderá a importância da invocação activity.get().getAddresses().clear().

Já lhe adianto: este clear() vai nos permitir aliviar o peso na memória do device evitando que tenhamos de criar um novo objeto de lista. O clear() faz parte da lógica que vai nos ajudar a ter este ganho em reutilização de recursos.

Com isso terminamos com as novas classes de domínio do problema. Vamos prosseguir, pois ainda falta a nova Activity, ZipCodeSearchActivity, e a atualização de algumas classes criadas na parte um da série.

Só um minuto. ZipCodeSearchActivity não faz parte do domínio do problema, digo, classes de negócio?

Sim, faz parte, alias é a classe que mais tem lógica de negócio, mas como se trata de uma Activity, um componente Android, que tem muito mais responsabilidades do que somente lógica de negócio do sistema, preferi coloca-la em uma seção separada.

Construindo a ZipCodeSearchActivity, Activity de busca por CEP

Nosso primeiro passo aqui é definir o layout da Activity. Esta terá de permitir o usuário entrar com os dados: rua, cidade e estado. E, obviamente, permitir o clique em um botão para invocar a busca.

Também será necessária a estrutura para apresentação dos itens, isso no mesmo layout que terá o formulário de busca.

Vamos reaproveitar parte do layout da SignUpActivity, mais precisamente, parte do formulário. Assim teremos um layout com a seguinte arquitetura:

Uma correção na figura anterior: no lugar de Button, na verdade é TextView. Mas você pode utilizar, sem problema algum, um Button.

A figura acima facilita o entendimento do XML que será apresentado a seguir, o XML do arquivo de layout activity_zip_code_search.xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context="br.com.thiengo.marketplaceapp.ZipCodeSearchActivity">

<RelativeLayout
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">

<TextView
android:id="@+id/sub_title_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="#005740"
android:gravity="center"
android:padding="6dp"
android:text="Busca CEP"
android:textColor="#f9f9f9"
android:textSize="20sp" />

<LinearLayout
android:id="@+id/ll_fieldset_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/sub_title_1"
android:layout_marginTop="10dp"
android:orientation="horizontal">

<android.support.design.widget.TextInputLayout
android:id="@+id/til_city"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">

<EditText
android:id="@+id/et_city"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ems="10"
android:hint="*Cidade"
android:inputType="text" />
</android.support.design.widget.TextInputLayout>

<Spinner
android:id="@+id/sp_state"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>

<LinearLayout
android:id="@+id/ll_fieldset_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/ll_fieldset_1"
android:layout_marginTop="10dp"
android:orientation="horizontal">

<android.support.design.widget.TextInputLayout
android:id="@+id/til_street"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7">

<EditText
android:id="@+id/et_street"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ems="10"
android:hint="*Rua"
android:inputType="text" />
</android.support.design.widget.TextInputLayout>

<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:background="#005740"
android:gravity="center"
android:onClick="searchAddress"
android:padding="6dp"
android:text="Buscar"
android:textColor="#f9f9f9"
android:textSize="20sp" />
</LinearLayout>

<TextView
android:id="@+id/sub_title_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_fieldset_2"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="#005740"
android:gravity="center"
android:padding="6dp"
android:text="Resultado (endereços)"
android:textColor="#f9f9f9"
android:textSize="20sp" />

<ListView
android:id="@+id/lv_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/sub_title_2"
android:layout_marginTop="10dp" />

</RelativeLayout>
</ScrollView>

 

Com a estrutura de layout anterior, teremos como resultado uma visualização como a figura a seguir:

Assim podemos prosseguir com o código de ZipCodeSearchActivity. Como com outras classes grandes apresentadas nesta série, também vamos em partes.

Primeiro a inicialização dos atributos:

public class ZipCodeSearchActivity extends AppCompatActivity
implements AdapterView.OnItemClickListener {
private Spinner spStates;
private ListView lvAddress;
private List<Address> addresses;
private Util util;


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

addresses = new ArrayList<>();
lvAddress = (ListView) findViewById(R.id.lv_address);
AddressAdapter adapter = new AddressAdapter( this, addresses );
lvAddress.setAdapter( adapter );
lvAddress.setOnItemClickListener(this);

spStates = (Spinner) findViewById(R.id.sp_state);
spStates.setAdapter( ArrayAdapter.createFromResource(this, R.array.states, android.R.layout.simple_spinner_item) );

util = new Util(this,
R.id.et_street,
R.id.et_city,
R.id.sp_state);
}

...
}

Como em SignUpActivity, também vamos trabalhar com o travamento / destravamento de Views via classe utilitária Util.

Veja que colocamos a implementação de OnItemClickListener diretamente em ZipCodeSearchActivity, isso para evitar a "embolação" de código devido ao uso de instância anônima caso essa estratégia não fosse adotada.

Agora o trecho com mais lógica de negócio:

public class ZipCodeSearchActivity extends AppCompatActivity
implements AdapterView.OnItemClickListener {
...

private String getState(){
String state = (String) spStates.getSelectedItem();
String[] parts = state.split("\\(");
parts = parts[ parts.length - 1 ].split("\\)");
state = parts[0];

return state;
}

private String getCity(){
return ((EditText) findViewById(R.id.et_city)).getText().toString();
}

private String getStreet(){
return ((EditText) findViewById(R.id.et_street)).getText().toString();
}

public String getUriRequest(){
String uri = getState()+"/";
uri += getCity()+"/";
uri += getStreet()+"/";
uri += "json/";

return "https://viacep.com.br/ws/"+uri;
}

public void searchAddress( View view ){
new ZipCodeRequest( this ).execute();
}

public void updateListView(){
((AddressAdapter) lvAddress.getAdapter()).notifyDataSetChanged();
}

public List<Address> getAddresses(){
return addresses;
}

public void lockFields( boolean isToLock ){
util.lockFields( isToLock );
}

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String[] zipCodeArray = addresses.get( i ).getCep().split("-");
String zipCode = zipCodeArray[0] + zipCodeArray[1];

Intent intent = new Intent();
intent.putExtra( Address.ZIP_CODE_KEY, zipCode );
setResult(RESULT_OK, intent);
finish();
}
}

 

O método getUriRequest() utiliza alguns métodos que encapsulam a complexidade de acesso aos dados de algumas Views especificas. Este método é muito similar ao da classe SignUpActivity, aqui retornando a url de busca de CEPs.

O método getAddresses() permite que o código de ZipCodeRequest realize o clear() na lista addresses. Com isso reaproveitamos o objeto de lista, diminuindo a possiblidade de vazamento de memória e a posterior exceção OutOfMemoryException.

Note o método getState(). Como os itens de nosso array de estados tem a seguinte estrutura: Nome Estado (Sigla). Temos de criar uma lógica somente para pegar a sigla desta estrutura, pois a API do ViaCEP está esperando a sigla e não o nome completo do estado.

O método updateListView() permite o fácil acesso, do código em ZipCodeRequest, ao algoritmo de atualização de itens na ListView, para que o usuário tenha o reflexo da atualização na tela dele.

No onItemClickListener() obtemos o CEP da posição escolhida e o passamos para um Intent que permitirá o acesso a ele na SignUpActivity. Com isso vamos poder atualizar o campo etZipCode desta Activity. Note que removemos o "-" para facilitar a atribuição do CEP ao correto campo em SignUpActivity.

O método searchAddress() é o que responde ao clique no TextView de rótulo "Buscar" no layout da Activity atual. Nele ativamos o ZipCodeRequest.

O código em ZipCodeSearchActivity ainda não está funcional devido a algumas atualizações que devemos realizar nas classes Address e SignUpActivity.

Mas por aqui já terminamos com o código dela, ou seja, o usuário preenche o formulário para busca do CEP. A busca é apresentada no ListView logo abaixo do formulário.

E assim, encontrado o CEP correto, quando o usuário clica no item enviamos o CEP para a Activity que contém o formulário de endereço para cadastro de conta.

Somente um detalhe, a atualização do AndroidManifest.xml:

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

<uses-permission android:name="android.permission.INTERNET" />

<application
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=".SignUpActivity" />
<activity android:name=".ZipCodeSearchActivity"/>
</application>

</manifest>

Atualizando o domínio do problema

A seguir as atualizações nas classes Address e SignUpActivity.

Vamos iniciar com a classe Address:

public class Address {
public static final int RESQUEST_ZIP_CODE_CODE = 556; /* NÚMERO ALEATÓRIO */
public static final String ZIP_CODE_KEY = "zip_code_key";
...
}

 

Apenas adicionamos as entidades que permitem a utilização do CEP de ZipCodeSearchActivity em SignUpActivity. Uma constante para chamada e verificação, respectivamente para uso em: startActivityForResult() e onActivityResult().

A chave ZIP_CODE_KEY é para acesso ao CEP no Intent recebido em onActivityResult().

E assim o código da Activity:

public class SignUpActivity extends AppCompatActivity {
...

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if( requestCode == Address.RESQUEST_ZIP_CODE_CODE
&& resultCode == RESULT_OK ){
etZipCode.setText( data.getStringExtra( Address.ZIP_CODE_KEY ) );
}
}

public void searchZipCode(View view){
Intent intent = new Intent(this, ZipCodeSearchActivity.class);
startActivityForResult( intent, Address.RESQUEST_ZIP_CODE_CODE );
}
}

 

Simples. A chamada a Activity de busca de CEP, via searchZipCode() que está vinculado ao onClick do TextView de rótulo "Esqueci o CEP" do layout de SignUpActivity.

E a atribuição do valor retornado, em onActivityResult(), ao campo de CEP, etZipCode, do layout de SignUpActivity.

Assim podemos partir para os testes.

Testes e resultados

Execute o aplicativo em algum device ou emulador, logo em seguida clique em "Ainda não tem conta? Cadastre-se":

Na tela seguinte clique em "Esqueci o CEP":

Entre com os dados de sua região, digo, os dados: cidade, estado e rua. Logo depois clique em Buscar:

Terá o resultado sendo apresentado de maneira similar ao da figura a seguir:

Encontre a opção que se enquadra em sua região e clique nela. Assim, o formulário de endereço em SignUpActivity terá o pré-preenchimento realizado, como a seguir: 

Terminamos com esta série sobre API de endereços. Existem várias outras disponíveis, com isso fica como principal valor da série a lógica de negócio utilizada no projeto de exemplo, para você reaproveita-la com qualquer outra API.

Vídeo com implementação passo a passo do código - Parte dois

No vídeo abaixo é apresentada a implementação passo a passo do projeto, parte dois:

Para acessar a versão Android do Projeto, completa (incluindo parte um), entre no GitHub a seguir: https://github.com/viniciusthiengo/marketplace-app.

Conclusão

Com o final da série de API de endereço temos que a parte crítica da implementação está ligada a lógica de negócio para gerenciar corretamente os dados retornados pela API e a posterior apresentação deles.

Ou seja, não somente para pré-preenchimento de endereço, mas para qualquer outro tipo de dado, a lógica que você utilizará em seu aplicativo é que fará a diferença tanto na qualidade do algoritmo dele quanto na qualidade percebida pelo usuário.

No aplicativo do Blog Thiengo [Calopsita], assim que você entra na área de envio de contato seu endereço de email já está presente no campo de email. Isso conforta o usuário em saber que somente precisará preencher o campo assunto e a mensagem em si.

Mas lhe digo que para a apresentação desse email, o código que obtém ele e então envia este por "n" entidades até colocar o endereço no campo correto é a parte menos trivial de todo o algoritmo. Porque somente pegar o email é de um entidade nativa Android é algo simples. Ou seja, novamente a lógica de negócio é a parte "burocrática".

Com essa série de dois artigos, com vídeos, conseguimos assim entender que formulários não devem ser colocados no ar sem o estudo correto, digo, a otimização dos campos que devem ou não estar presentes e a melhoria do preenchimento daqueles que devem estar.

Qualquer dúvida ou sugestão, é só deixar seu comentário logo abaixo.

Fontes

ViaCEP - página de apresentação da API

Página GitHub Postmon API

Usando HttpClient e Gson no Android Studio

Vlw.

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Relacionado

Estratégia de Anúncios com In Loco Media no AndroidEstratégia de Anúncios com In Loco Media no AndroidAndroid
Lint Tool Para Alta Performance em APPs AndroidLint Tool Para Alta Performance em APPs AndroidAndroid
GCMNetworkManager Para Execução de Tarefas no Background AndroidGCMNetworkManager Para Execução de Tarefas no Background AndroidAndroid
API de Endereços Para Pré-Cadastro em APPs Android - Parte 1API de Endereços Para Pré-Cadastro em APPs Android - Parte 1Android

Compartilhar

Comentários Facebook (3)

Comentários Blog (3)

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...
Ricardo Fagmer (1) (0)
26/01/2017
Bom dia Thiengo,

Tem algum vídeo abordando o sobre opencv ?
Responder
Vinícius Thiengo (0) (0)
26/01/2017
Ricardo, respondido logo acima nos comentários do Facebook. Abraço.
Responder
11/01/2017
Incrivel e muito bem explicado.
Parabéns.
Se  possivel Thiengo traga mais tutoriais sobre API.s disponiveis na Web.
Responder