A aplicação desenvolvida é algo muito simples e no mundo real ninguém criaria uma calculadora como esta. Lembre-se, o aplicativo foi criado apenas para estudar alguns conceitos (Principalmente o BroadcastReceiver).
Mas de que se trata o BroadcastReceiver?
Assim como as Activities podem ser chamadas por outras Activities através da utilização de Intents, Receivers também podem ser "chamados".
A principal diferença entre uma Activity e um Receiver é que o Receiver é executado em background e geralmente não deve realizar interação com o usuário (para evitar interrompe-lo). Além disso, um receiver possui um tempo máximo para executar alguma tarefa determinado em 10 segundos. Caso sua tarefa ultrapasse este tempo o Receiver é interrompido pelo sistema operacional.
Para as Activities que disponibilizamos, geralmente utilizamos um IntentFilter que diz o nome da Action e Category que permitem ao android encontrar nossa aplicação.
O exemplo clássico de um IntentFilter, é o que já é declarado quando criamos uma aplicação de HelloWorld no eclipse:
<activity
android:name=".LivroAndroidCap7Activity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Para um Receiver responder à uma Intent, o mesmo também precisa ser declarado com um IntentFilter. Um Receiver pode atender a várias Actions nativas como BOOT, recebimento de SMS, eventos relacionados à bateria além de poder atender a Actions customizadas (strings definidas pelo próprio desenvolvedor).
Criando a calculadora
Bom, então vamos logo para a criação da calculadora. A idéia aqui é criar um aplicativo que possui uma tela inicial que mostra apenas um botão com o rótulo Calcular conforme mostrado na figura abaixo:
Ao pressionar este botão, o usuário receberá um formulário com 3 campos dentro de um AlertDialog. O formulário poderia ter sido criado na mesma tela que o botão calcular, mas eu quis complicar um pouco mais só para brincar um pouco mais com outras funcionalidades do android (neste caso usar um AlertDialog).
Caso o usuário selecione o botão Calcular neste formulário, os dados para o cálculo são enviados para o sistema operacional através de uma Intent definida com o seguinte intent filter:
<intent-filter>
<action android:name="CALCULO" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Considerando este IntentFilter, outros aplicativos podem ser criados para enviar um broadcast com dados para CALCULO. Outros Receivers também podem ser criados para receber dados para calcular e efetuar estes cálculos de forma diferente (por exemplo algum tipo de cálculo alienígena).
A primeira coisa que criei neste projeto foram os layouts definidos no diretório res/layout do projeto.
main.xml (layout que possui apenas o botão calcular - tela inicial)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/calculadora" />
<Button
android:id="@+id/btCalcular"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/calcular" />
</LinearLayout>
layout_form.xml (layout que possui os campos do formulário - usado no AlertDialog)
<?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" >
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="@string/primeiro_numero"
/>
<EditText
android:id="@+id/numero1"
android:inputType="number"
android:layout_width="fill_parent" android:layout_height="wrap_content"
/>
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="@string/segundo_numero"
/>
<EditText
android:id="@+id/numero2"
android:inputType="number"
android:layout_width="fill_parent" android:layout_height="wrap_content"
/>
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="@string/operacao"
/>
<Spinner
android:id="@+id/operacao"
android:layout_width="fill_parent" android:layout_height="wrap_content"/>
</LinearLayout>
Após definir os layouts, criei as classes para a Activity e uma para o Receiver.
CalculoReceiver.java
package br.com.livro.cap9;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class CalculoReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
// recupera os dados para calculo que qualquer Intent
// recebida para este fim precisa enviar
Bundle extras = intent.getExtras();
if (extras != null) {
String n1 = extras.getString("numero1");
String n2 = extras.getString("numero2");
String op = extras.getString("operacao");
// recebe os valores
// faz uma pequena validação
// e então decide qual operaçao executar guardando o valor em resultado
if (!isEmpty(n1) && !isEmpty(n2) && !isEmpty(op)) {
int in1 = Integer.parseInt(n1);
int in2 = Integer.parseInt(n2);
int iop = Integer.parseInt(op);
int resultado = 0;
switch (iop) {
case 0: // soma
resultado = in1 + in2;
break;
case 1: // subtracao
resultado = in1 - in2;
break;
case 2: // multiplicacao
resultado = in1 * in2;
break;
case 3: // divisao
resultado = in1 / in2;
break;
}
// após efetuar o cálculo apenas gera um log
// que poderá ser verificado pelo LogCat no eclipse.
Log.i("CALCULO", "resultado do calculo: " + resultado);
}
}
}
private boolean isEmpty(String v) {
return (v == null || v.length() == 0);
}
}
CalculadoraActivity.java
package br.com.livro.cap9;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
public class CalculadoraActivity extends Activity implements OnItemSelectedListener, OnClickListener {
protected static final int SOMA = 0;
private int codigoOperacao = SOMA;
// lista de operações disponíveis
private String[] operacoes = {
"Soma", "Subtração", "Multiplicação", "Divisão"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// adicionando o comportamento para o botão calcular
Button btCalcular = (Button) findViewById(R.id.btCalcular);
btCalcular.setOnClickListener(this);
}
/**
* Ao selecionar um item no Spinner (famoso combobox em outras plataformas),
* a posição da operação selecionada é guardada em codigoOperacao que podera ser
* encaminhada através da Intent posteriormente quando o usuário solicitar o calculo.
*/
public void onItemSelected(AdapterView adapterView, View view,
int position, long id) {
codigoOperacao = position;
}
@Override
public void onNothingSelected(AdapterView arg0) {
codigoOperacao = SOMA; // operação padrao é a soma
}
@Override
public void onClick(View v) {
// criando a janela de dialogo
AlertDialog.Builder alert = new AlertDialog.Builder(this);
// Uma das coisas interessantes em utilizar este AlertDialog no exemplo, foi
// utilizar também o LayoutInflater conforme mostrado abaixo.
// O LayoutInflater cria uma instancia de View baseando-se
// no layout informado em inflater.inflate
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View viewForm = inflater.inflate(R.layout.layout_form, null);
// Desta forma é possivel definir o conteúdo do AlertDialog
// como uma View ao invés de uma mensagem texto.
alert.setView(viewForm);
// Criamos entao os botoes para uma açao positiva e uma açao negativa
// utilizando os devidos Listeners para click nos botoes.
// Repare que a classe OnClickListener está dentro de DialogInterface
// e não dentro de View como é utilizado para Buttons.
alert.setPositiveButton("Calcular", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// aqui dentro recuperamos os dados registrados na view do formulário
// por isso, para recuperar cada EditText, foi utilizado o viewForm.findViewById.
// Pois apenas esta view possui os componentes registrados.
// Tente utilizar findViewbyId apenas para ver o que acontece =P
EditText txtNumero1 = (EditText) viewForm.findViewById(R.id.numero1);
EditText txtNumero2 = (EditText) viewForm.findViewById(R.id.numero2);
Bundle extras = new Bundle();
extras.putString("numero1", txtNumero1.getText().toString());
extras.putString("numero2", txtNumero2.getText().toString());
extras.putString("operacao", Integer.toString(codigoOperacao));
// Este é o ponto principal para o estudo do BroadcastReceiver.
// É aqui que criamos uma intent para calculo que será
// recebida pelo nosso Receiver CalculoReceiver.
Intent itCalculo = new Intent();
itCalculo.setAction("CALCULO");
itCalculo.putExtras(extras);
sendBroadcast(itCalculo);
Toast.makeText(CalculadoraActivity.this, "calculo enviado para broadcast", Toast.LENGTH_SHORT).show();
}
});
alert.setNegativeButton("Cancelar", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(CalculadoraActivity.this, "calculo cancelado", Toast.LENGTH_SHORT).show();
}
});
// carregando a lista de operações utilizando um ArrayAdapter
// Existe muito conteúdo na net explicando o conceito de adapter para utilização em listas.
ArrayAdapter adapter = new ArrayAdapter(
this, android.R.layout.simple_spinner_item, operacoes);
Spinner spnOperacoes = (Spinner) viewForm.findViewById(R.id.operacao);
spnOperacoes.setAdapter(adapter);
// guarda a posicao da operacao pois deve ser enviado para o broadcast receiver
// o código da operação a ser realizada e não a descrição
spnOperacoes.setOnItemSelectedListener(this);
// exibindo o alert com o formulario para o usuário.
alert.show();
}
}
Para entender o código, leia os comentários colocados no próprio código. Não vou detalhar o código aqui para não ficar repetitivo.
Agora que criamos tudo que é necessário, é preciso registrar a Activity e o Receiver dentro no arquivo AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="br.com.livro.cap9"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity android:name="CalculadoraActivity" android:label="calculadora">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name="CalculoReceiver" android:label="calculo receiver">
<intent-filter>
<action android:name="CALCULO" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>
Ao executar a aplicação, teremos a seguinte saída no emulador:
E teremos a seguinte saída no LogCat:
Bom, é isso aí... o post acaba por aqui e espero que alguém também possa aprender algo com este exemplo simples.
Até a próxima.




tem como passar valores do BroadCastReceiver para uma Activity ?
ResponderExcluir