Visão rápida do armazenamento
- Use preferências compartilhadas para dados primitivos
- Use o armazenamento interno do dispositivo para dados privados
- Use o armazenamento externo para conjuntos de dados grandes que não são privados
- Use bancos de dados SQLite para armazenamento estruturado
Neste documento
- Como usar preferências compartilhadas
- Como usar armazenamento interno
- Como usar armazenamento externo
- Como usar bancos de dados
- Como usar conexões de rede
Veja também
O Android oferece várias opções para salvar dados de aplicativos de forma persistente. A solução escolhida depende das necessidades especificas, como se os dados devem ser privados para o aplicativo ou acessíveis para outros aplicativos (e o usuário) e quanto espaço é necessário para os dados.
As opções de armazenamento de dados são:
- Preferências compartilhadas
- Armazene dados primitivos privados em pares chave-valor.
- Armazenamento interno
- Armazene dados privados na memória do dispositivo.
- Armazenamento externo
- Armazena dados públicos no armazenamento externo compartilhado.
- Bancos de dados SQLite
- Armazene dados estruturados em um banco de dados privado.
- Conexão de rede
- Armazene dados na web com o seu próprio servidor de rede.
O Android permite expor até seus dados privados para outros aplicativos — com um provedor de conteúdo. Um provedor de conteúdo é um componente opcional que expõe acesso de leitura/gravação para dados do aplicativo, respeitando as restrições que você definir. Para obter mais instruções sobre o uso de provedores de conteúdo, consulte a documentação Provedores de conteúdo.
Como usar preferências compartilhadas
A classe SharedPreferences oferece uma estrutura de trabalho geral que permite
salvar e recuperar pares persistentes chave-valor de tipos de dados primitivos. Você pode usar SharedPreferences para salvar qualquer dado primitivo: booleanos, flutuantes, inteiros, longos
e strings. Esses dados persistirão entre sessões do usuário (mesmo se o aplicativo for eliminado).
Preferências do usuário
As preferências compartilhadas não são exclusivamente para salvar “preferências do usuário”, como o toque
escolhido por ele. Se você está interessado na criação de preferências do usuário para o aplicativo, consulte PreferenceActivity, que oferece uma estrutura de trabalho Activity para a criação
de preferências do usuário persistidas automaticamente (usando preferências compartilhadas).
Para obter um objeto SharedPreferences para o aplicativo, use um destes
dois métodos:
getSharedPreferences()— use esse método se precisar de vários arquivos de preferência, identificados por nome e especificados no primeiro parâmetro.getPreferences()— use esse método se precisar de apenas um arquivo de preferência para a Activity. Como esse será o único arquivo de preferências para a Activity, o nome não é fornecido.
Para gravar valores:
- Chame
edit()para obter umSharedPreferences.Editor. - Adicione valores com métodos como
putBoolean()eputString(). - Confirme os novos valores com
commit()
Para ler valores, use métodos de SharedPreferences como getBoolean() e getString().
Veja a seguir um exemplo que salva uma preferência para o modo de pressionamento de tela silencioso em uma calculadora:
public class Calc extends Activity {
public static final String PREFS_NAME = "MyPrefsFile";
@Override
protected void onCreate(Bundle state){
super.onCreate(state);
. . .
// Restore preferences
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean("silentMode", false);
setSilent(silent);
}
@Override
protected void onStop(){
super.onStop();
// We need an Editor object to make preference changes.
// All objects are from android.context.Context
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("silentMode", mSilentMode);
// Commit the edits!
editor.commit();
}
}
Como usar armazenamento interno
É possível salvar arquivos diretamente no armazenamento interno do dispositivo. Por padrão, os arquivos salvos no armazenamento interno são privados do aplicativo e não podem ser acessados por outros aplicativo (nem pelo usuário). Quando o usuário desinstalar o aplicativo, esses arquivos serão removidos.
Para criar e gravar um arquivo privado no armazenamento interno:
- Chame
openFileOutput()com o nome do arquivo e o modo operacional. Isso retorna umFileOutputStream. - Grave no arquivo com
write(). - Feche o stream com
close().
Por exemplo:
String FILENAME = "hello_file"; String string = "hello world!"; FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close();
MODE_PRIVATE cria o arquivo (ou substitui um arquivo
de mesmo nome) e o torna privado para o aplicativo. Os outros modos disponíveis são: MODE_APPEND, MODE_WORLD_READABLE e MODE_WORLD_WRITEABLE.
Observação: As constantes MODE_WORLD_READABLE e MODE_WORLD_WRITEABLE estão obsoletas desde a API de nível 17.
A partir do Android N, se usadas, acionarão uma SecurityException.
Isso significa
que aplicativos direcionados ao Android N ou versão posterior
não poderão compartilhar arquivos privados por nome, e tentativas de compartilhar um URI “file://” acionarão
uma FileUriExposedException. Se o aplicativo precisar compartilhar arquivos
privados com outros aplicativos, poderá usar um FileProvider com
FLAG_GRANT_READ_URI_PERMISSION.
Consulte também Compartilhamento de arquivos.
Para ler um arquivo no armazenamento interno:
- Chame
openFileInput()e passe o nome do arquivo a ler. Isso retorna umFileInputStream. - Leia bytes do arquivo com
read(). - E feche o stream com
close().
Dica: Se você quiser salvar um arquivo estático no aplicativo durante
a compilação, salve o arquivo no diretório res/raw/ do projeto. Você pode abri-lo
com openRawResource(), passando o
ID de recurso R.raw.<filename>. Esse método retorna um InputStream
que pode ser usado para ler o arquivo (mas não é possível gravar no arquivo original).
Salvar arquivos de cache
Se você quiser armazenar dados em cache, em vez de armazená-los de forma persistente, use getCacheDir() para abrir um File que representa o diretório interno onde o aplicativo deve salvar
arquivos de cache temporários.
Quando houver pouco espaço de armazenamento interno no dispositivo, o Android poderá excluir esses arquivos de cache para liberar espaço. No entanto, não dependa do sistema para limpar esses arquivos. Mantenha sempre você mesmo os arquivos de cache e respeite um limite razoável de espaço consumido — como 1 MB. Quando o usuário desinstalar o aplicativo, esses arquivos serão removidos.
Outros métodos úteis
getFilesDir()- Obtém o caminho absoluto do diretório do sistema de arquivos onde os arquivos internos são salvos.
getDir()- Cria um diretório (ou abre um diretório existente) no espaço de armazenamento interno.
deleteFile()- Exclui um arquivo salvo no armazenamento interno.
fileList()- Retorna uma matriz dos arquivos salvos pelo aplicativo nesse momento.
Como usar armazenamento externo
Todo dispositivo compatível com Android permite um “armazenamento externo” compartilhado que pode ser usado para salvar arquivos. Esse armazenamento pode ser uma mídia de armazenamento removível (como um cartão SD) ou um armazenamento interno (não removível). Os arquivos salvos no armazenamento externo podem ser lidos por todos e modificados pelo usuário quando o armazenamento em massa de USB é ativado para transferir arquivos para um computador.
Atenção: O armazenamento externo poderá ficar indisponível se o usuário montar o armazenamento externo em um computador ou remover a mídia. Não é aplicada nenhuma segurança nos arquivos salvos no armazenamento externo. Todos os aplicativos podem ler e gravar arquivos colocados no armazenamento externo e o usuário pode removê-los.
Uso do acesso a diretórios com escopo
No Android 7.0 ou versão posterior, se for necessário acessar um diretório específico no armazenamento externo, use o acesso a diretórios com escopo. O acesso a diretórios com escopo simplifica a forma com que o aplicativo acessa diretórios de armazenamento externo padrão, como o diretórioPictures, e oferece uma IU de permissões
simples que detalha claramente a qual diretório o aplicativo
está solicitando acesso. Para obter mais detalhes sobre o acesso a diretórios com escopo, consulte
Uso
do acesso a diretórios com escopo.
Obter acesso ao armazenamento externo
Para ler ou gravar arquivos no armazenamento externo, o aplicativo deve adquirir as permissões de sistema
READ_EXTERNAL_STORAGE
ou WRITE_EXTERNAL_STORAGE.
Por exemplo:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
Se você precisar ler e gravar arquivos, solicite apenas a
permissão WRITE_EXTERNAL_STORAGE porque ela
exige implicitamente o acesso de leitura.
Observação: A partir do Android 4.4, essas permissões não são necessárias para ler ou gravar apenas arquivos privados do aplicativo. Para obter mais informações, consulte a seção abaixo sobre salvar arquivos privados do aplicativo.
Verificar disponibilidade da mídia
Antes de executar qualquer trabalho com o armazenamento externo, chame sempre getExternalStorageState() para verificar se a mídia está disponível. A
mídia pode estar montada em um computador, ausente, somente para leitura ou em algum outro estado. Por exemplo,
veja a seguir alguns métodos que podem ser usados para verificar a disponibilidade:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
O método getExternalStorageState() retorna outros estados que você pode
verificar, como se a mídia está sendo compartilhada (conectada a um computador), se não está
presente, se foi removida incorretamente etc. Use esses estados para notificar o usuário com mais informações
quando o aplicativo precisar acessar a mídia.
Salvar arquivos que podem ser compartilhados com outros aplicativos
Ocultar os arquivos do detector de mídia
Inclua um arquivo vazio denominado .nomedia no diretório de arquivos externos (observe o ponto
como prefixo no nome do arquivo). Isso evita que o detector de mídia leia seus arquivos
de mídia e os ofereça a outros aplicativos por meio do provedor
de conteúdo MediaStore. No entanto, se os arquivos realmente forem privados para o aplicativo, você deverá
salvá-los em um diretório privado do aplicativo.
Normalmente, arquivos novos adquiridos pelo usuário por meio do aplicativo devem ser salvos em um local
“público” no dispositivo, acessíveis por outros aplicativos e facilmente copiáveis do dispositivo
pelo usuário. Para fazer isso, use um dos diretórios públicos compartilhados, como Music/, Pictures/ e Ringtones/.
Para obter um File representando o diretório público adequado, chame getExternalStoragePublicDirectory(), passando o tipo de diretório desejado, como
DIRECTORY_MUSIC, DIRECTORY_PICTURES,
DIRECTORY_RINGTONES ou outros. Salvar os arquivos no
diretório de tipo de mídia correspondente
permite que o detector de mídia do sistema categorize adequadamente os arquivos no sistema (por
exemplo, os toques aparecem nas configurações de sistema como toques e não como música).
Por exemplo, veja a seguir um método que cria um diretório para um novo álbum de fotografias no diretório público de fotos:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
Salvar arquivos privados do aplicativo
Se você estiver processando arquivos que não devem ser usados por outros aplicativos
(como texturas gráficas ou efeitos sonoros usados apenas pelo seu aplicativo), use
um diretório de armazenamento privado no armazenamento externo chamando getExternalFilesDir().
Esse método também recebe um argumento type para definir o tipo do subdiretório
(como DIRECTORY_MOVIES). Se você não precisar de um diretório
de mídia específico, passe null para receber
o diretório raiz do diretório privado do aplicativo.
A partir do Android 4.4, a leitura ou gravação de arquivos nos diretórios
privados do aplicativo não exigem as permissões READ_EXTERNAL_STORAGE
ou WRITE_EXTERNAL_STORAGE.
Portanto, você pode declarar que a permissão deve ser solicitada penas nas versões anteriores
do Android, adicionando o atributo maxSdkVersion:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
</manifest>
Observação:
quando o usuário desinstala o aplicativo, esse diretório e todo o seu conteúdo é excluído.
Além disso, o detector de mídia do sistema não lê arquivos nesses diretórios, o que significa que eles não podem ser acessados
pelo provedor de conteúdo MediaStore. Desse modo, não
use esses diretórios para mídia que, essencialmente, pertence ao usuário, como fotos
capturadas ou editadas pelo aplicativo ou música comprada pelo usuário usando o aplicativo — esses
arquivos devem ser salvos nos diretórios públicos.
Algumas vezes, um dispositivo que alocou uma partição da
memória interna para uso como armazenamento externo também pode oferecer um slot de cartão SD.
Quando esse dispositivo executa o Android 4.3 ou versões anteriores, o método getExternalFilesDir() oferece
acesso apenas à partição interna e o aplicativo não consegue ler ou gravar o cartão SD.
No entanto, a partir do Android 4.4, é possível acessar os dois locais chamando
getExternalFilesDirs(),
que retorna uma matriz de File com uma entrada para cada local. A primeira entrada na matriz é considerada
o armazenamento externo principal e o local a ser usado, a menos que esteja cheio ou
indisponível. Se você quiser acessar os locais possíveis, sem deixar de ser compatível com o Android
4.3 ou anterior, use o método estático
ContextCompat.getExternalFilesDirs() da biblioteca de suporte. Esse método também retorna uma matriz de File, mas contém sempre apenas uma entrada no Android 4.3 e anteriores.
Atenção: embora os diretórios fornecidos por getExternalFilesDir() e getExternalFilesDirs() não sejam acessíveis pelo
provedor de conteúdo MediaStore, outros aplicativos com a permissão READ_EXTERNAL_STORAGE podem acessar todos os arquivos no armazenamento
externo, inclusive os fornecidos por esses dois métodos. Se você precisar restringir completamente o acesso a seus arquivos,
grave-os no armazenamento interno.
Salvar arquivos de cache
Para abrir um File que represente o
diretório de armazenamento externo onde você deve salvar arquivos de cache, chame getExternalCacheDir(). Se o usuário desinstalar o
aplicativo, esses arquivos serão automaticamente excluídos.
De forma semelhante a ContextCompat.getExternalFilesDirs(), mencionado acima, também é possível acessar um diretório de cache em
um armazenamento externo secundário (se disponível) chamando
ContextCompat.getExternalCacheDirs().
Dica: para preservar o espaço de arquivos e manter o desempenho do aplicativo, é importante gerenciar cuidadosamente os arquivos de cache durante todo o ciclo de vida do aplicativo, removendo os que não forem mais necessários.
Como usar bancos de dados
O Android é totalmente compatível com bancos de dados SQLite. Todos os bancos de dados criados poderão ser acessados pelo nome em qualquer classe do aplicativo, mas não fora dele.
O método recomendado para criar um novo banco de dados SQLite é criar uma subclasse de SQLiteOpenHelper e modificar o método onCreate(), em que é possível
executar um comando SQLite para criar tabelas no banco de dados. Por exemplo:
public class DictionaryOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String DICTIONARY_TABLE_NAME = "dictionary";
private static final String DICTIONARY_TABLE_CREATE =
"CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
KEY_WORD + " TEXT, " +
KEY_DEFINITION + " TEXT);";
DictionaryOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DICTIONARY_TABLE_CREATE);
}
}
É possível obter uma instância da sua implementação de SQLiteOpenHelper
usando o construtor que você definiu. Para gravar e ler no banco de dados, chame respectivamente
getWritableDatabase() e getReadableDatabase(). Os dois métodos retornam um objeto
SQLiteDatabase que representa o banco de dados e
fornece métodos para operações do SQLite.
O Android não impõe nenhum limite além dos conceitos padrão do SQLite. Recomendamos
incluir um campo-chave de valor incrementado automaticamente que seja usado como ID único
para encontrar rapidamente um registro. Isso não é necessário para dados privados, mas se você
implementar um provedor de conteúdo,
deverá incluir um ID único usando a constante BaseColumns._ID.
Você pode executar consultas do SQLite usando os métodos de
query() de SQLiteDatabase, que aceitam vários parâmetros de consulta, como tabela a consultar,
projeção, seleção, colunas e agrupamento, entre outros. Para consultas complexas, como as
que exigem aliases de coluna, use
SQLiteQueryBuilder, que fornece
vários métodos convenientes para a criação de consultas.
Toda consulta do SQLite retorna um Cursor, que aponta para as linhas
encontradas pela consulta. O Cursor é sempre o mecanismo usado
para navegar pelos resultados de uma consulta de banco de dados e ler linhas e colunas.
Para obter aplicativos de amostra, que demonstram como usar bancos de dados SQLite no Android, consulte os aplicativos Note Pad e Searchable Dictionary.
Depuração de bancos de dados
O Android SDK contém uma ferramenta de banco de dados sqlite3 que permite navegar
pelo conteúdo de tabelas e executar comandos do SQL e outras funções úteis em bancos de dados
SQLite. Consulte Examinar bancos de dados
sqlite3 de um shell remoto para saber como executar essa ferramenta.
Como usar conexões de rede
Você pode usar a rede (se disponível) para armazenar e recuperar dados em seus próprios serviços baseados na Web. Para executar operações de rede, use as classes dos seguintes pacotes: