+ Curso de Android 19ª Jornada de Cursos. + 7. Programação para internet

Preview:

Citation preview

+

Curso de Android

19ª Jornada de Cursos

+7. Programação para internet

+Trabalhando com sockets

Sockets são conexões de internet que são especificadas pelos protocolos TCP/IP, ou melhor, são endereços de nós e um número de porta, os quais identificam um serviço.

Funciona da seguinte maneira: Primeiro, o programa servidor começa a ser executado esperando

por um pedido do cliente. Depois, o programa cliente requisita uma conexão indicando o

servidor com o qual quer se conectar. Por fim, quando o cliente envia um pedido, o servidor pode

“aceitar” a conexão, e inicia um socket no lado servidor e dedica esse socket para essa conexão cliente especifica.

+Trabalhando com sockets

Todo computador ou dispositivo conectado a internet pode ser acessado qualquer outro computador ou dispositivo, e eles podem estar atuando como cliente (que requisita uma conexão) ou servidor (negando ou aceitando essa conexão).

A idéia aqui e criar um cliente, que será uma aplicação em Android onde ela irá requisitar um serviço no servidor, que será uma aplicação em Java.

A aplicação cliente será uma calculadora onde ela envia dois números para o servidor, que será responsável por retornar a soma dos dois números para o cliente.

+Aplicação Cliente-Servidor

ANDROID:

Project Name: ClienteServidorAndroidJava

Package Name : br.ufpe.cin.android.appservidorcliente

Create Activity: AppCliente

Application Name: Aplicação Cliente

Min SDK Version: 10

+Aplicação Cliente-Servidor

Crie um projeto Java, contendo a classe ServidorCalculadora.java.

Essa classe deve ser executada via linha de comando, com o seguinte comando a ser executado: “cd <caminho para a pasta do java>\jre7\bin\ java –cp “<caminho para seu workspace>\ServidorJava\bin"

ServidorCalculadora

+Aplicação Cliente-Servidor

ServidorCalculadora.javaimport java.net.*;import java.io.*;public class ServidorCalculadora {

public static void main(String[] args) { double num1,num2; try {

ServerSocket ss = new ServerSocket(60);System.out.print("Aguardando conexao...\n\n");Socket s = ss.accept();System.out.print("Conexao aceita...\n\n");DataInputStream in = new DataInputStream(s.getInputStream());

+Aplicação Cliente-Servidor

DataOutputStream out = newDataOutputStream(s.getOutputStream());num1 = in.readDouble();num2 = in.readDouble();System.out.println(num1 + "+" + num2 + "=" +(num1 + num2));out.writeDouble((num1 + num2));in.close();out.close();s.close();ss.close();  } catch (IOException e) {e.printStackTrace();}

 }}

+Aplicação Cliente-Servidor

AppCliente.javapublic void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);setContentView(R.layout.main);Button btsomar = (Button)findViewById(R.id.btsomar);btsomar.setOnClickListener(new View.OnClickListener(){public void onClick(View v) {try {

Socket s = new Socket("10.0.2.2",60);DataInputStream in = newDataInputStream(s.getInputStream());

+Aplicação Cliente-Servidor

DataOutputStream out = newDataOutputStream(s.getOutputStream());TextView txtnum1,txtnum2;txtnum1 = (TextView)findViewById(R.id.txtnum1);txtnum2 = (TextView)findViewById(R.id.txtnum2);out.writeDouble(Double.parseDouble(txtnum1.getText().toString()));out.writeDouble(Double.parseDouble(txtnum2.getText().toString()));AlertDialog.Builder d = newAlertDialog.Builder(AppCliente.this);d.setTitle("Soma");d.setMessage("Soma:" +String.valueOf(in.readDouble()));d.setNeutralButton("OK", null);

+Aplicação Cliente-Servidor

d.show();in.close();out.close();s.close();

} catch (Exception e) {e.printStackTrace();

}}

+Aplicação Cliente-Servidor

No arquivo AndroidManifest.xml, antes da tag </manifest>, coloque a tag abaixo:

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

+Melhorando!

Adicione as outras operações básicas, informando ao servidor de que operação se trata;

Faça com que o servidor fique constantemente esperando requisições.

+Obtendo conteúdo de uma URL

Project Name: AplicacaoRecebConteudo

Package Name : br.ufpe.cin.android.apprecebcont

Create Activity: AppContent

Application Name: Aplicação URL 1

Min SDK Version: 10

+Obtendo conteúdo de uma URL

main.xml

EditText Id:@+id/edurlLayout width: fill_parentButton Id: @+id/btsmostrar, Layout width: fill_parentText: Somar

+Obtendo conteúdo de uma URL

AppContent.javapublic void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);setContentView(R.layout.main);edurl = (EditText) findViewById(R.id.edurl);btmostrar = (Button) findViewById(R.id.mostrar);btmostrar.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) {try{String strurl = edurl.getText().toString();URL url = new URL(strurl);InputStream is = url.openStream();int i;

+Obtendo conteúdo de uma URL

String conteudo="";while((i = is.read()) != -1)conteudo+= ((char)i);AlertDialog.Builder dialogo = newAlertDialog.Builder(AppContent.this);dialogo.setMessage(conteudo);dialogo.setTitle("Conteúdo");dialogo.setNeutralButton("OK", null);dialogo.show();

}catch(Exception e) { }}

});}

+Obtendo conteúdo de uma URL

No arquivo AndroidManifest.xml, antes da tag </manifest>, coloque a tag abaixo:

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

+Envio de informações para uma URL

Project Name: AplicacaoEnviaConteudo

Package Name : br.ufpe.cin.android.appenviacont

Create Activity: AppSend

Application Name: Aplicação URL 2

Min SDK Version: 10

+Enviando informações para uma URL

main.xml

EditText Id:@+id/nomeLayout width: fill_parentTextView Text: IdadeEditTextId: @+id/idadeLayout width: fill_parentButton Id: @+id/btsenviar, Layout width: fill_parent, Text: Enviar Dados

+Enviando informações para uma URL

AppContent.javapublic void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);setContentView(R.layout.main);Button b = (Button)findViewById(R.id.btenviar);b.setOnClickListener(newView.OnClickListener(){public void onClick(View v) {

TextView txtnome = (TextView) findViewById(R.id.nome);TextView txtidade = (TextView) findViewById(R.id.idade);String nome = txtnome.getText().toString();String idade = txtidade.getText().toString();nome = URLEncoder.encode(nome);

+Enviando informações para uma URL

try{URL url = new URL("http://www.lfliborio.com.br/android/php/cadastrar_dados.php?nome=" + nome + "&idade=" + idade);url.openStream();AlertDialog.Builder d = new AlertDialog.Builder(AppSend.this);d.setMessage("Dados enviados com sucesso.");d.setNeutralButton("OK", null);d.setTitle("Resultado");d.show();

}catch(Exception e) {AlertDialog.Builder d = new AlertDialog.Builder(AppSend.this);d.setMessage(e.toString());d.setNeutralButton("OK", null);d.setTitle("Erro");d.show();

}}

});}

+Enviando informações para uma URL

No arquivo AndroidManifest.xml, antes da tag </manifest>, coloque a tag abaixo:

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

+Desafio!

Voltemos para a nossa aplicação de cadastro (a primeira versão);

Queremos agora armazenar os dados a serem cadastrados em um banco de dados remoto;

Usaremos duas páginas Web: www.lfliborio.com.br/android/php/cadastrar_dados.php:

Receberá os parâmetros nome,idade e profissao, para inserir no BD;

www.lfliborio.com.br/android/php/get_pessoa.php: Retornará o registro com a posição indicada pelo parâmetro id (inciando de zero)

+Fazendo download de um arquivo

Project Name: AplicacaoDownload

Package Name : br.ufpe.cin.android.appdownload

Create Activity: AppDownload

Application Name: Aplicação Download

