Importação de Banco de Dados Externo em Android
No desenvolvimento Android, não é possível acessar diretamente um arquivo de banco de dados no diretório res/raw. Em vez disso, é necessário copiar o arquivo para o armazenamento interno ou SD card durante a primeira execução do aplicativo, e então abri-lo a partir desse local. O processo envolve obter um InputStream do recurso usando getResources().openRawResource(), e gravar os dados em outro diretório. O método SQLiteDatabase.openOrCreateDatabase() pode ser utilizado para abrir bancos de dados SQLite em qualquer caminho.
Normalmente, aplicativos Android criam um banco de dados vazio no início e realizam operações subsequentes. Para usar um banco de dados pré-existente, ele deve ser copiado para o diretório do aplicativo em /data/data/com.exemplo.pacote/. Isso é feito lendo o banco original com FileInputStream e escrevendo-o usando FileOutputStream. Um exemplo de implementação envolve criar uma classe gerenciadora:
package com.example.gestao.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.util.Log;
import java.io.*;
public class GestorBD {
private static final String NOME_BD = "paises.db";
private static final String PACOTE = "com.example.gestao.db";
private static final String CAMHO_BD = Environment.getDataDirectory().getAbsolutePath() + "/data/" + PACOTE;
private final Context contexto;
public GestorBD(Context ctx) {
this.contexto = ctx;
}
public SQLiteDatabase abrirBD() {
String caminhoCompleto = CAMHO_BD + "/" + NOME_BD;
File arquivoBD = new File(caminhoCompleto);
if (!arquivoBD.exists()) {
try (InputStream entrada = contexto.getResources().openRawResource(R.raw.paises);
OutputStream saida = new FileOutputStream(arquivoBD)) {
byte[] buffer = new byte[4096];
int bytesLidos;
while ((bytesLidos = entrada.read(buffer)) > 0) {
saida.write(buffer, 0, bytesLidos);
}
} catch (IOException e) {
Log.e("BD", "Erro ao copiar banco de dados", e);
return null;
}
}
return SQLiteDatabase.openOrCreateDatabase(caminhoCompleto, null);
}
}
Componentes Personalizados em Android
O desenvolvimento de componentes personalizados segue etapas específicas, incluindo entender o ciclo de vida das Views, criar subclasses, adicionar atributos, desenhar o componente e responedr a interações. A estrutura de Views no Android utiliza o padrão Composite, onde View é a classe base e ViewGroup atua como contêiner.
As operações fundamentais de desenho envolvem três métodos: measure(), layout() e draw(), que por sua vez chamam onMeasure(), onLayout() e onDraw(). Para criar um componente personalizado, é comum sobrescrever onMeasure() e onDraw(). Exemplo básico:
public class MeuComponente extends View {
private String texto;
public MeuComponente(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MeuComponente);
texto = a.getString(R.styleable.MeuComponente_texto);
a.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawText(texto, 50, 50, paint);
}
}
Atributos podem ser definidos via XML usando um arquivo attrs.xml no diretório res/values.
Integração com VMware para Desenvolvimento Android
Para executar o ambiente Android em uma máquina virtual, é necessário configurar o VirtualBox com uma imagem ISO do Android x86. O processo inclui criar uma nova VM, alocar memória e armazenamento, e instalar o sistema operacional a partir da ISO. Após a instalação, o Android pode ser inicializado na VM.
Frameworks de Código Aberto Populares para Android
Diversos frameworks de código aberto simplificam o desenvolvimento Android, como bibliotecas para rede, banco de dados e gerenciamento de dependências. Consulte repositórios como GitHub para lista atualizada.
Serviços em Segundo Plano no Android
Serviços Android podem ser encerrados pelo sistema quando há pressão na memória. Para manter um serviço rodando em segundo plano, pode-se utilizar um serviço em primeiro plano com uma notificação. Exemplo de implementação:
private void iniciarServicoPrimeiroPlano() {
Intent intent = new Intent(this, MeuServico.class);
Notification notification = new NotificationCompat.Builder(this, "canal_id")
.setSmallIcon(R.drawable.icone)
.setContentTitle("Serviço Ativo")
.build();
startForeground(1, notification);
startService(intent);
}
Para evitar que o aplicativo seja encerrado ao retornar à tela inicial, técnicas como o uso de singleTask launch mode e verificação de flags na onCreate podem ser aplicadas.
Comunicação via Bluetooth Low Energy (BLE)
O desenvolvimento com BLE envolve conceitos como GATT, ATT, Characteristics e Services. O Android atua como dispositivo central, conectando-se a periféricos BLE. Exemplo de busca por dispositivos:
BluetoothAdapter adaptador = BluetoothAdapter.getDefaultAdapter();
adaptador.startLeScan(new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
// Processar dispositivo encontrado
}
});
A conexão com um GATT Server é feita via connectGatt(), e a comunicação é gerida por callbacks como onConnectionStateChange e onCharacteristicRead.
Sistemas de Notificação Push
Existem várias abordagens para implementar notificações push, incluindo polling, SMS e conexões persistentes. Bibliotecas como Firebase Cloud Messaging (FCM) são recomendadas para notificações em tempo real.
Desempenho e Diagnóstico
Ferramentas como Hierarchy Viewer e Memory Monitor ajudam a identificar problemas de desempenho, como overdraw e memory leaks. O overdraw ocorre quando pixels são desenhados múltiplas vezes, e pode ser detectado nas opções de desanvolvedor.
Instalação Silenciosa de Aplicativos
A instalação silenciosa requer permissões elevadas (ROOT) ou uso de serviços de acessibilidade. Com ROOT, é possível usar o comando pm install via processo su. Sem ROOT, pode-se simular cliques na interface de instalação usando um AccessibilityService.
Uso da Biblioteca xUtils
xUtils simplifica tarefas como injeção de dependências, carregamento de imagens e operações com banco de dados. Exemplo de uso do IoC:
@ContentView(R.layout.activity_principal)
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.botao)
private Button meuBotao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
}
@Event(R.id.botao)
private void aoClicarBotao(View v) {
// Ação do botão
}
}
Gerenciamento de Estado em Activities
Dados podem ser passados entre Activities via Intent e recuperados em onCreate(). Para persistência durante mudanças de configuração, utilize onSaveInstanceState() e onRestoreInstanceState(). Exemplo:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("chave", "valor");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String valor = savedInstanceState.getString("chave");
}
Diálogos em Modo Tela Cheia
Para manter o modo tela cheia ao exibir diálogos, é necessário configurar a janela do diálogo de forma semelhante à Activity. Isso envolve definir flags como SYSTEM_UI_FLAG_FULLSCREEN no decorView do diálogo.