quarta-feira, 20 de março de 2013

O elemento <svg> do HTML5

O HTML 5 trouxe novas possibilidades em relação a suas versões anteriores. Entre essas novidades está a tag <svg>.

SVG é o acrônimo de "Scalable Vector Graphics" (ou "gráficos vetoriais escaláveis"). É um formato aberto (uma recomendação da W3C) para definir, através da linguagem XML, gráficos bidimensionais baseados em vetores. Esses gráficos podem ser estáticos, dinâmicos e, até mesmo, animados.

DICA: O site svgwow possui diversos exemplos de animações feitas com svg (clique em um dos exemplos e depois no botão "start svg demo").

Uma das grandes vantagens desse tipo de gráfico, em relação a outros formatos de imagem (como JPEG, PNG, GIF, etc), é que ele não perde qualidade quando é redimensionado ou quando é ampliado (zoom), sendo totalmente escalável. Além disso, ele pode ser impresso com alta qualidade, em qualquer resolução.

Por ter uma representação em XML, as imagens SVG podem ser criadas e editadas em qualquer editor de texto (apesar de ser mais simples criá-las em editores, como o Inkscape), além de poderem ser indexadas, buscadas, navegadas (pelo seu DOM) e comprimidas.

No HTML5, podemos criar um gráfico SVG inserindo a tag <svg> dentro de um container HTML tradicional e incluindo dentro dela os elementos relativos à representação gráfica desejada.

DICA: Nessa página, pode-se encontrar uma referência completa de todos os elementos SVG presentes na recomendação do W3C (versão 1.1). E nessa página, pode-se encontrar exemplos de representações do SVG desenhando diferentes formas geométricas e mostrando algumas de suas potencialidades.


A seguir, é apresentado um exemplo de utilização da tag <svg> com a representação da bandeira do Brasil (simplificada), sendo equivalente ao exemplo apresentado no post da tag <canvas> do HTML5.

Visualização:
Ordem e Progresso
*Observação: esse exemplo é suportado pelos navegadores Firefox, Google Chrome, Safari e Internet Explorer a partir da versão 9.

Código fonte:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" height="150" width="250">
   
<rect fill="green" height="150" width="250" style="stroke-width: 1; stroke: rgb(0,0,0);" />

<polygon points="125,0 250,75 125,150 0,75 125,0" style="fill: #FCFF00; stroke-width: 1; stroke: purple;"/>

<circle cx="125" cy="75" fill="#00027F" r="50" stroke-width="1" stroke="black"/>

<rect fill="white" height="15" rx="2" width="100" x="75" y="65"/>

<text fill="black" font-family="Arial" font-size="10" x="80" y="75">Ordem e Progresso</text>

</svg>

DICA: Existem dois tipos de especificações especiais do SVG 1.1 para dispositivos móveis, o "SVG Tiny" (SVGT) e o "SVG Basic" (SVGB). O primeiro é destinado a rodar em máquinas com maior limitação de hardware (como aparelhos celulares) e o segundo a aparelhos com maior capacidade.


<svg> x <canvas>

Conforme pode ser visto no exemplo acima e no exemplo apresentado no post da tag <canvas> do HTML5, muitas vezes pode-se fazer uma imagem SVG equivalente a uma imagem feita em um Canvas. Mas qual a diferença de utilizar uma abordagem ou a outra?

Bom, pra começar, o SVG é baseado em XML - o que implica que todos os seus elementos ficam disponíveis no seu DOM, sendo possível navegar e manipular esses elementos. Também pode-se vincular tratamento de eventos (Javascript) para esses elementos. Além disso, cada forma geométrica é tratada como um objeto e se os atributos desse objeto são alterados, o navegador pode automaticamente renderizar a forma geométrica equivalente. Uma desvantagem dessa abordagem é que, em representações complexas, ele tende a ter uma renderização lenta.

Já na abordagem que utiliza o Canvas, o gráfico é renderizado pixel por pixel e, uma vez que estiver totalmente desenhado, ele é "esquecido" pelo navegador. Assim, qualquer alteração faz com que todo o gráfico tenha que ser desenhado novamente. Além disso, a qualidade do gráfico varia conforme a resolução utilizada. Uma vantagem desse tipo de gráfico é que ele pode ser salvo pelo usuário como uma imagem ".png" ou ".jpg".


O exemplo abaixo, adaptado desse post, deixa bem clara a diferença entre uma imagem tradicional (png) e uma imagem vetorial (svg), ao ser clicado no botão de zoom.


PNG
SVG


Referências


sábado, 9 de março de 2013

Como funciona uma Activity no Android?

Uma atividade é alguma coisa específica que pode ser feita para atingir um objetivo. Em quase todas as atividades ocorre interação com o usuário. Desta forma, em uma aplicação Android, a classe Activity se responsabiliza em criar uma janela, na qual o desenvolvedor pode colocar seus elementos de interface (GUI) através do método "setContentView(View)".

Todo aplicativo Android começa por uma Activity. Quando uma aplicação Android é executada, sua Activity principal (definida como padrão na configuração do projeto) é executada.

Fragments: A partir da versão 3.0 (Honeycomb), as implementações das Activities podem fazer uso da classe Fragment para modularização do seu código - o que também facilita o desenvolvimento de GUIs para telas maiores.

A classe Activity é uma parte importante de todo o ciclo de vida de uma aplicação, e a forma como as atividades são executadas e agrupadas são uma parte fundamental do modelo de aplicação da plataforma.


Ciclo de vida de uma Activity

Uma das questões mais importantes para entender e desenvolver uma aplicação Android é conhecer o ciclo de vida das Activities.