Min SDK Version: 10

+Fazendo download de um arquivo

main.xml

ButtonId: @+id/btdownloadLayout width: fill_parentText: Baixar imagemTextView Text: ImagemImageView

Id: @+id/imagemSrc:<vazio>Layout: height wrap_contentLayout width: wrap_content

+Fazendo download de um arquivo

AppDownload.javapublic void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);setContentView(R.layout.main);Button b = (Button)findViewById(R.id.btdownload);b.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) {ImageView imagem = (ImageView) findViewById(R.id.imagem);try {

URL url = new URL("http://www.lfliborio.com.br/android/php/logo.png");InputStream is = url.openStream();Bitmap bmp = BitmapFactory.decodeStream(is);imagem.setImageBitmap(bmp);

+Fazendo download de um arquivo

} catch (Exception e) {AlertDialog.Builder d = newAlertDialog.Builder(AppDownload.this);d.setMessage(e.toString());d.setTitle("Aviso");d.setNeutralButton("OK", null);d.show();

}}

});}

+Fazendo download de uma arquivo

No arquivo AndroidManifest.xml, antes da tag </manifest>, coloque a tag abaixo:

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

+Melhorando!

Voltemos a nossa aplicação de galeria de imagem.

Vamos fazer a sua composição apenas de imagens retiradas da internet; http://www.lfliborio.com.br/android/php/lista_imagens.php

Nomes separados por vírgulas (“\\,”) As imagens estão em http://www.lfliborio.com.br/android/php/

+O componente WebView

Esse componente WebView é muito utilizado quando queremos desenvolver um navegador próprio para o nosso dispositivo.

Embora o emulador já possua um Browser embutido, o Android fornece um componente próprio voltado para tal finalidade.

Ele funciona como um display onde podemos visualizar as páginas da internet.

Normalmente, o componente WebView é trabalhado em conjunto com o componente WebSettings.

+Aplicação de cadastro

Project Name: AplicacaoBrowser

Package Name : br.ufpe.cin.android.appbrowser

Create Activity: AppBrowser

Application Name: Aplicação de Browser

Min SDK Version: 10

+Aplicação de Browser

AppNavegador.javapublic void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);WebView w = new WebView(this);WebSettings ws = w.getSettings();ws.setSavePassword(false);ws.setSaveFormData(false);ws.setJavaScriptEnabled(true);ws.setSupportZoom(false);w.loadUrl("http://www.globo.com");setContentView(w);}

+Aplicação de Browser

No arquivo AndroidManifest.xml, antes da tag </manifest>, coloque a tag abaixo:

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

+8. Testes

+TDD

Test-driven development (TDD), é um método de desenvolvimento de software in que testes de unidade são repetidamente feitos no código.

O conceito é ter algo funcionando agora e perfeito depois.

Depois de cada teste, refatorações são feitas e o mesmo teste é rodado novamente. Esse processo é repetido quantas vezes forem necessárias até cada

unidade estar funcionando de acordo com as especificações fornecidas.

+TDD

Utilizando TDD, pode-se produzir aplicações com alta qualidade em menos tempo do que é possível com outros métodos.

Implementações corretas de TDD precisam que os desenvolvedores e testadores antecipem acertadamente como a aplicação e suas funcionalidades vão ser utilizadas pelos usuários finais.

+TDD

Problemas são abordados de uma maneira incremental, e os testes são feitos em uma mesma unidade de código devem ser feitos várias vezes.

A natureza metódica do TDD garante que todas as unidades na aplicação foram testadas para obter a melhor funcionalidade, individual ou coletivamente.

Como começa cedo no ciclo de desenvolvimento, o custo com uma depuração que seria feita mais adiante é minimizado.

+Estrutura do teste de aplicações

Os testes em Android, como as aplicações, são organizados em projetos.

Um projeto de teste é um diretório ou um projeto do Eclipse em que o desenvolvedor cria, entre outros arquivos, o código-fonte do pacote de testes.

