Por que eu devo ler este artigo:Este artigo apresenta uma introdução ao Android Native Development Kit – NDK, permitindo a você tirar o máximo de proveito do dispositivo em aplicações que consomem muitos recursos de CPU ou que precisam aproveitar um hardware específico. Para muitas aplicações, o desempenho obtido com o desenvolvimento baseado apenas no Android Software Development Kit – SDK pode não ser satisfatório. Nestes casos, o uso do NDK contribui para que a aplicação atenda aos requisitos de desempenho desejados.
Autores: Leandro Luque e Eron Silva

O mercado de dispositivos móveis cresce em ritmo acelerado no Brasil e no mundo. Esse crescimento, aliado à maior capacidade dos dispositivos móveis, está impulsionando a demanda por aplicações e jogos cada vez mais complexos, rápidos e interativos.

Isto pode ser facilmente percebido pelo volume de jogos com alta complexidade gráfica que vêm sendo comercializados e também por aplicações baseadas em processamento de imagens e realidade aumentada que possibilitam a tradução simultânea de imagens com textos em outros idiomas (exemplo: Word Lens e CamTranslator), a pesquisa por informações baseada em imagens (exemplo: Google Goggles), a simulação de mobílias em ambientes a partir de imagens da câmera (exemplo: Home Design 3D), entre muitas outras.

Para muitas das aplicações citadas, o desempenho obtido com o desenvolvimento baseado apenas no Android Software Development Kit – SDK pode não ser satisfatório. Nestes casos, o uso do Android Native Development Kit – NDK contribui para que a aplicação atenda aos requisitos de desempenho desejados.

Neste contexto, este artigo apresenta o NDK e como ele pode ser integrado ao SDK para que você possa tirar o máximo de proveito do dispositivo em aplicações que consomem muitos recursos de CPU ou que precisam aproveitar um hardware específico. Será utilizada uma aplicação exemplo, desenvolvida e comentada passo a passo para esclarecer as etapas necessárias para atingir o objetivo proposto.

Integração de Aplicações Java com Código Nativo

Existem duas alternativas principais para a integração de aplicações Java, não apenas móveis, com código nativo. A primeira delas envolve a criação de processos do sistema operacional para a execução do código nativo. Uma forma de fazer isso é por meio da classe ProcessBuilder, disponível a partir do Java 5 (Listagem 1).

O código apresentado nesta listagem é autoexplicativo e permite a recuperação da saída padrão produzida pelo comando cmd /c dir /ad, executado na pasta raiz – para sistemas Windows.

Esse mesmo recurso poderia ser utilizado para executar um código nativo que realiza um cálculo matemático, por exemplo. Entre outras formas, a recuperação do resultado poderia ser feita a partir da saída padrão, como no exemplo apresentado, ou mesmo por meio de arquivos – o código nativo gravaria um arquivo como saída e o código Java realizaria a leitura deste arquivo e recuperaria o resultado.

Listagem 1. Exemplo de código que executa o comando cmd /c dir /ad e exibe as subpastas da pasta raiz (para sistemas Windows).


  // ... package e imports
   
  public class TesteProcessBuilder {
      public static void main(String[] args) {
          // Comando que será executado: cmd /c dir /ad
          // A array contém em ordem: comando parâmetro1 parâmetro2 ...
          String[] comando = {"cmd", "/c", "dir", "/ad"};
          // Cria um construtor de processo.
          ProcessBuilder construtorProcesso = new ProcessBuilder(comando);
          // Pasta de trabalho relacionada ao comando (raiz).
          construtorProcesso.directory(new File("c:\\"));
          try {
              // Tenta iniciar o processo.
              Process processo = construtorProcesso.start();
              // Aguarda a finalização do processo.
              processo.waitFor();
              // Lê a saída do comando.
              BufferedReader in = new BufferedReader(new 
               InputStreamReader(processo.getInputStream()));
              System.out.println("Saída do comando: cmd /c dir /ad");
              String saida;
              while ((saida = in.readLine()) != null) {
                  System.out.println(saida);
              }
          } catch (IOException erro) {
              System.out.println("Sentimos muito. 
               Ocorreu um erro durante a execução do programa.");
              // ...
          } catch (InterruptedException erro) {
              System.out.println("Sentimos muito. 
               Ocorreu um erro durante a execução do programa.");
              // ...
          }
      }
  }

Existem algumas implicações relacionadas a esta abordagem. Uma delas é a necessidade do código nativo ser executável na plataforma em questão. Outra está relacionada à comunicação, que geralmente envolverá o processamento de textos e conversões. Ainda, não sendo possível acessar diretamente variáveis e métodos da máquina virtual do Java, as informações que o método nativo necessita devem ser fornecidas previamente via parâmetros ou arquivos.

A outra abordagem envolve o uso da JNI – Java Native Interface, um padrão que permite que bibliotecas, não código executável, sejam integradas ao código Java. É por meio dela que aplicações Android NDK conseguem executar códigos implementados em C/C++.

Diferentemente da outra abordagem, a JNI possibilita a interação direta com a máquina virtual do Java, não apresentando as implicações citadas. A seguir, ela será descrita mais detalhadamente.

Java Native Interface – JNI

Para utilizar a Java Native Interface – JNI em um projeto, além de o código nativo ter que ser escrito seguindo algumas convenções, a biblioteca onde o código nativo se encontra deve ser carregada no código Java, onde também devem ser escritas as assinaturas dos métodos nativos.

Por fim, basta invocar os métodos cujas assinaturas foram definidas e o código nativo será automaticamente executado. A seguir, cada uma destas etapas e alguns deta ...

Quer ler esse conteúdo completo? Tenha acesso completo