No sistema, as activities são gerenciadas como uma pilha. Quando uma nova Activity é inicializada, ela é colocada no topo dessa pilha e se torna a Activity em execução ("running activity"). A Activity anterior permanece sempre embaixo dela na pilha e não vem para o topo dela ("foreground") enquanto a nova Activity não sai.

O diagrama abaixo, retirado da documentação oficial, apresenta os diferentes estágios em que esse elemento pode se encontrar, além dos eventos que fazem mudar esses estados e dos métodos de callback disparados em cada etapa desse ciclo de vida (retângulos cinzas). Esses métodos podem ser implementados para realização de operações quando uma Activity passa de um estado para outro.


Nesse diagrama, as formas coloridas ovais marcam alguns estágios principais da Activity frente à aplicação, mas pode-se observar também três estados em que uma Activity pode se encontrar após ela ser criada e enquanto a aplicação ainda está rodando:
  1. Activity rodando ou ativa (em foco, no topo da pilha)
  2. Activity pausada (ainda visível, mas sem foco - com outra Activity transparente ou que não ocupe toda a tela na frente dela) 
  3. Activity parada (não visível, com outra Activity na frente)

DICA: Uma Activity pausada está completamente "viva", mantendo todo seu estado e informações e permanecendo ligada ao gerenciador de janelas ("window manager") - ela só será destruída pelo sistema em situações em que a memória ficar extremamente baixa. Já uma Activity parada, também mantém o seu estado e informações, mas sua janela fica oculta e pode ser frequentemente destruída pelo sistema quando for necessário mais memória.

Nos dois casos, o sistema pode destruir as activities "pedindo" para elas finalizarem ou, simplesmente, matando seus processos. Quando elas são apresentadas novamente para o usuário, elas precisam ser completamente reiniciadas e restauradas aos seus estados anteriores.

Ainda nesse diagrama, é possível diferenciar três níveis de ciclo de vida que podem ser analisados e monitorados:
  1. O tempo de vida completo ("entire lifetime"): ocorre desde a primeira chamada ao método "onCreate()" até a chamada do método "onDestroy()".
  2. O tempo de vida visível ("visible lifetime"): ocorre entre uma chamada do método "onStart" e a chamada correspondente do método "onStop()".
  3. O tempo de vida no topo da pilha ("foreground lifetime"): ocorre  entre uma chamada do método "onResume" e a chamada correspondente do método "onPause()".

Dentro do primeiro nível, pode-se enfatizar que uma Activity fará a configuração de todo seu "estado global" dentro do método "onCreate()", e liberá todos os recursos remanescentes no método "onDestroy()". Por exemplo, pode-se criar uma thread para fazer download de dados em backgroud no primeiro método e destruí-la no segundo método.

Dentro do segundo nível, pode-se manter recursos que são necessários ao mostrar a atividade ao usuário. Por exemplo, pode-se registrar um BroadcastReceiver dentro do método "onStart()", para monitorar as mudanças que impactam na GUI, e desregistrá-lo no método "onStop()", quando a tela não está mais visível par ao usuário.

Já dentro do terceiro nível, normalmente se inclui um código leve, já que uma atividade pode alterar frequentemente seu estado entre "resumed" e "paused" - por exemplo, quando o aparelho "dorme" (ao ficar um certo tempo parado), quando o resultado de uma Activity é disponibilizado ou quando um novo Intent é disponibilizado.


Executando uma Activity

Quando uma aplicação Android é executada, a Activity definida como padrão na configuração do projeto é criada automaticamente. De qualquer forma, no código da aplicação, também é possível criar novas Activities.

Para executar outras Activities, basta usar as funções startActivity() ou startActivityForResult().

O método "startActivity()" espera somente um argumento, um objeto da classe Intent, que descreve a atividade que será executada.

Por exemplo, se na nossa Activity principal ("MainActivity") quisermos, já na sua criação (método "onCreate()"), executar uma segunda Activity ("SecondActivity"), podemos fazer da seguinte forma:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Intent i = new Intent(this, SecondActivity.class);  
        startActivity(i); 
 }

    //continuação do código da classe....
}

O segundo método, "startActivityForResult()", é utilizado quando precisamos obter algum resultado da Activity quando ela terminar (por exemplo, pode-se iniciar uma Activity que permite ao usuário selecionar uma pessoa de uma lista de contatos; e, quando ela finalizar, vai retornar a pessoa que foi selecionada).

Esse método espera dois argumentos: um objeto da classe Intent e um número inteiro (para identificar a chamada). O resultado pode ser então obtido através do método "onActivityResult(int, int, Intent)".

Quando uma Activity é finalizada, ela pode chamar o método "setResult(int)" para retornar dados para sua Activity pai. O número inteiro que é parâmetro desse método é o código que identifica o resultado, podendo ser as constantes "RESULT_CANCELED" e "RESULT_OK", ou valores customizados.

Além disso, pode-se retornar um objeto "Intent", contendo qualquer informação desejada. Além do código identificador e do "Intent", o método "onActivityResult" vai receber, na Activity pai, o outro número inteiro que foi fornecido na criação da Activity filha.

DICA: Se uma Activity filha falha, por qualquer razão, a atividade pai recebe um resultado com o código identificado pela constante "RESULT_CANCELED".


No exemplo abaixo, é lançada uma segunda Activity a partir da principal, esperando-se um resultado dela.

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;

public class MainActivity extends Activity {

 static final int PICK_CONTACT_REQUEST = 0;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Intent i = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
        startActivityForResult(i, PICK_CONTACT_REQUEST);
 }
    
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PICK_CONTACT_REQUEST) {
            if (resultCode == RESULT_OK) {
             //...
            }
        }
    }

    //continuação do código da classe....
}


Referências bibliográficas: grande parte dessas informações foram tiradas da documentação de referência da plataforma Android, sendo feita uma seleção, tradução, interpretação, organização e complementação com outras informações.