O Android SDK possui ferramentas para auxiliar o desenvolvimento em conjunto com o Eclipse e o ADT, para criação de toda a estrutura de arquivos necessária.

+Estrutura do teste de aplicações

É altamente recomendado que o desenvolvedor sempre utilize as ferramentas do Android SDK para criar o projeto de testes. Entre outros benefícios, temos: Uso da classe InstrumentationTestRunner setado

automaticamente para o pacote de testes. Ela sera usada para execução dos testes com JUnit.

Criação automática de todos os arquivos de build, manifest e a estrutura de diretórios do projeto de testes.

+Estrutura do teste de aplicações

O projeto de teste pode ser criado em qualquer diretório da máquina de desenvolvimento, mas uma boa prática é adicionar o projeto (com a pasta raiz tests/) no mesmo nível da pasta src/ da aplicação. Isso facilita a associação do pacote de testes com a aplicação em questão.

A API de testes do Android é baseada na API do JUnit, e estendida com um framework de instrumentação e casos de testes específicos para o Android.

+Estrutura do teste de aplicações

O JUnit pode ser usado para planejar um objeto em Java puro. A classe TestCase é a base para a classe AndroidTestCase, que é usada para realizar testes específicos para objetos Android.

Para exibir os resultados dos testes, podemos utilizar a classe do JUnit chamada Assert. Os métodos desta classe comparam os valores esperados para o teste com os resultados atuais e lança uma exceção se a comparação falhar.

+Instrumentation

A instrumentação no Android funciona como uma série de métodos de controle no sistema, como “ganchos”. Estes ganchos controlam um componente Android

independentemente do seu ciclo de vida normal. Eles também controlam como o Android carrega aplicações.

Normalmente, um componente do Android executa em um ciclo de vida determinado pelo sistema. Quando uma Activity é ativada por uma Intent, seus métodos

onCreate, onPause, onResume e onDestroy são chamados pelo sistema, não existindo meios para que o código acesse esses métodos diretamente. Mas isto pode ser feito com instrumentação.

+Instrumentation

Também é possível que o sistema execute todos os componentes de uma aplicação dentro do mesmo processo.

O desenvolvedor pode permitir que alguns componentes, como ContentProviders, executem em um processo separado, mas não pode forçar uma aplicação a rodar no mesmo processo que outra que já está executando.

+Instrumentation

Com a instrumentação do Android métodos de call-back podem ser invocados diretamente no código de teste. Isto possibilita executar passo a passo o ciclo de vida de um

componente, como se o código estivesse sendo debugado.

mActivity = getActivity();mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01);mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);mActivity.finish();mActivity = getActivity();int currentPosition = mActivity.getSpinnerPosition();assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

+Instrumentation

O método-chave utilizado é o getActivity(), que é parte da API de instrumentação. A Activity testada não é iniciada enquanto o método não for chamado.

Adicionalmente, a instrumentação pode rodar a aplicação e o pacote de testes dentro do mesmo processo. Desde que os componentes da aplicação e os respectivos testes

estejam no mesmo processo, os testes podem invocar métodos dos componentes, bem como modificar e examinar campos nos mesmos.

+9. Layouts

+FrameLayout

FrameLayout é o tipo mais simples de layout.

Ele é, basicamente, um espaço em branco na tela, que o desenvolvedor pode preencher com um único objeto.

Todos os componentes do layout são fixados no topo esquerdo da tela.

Não é permitida outra localidade para ele. Itens subsequentes são simplesmente desenhados sobre os outros, encobrindo total ou parcialmente.

+LinearLayout

Um LinearLayout alinha todos os components em uma única direção – vertical ou horizontal, dependendo da orientação fornecida.

Todos os componentes são enfileirados um depois do outro, sendo uma lista vertical tendo um elemento por linha, enquanto que uma horizontal tem a altura máxima de uma linha (no caso, a altura do maior item).

+LinearLayout

O LinearLayout respeita margens entre os items e o alinhamento de cada item de acordo com o espaço.

LinearLayout também pode atribuir um peso a componentes, para mostrar a importância deste para a view, e permite ao componente ocupar todo o espaço restante da view.

No caso de vários valores de pesos serem atribuídos (sendo estes inteiros), cada item é expandido proporcionalmente ao valor do seu peso. O valor default é zero.

+LinearLayout

Para criar um layout de tamanho proporcional, crie um container com os atributos “layout_width” e “layout_height” setados para “fill_parent”; atribua os valores dos itens de height e width para zero.

+TableLayout

TableLayout posiciona seus components em linhas e colunas. Os espaços desse layout não mostram as bordas das linhas, colunas e células. A quantidade de colunas na tabela será determinada pelo linha com o maior número de células. Uma tabela pode ter células vazias.

TableRow são sub-elementos de TableLayout, onde cada um deles define uma linha na tabela). Cada linha possui zero ou mais células, onde cada uma define uma outra View ImageView, TextView, etc), ou ainda, outro ViewGroup aninhado (outro TableLayout, por exemplo).

+TableLayout

+TableLayout

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

    <TableRow>        <TextView            android:layout_column="1"            android:text="Open..."            android:padding="3dip" />        <TextView            android:text="Ctrl-O"            android:gravity="right"            android:padding="3dip" />    </TableRow>

+TableLayout

<View        android:layout_height="2dip"        android:background="#FF909090" />

    <TableRow>        <TextView            android:text="X"            android:padding="3dip" />        <TextView            android:text="Import..."            android:padding="3dip" />    </TableRow>

+TableLayout

<View        android:layout_height="2dip"        android:background="#FF909090" />

    <TableRow>        <TextView            android:text="X"            android:padding="3dip" />        <TextView            android:text="Import..."            android:padding="3dip" />    </TableRow>

+TableLayout

<View        android:layout_height="2dip"        android:background="#FF909090" />

    <TableRow>        <TextView            android:text="X"            android:padding="3dip" />        <TextView            android:text="Import..."            android:padding="3dip" />    </TableRow> <TableRow>        <TextView            android:text="X"            android:padding="3dip" />

+TableLayout

        <TextView            android:text="Export..."            android:padding="3dip" />        <TextView            android:text="Ctrl-E"            android:gravity="right"            android:padding="3dip" />    </TableRow>    <View android:layout_height="2dip"        android:background="#FF909090" />TableRow>        <TextView            android:layout_column="1"            android:text="Quit"            android:padding="3dip" />    </TableRow></TableLayout>

+TableLayout

TableRow>        <TextView            android:layout_column="1"            android:text="Quit"            android:padding="3dip" />    </TableRow></TableLayout>

+RelativeLayout

RelativeLayout faz com que as posições dos componentes sejam determinadas relativamente ao layout ou a outro componente. Então, é possível alinhar dois elementos a margem direita, ou

colocar um abaixo do outro, centralizado na tela, etc.

Os elementos são renderizados na ordem fornecida, então, se o primeiro elemento for centralizado na tela, outros elementos alinham-se relativamente ao primeiro.

Também, por conta dessa ordenação, se for usado XML para especificar o layout, o elemento que o desenvolvedor irá usar como referencia tem que estar listado primeiro que os outros.

+RelativeLayout

+RelativeLayout

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent">    <TextView        android:id="@+id/label"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="Type here:"/>    <EditText        android:id="@+id/entry"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:background="@android:drawable/editbox_background"        android:layout_below="@id/label"/>

+RelativeLayout

<Button        android:id="@+id/ok"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/entry"        android:layout_alignParentRight="true"        android:layout_marginLeft="10dip"        android:text="OK" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_toLeftOf="@id/ok"        android:layout_alignTop="@id/ok"        android:text="Cancel" /></RelativeLayout>

+Melhorando!

Voltemos a nossa aplicação de cadastro!

Implemente a tela de Listar com um TableLayout;

Implemente a tela de Cadastrar com um RelativeLayout; Visualmente, o resultado deve ser o mesmo da

aplicação anterior!