Opções de armazenamento no Android (Tradução da documentação oficial)

O Android fornece diversas opções para que você salve dados persistentes da aplicação. A solução que você escolher depende da sua necessidade, como se os dados devem ser privativos da sua aplicação ou acessível a outras aplicações (e ao usuário) e quanto espaço seus dados necessitam.

Suas opções de armazenamento de dados são as seguintes:

Preferências compartilhadas
Armazena dados primitivos em pares chave-valor.
Armazenamento interno
Armazena dados privativos na memória do dispositivo.
Armazenamento externo
Armazena dados públicos na mídia de armazenamento externo.
Banco de dados SQLite
Armazena dados estruturados em um banco de dados privativo.
Conexão de rede
Armazena dados na web com seu próprio servidor de rede.

O Android fornece uma maneira para que você exponha seus dados privativos para outras aplicações – com um content provider. Um content provider é um componente opcional que permite acesso para leitura/escrita para sua aplicação, sujeito a qualquer restrições que você quiser impor. Para mais informações sobre o uso de content providers, veja o artigo Content Providers.

Usando Preferências compartilhadas


A classe SharedPreferences fornece um framework genérico que permite que você salve e recupere pares chave-valor persistentes. Você pode usar SharedPreferences para salvar qualquer dado primitivo: booleano, ponto flutuante, inteiros, inteiros longos, e strings. Esses dados irão persistir em todas as sessões do usuário (mesmo se a aplicação for terminada).

Preferências do usuário

Preferências compartilhadas não são estritamente para salvar “preferências com o usuário”, como qual ringtone o usuário escolhe. Se você estiver interessado em criar preferências para sua aplicação, veja PreferenceActivity, que fornece uma Activity para que você crie preferências, que serão automaticamente salvas.

Para obter um objeto SharedPreferences em sua aplicação, use um dos métodos abaixo:

  • getSharedPreferences() – Use esse método se você precisar de múltiplos arquivos de preferências identificados pelo nome, que você especifica pelo primeiro parâmetro.
  • getPreferences() – Use esse método se você precisa de apenas um arquivo de preferências para sua Activity. Por esse ser o único arquivo da Activity, você não precisa informar o nome.

Para escrever valores:

  1. Chame edit() para obter um SharedPreferences.Editor.
  2. Adicione valores com os métodos apropriados, como putBoolean() e putString().
  3. Finalize a adição dos novos valores com commit()

Para ler valores, use os métodos getBoolean() e getString()de SharedPreferences.

Abaixo segue um exemplo que salva uma preferência para ativar o modo de teclas silenciosas em uma calculadores:

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();
    }
}

Usando o armazenamento interno


Você pode salvar arquivos diretamente na memória interna do dispositivo. Por padrão, arquivos salvos na memória interna são privativos da aplicação e outras aplicações não podem acessa-los (nem o usuário). Quando o usuário desinstala a aplicação, esses dados são removidos.

Para criar e escrever um arquivo na memória interna:

  1. Chame openFileOutput() como o nome do arquivo e o modo de operação. Esse método retornará um FileOutputStream.
  2. Escreva no arquivo com write().
  3. 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  criará o arquivo (ou substituirá um arquivo do mesmo nome) e o tornará privativo de sua aplicação. Outros modos disponíveis são: MODE_APPENDMODE_WORLD_READABLE, e MODE_WORLD_WRITEABLE.

Para ler um arquivo da memória interna:

  1. Chame openFileInput() e passe o nome do arquivo a ser lido. Esse método retornará um FIleInputStream.
  2. Leia bytes do arquivo com read().
  3. Feche o stream com close().

Dica: Se você quiser salvar um arquivo estático junto com sua aplicação durante a compilação, salve o arquivo no diretório res/raw/ de seu projeto. Você pode abri-lo com o método openRawResource(), passando o ID de recurso R.raw.<filename> . Esse método retorna um InputStream que você pode usar para ler o arquivo (mas não pode escrever no arquivo original).

Salvando arquivos de cache

Se você quiser salvar alguns dados em cache, ao invés de armazena-los de forma persistente, você deve usar getCacheDir() para abrir um File que representa o diretório interno onde sua aplicação deve salvar os arquivos temporários de cache.

Quando o dispositivo estiver com pouco espaço de armazenamento interno, o Android pode apagar esses arquvios de cache para obter mais espaço. Porém, você não deve contar apenas com o sistema para limpar esses arquivos para você. Você deve sempre manter você mesmo os arquivos de cache e deixa-los dentro de um limite razoável de espaço, algo em torno de 1MB. Quando o usuário desinstala a aplicação, esses arquivos são removidos.

Outros métodos úteis

getFilesDir()
Obtém o caminho absoluto do diretório onde os arquivo são armazenados na memória interna.
getDir()
Cria (ou abre caso exista) um diretório na memória interna do dispositivo.
deleteFile()
Apaga um arquivo salvo na memória interna.
fileList()
Retorna um array de arquivo que foram salvos pela sua aplicação.

Usando o armazenamento externo


Todo dispositivo compatível com o Android suporta armazenamento externo compartilhado que você pode usar para salvar arquivos. Isso pode ser tanto uma mídia removível (como um cartão SD) quanto uma mídia interna (não removível). Os arquivos salvos no armazenamento externo são lidos por todos e podem ser modificados pelo usuário quando ele ativar o armazenamento USB para transferir arquivos com o computador.

Cuidado: Arquivos externos podem desaparecer se o usuário montar o dispositivo em um computador ou remover a mídia, e não existe nenhuma trava de segurança sobre os arquivos salvos na mídia externa. Todas as aplicações podem ler e escrever arquivos na mídia de armazenamento externo e o usuário pode remove-la.

Verificando a disponibilidade da mídia

Antes de você executar qualquer tarefa com o armazenamento externo, deve sempre chamar getExternalStorageState() para verificar se a mídia está disponível. A mídia pode  estar montada em um computador, ausente, apenas leitura, ou em algum outro estado. Por exemplo, abaixo segue a maneira de verificar a disponibilidade da mídia:

boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();

if (Environment.MEDIA_MOUNTED.equals(state)) {
    // We can read and write the media
    mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    // We can only read the media
    mExternalStorageAvailable = true;
    mExternalStorageWriteable = false;
} else {
    // Something else is wrong. It may be one of many other states, but all we need
    //  to know is we can neither read nor write
    mExternalStorageAvailable = mExternalStorageWriteable = false;
}

Esse exemplo verifica se o armazenamento externo está disponível para leitura e escrita. O método getExternalStorageState() retorna outros estados que você pode querer checar, como se a mídia está sendo compartilhada (conectada a um computador), está ausente, foi removida de forma abrupta, etc. Você pode usar essas opções para notificar o usuário com o máximo de informações necessárias quando a aplicação precisar usar a mídia.

Acessando os arquivos na mídia de armazenamento externo

Se você estiver usando a API Level 8 ou superior, use getExternalFilesDir() para abrir um File que representa o diretório do armazenamento externo onde você deve salvar seus arquivos. Esse método requer um parâmetro type que especifica o tipo de subdiretório onde você quer salvar seus arquivos, como DIRECTORY_MUSIC e DIRECTORY_RINGTONES (passe null para receber a raiz do diretório de arquivos de sua aplicação). Esse método irá criar o diretório apropriado se for necessário. Pela especificação do tipo do diretório, você garante que o scanner de mídia do Android irá categorizar de forma apropriada os seus arquivos no sistema (por exemplo, ringtones serão identificados como ringtone e não como música). Se o usuário desinstalar a aplicação, esse diretório e todo o conteúdo dele será apagado.

Se você estiver usando a API Level 7 ou inferior, use getExternalStorageDirectory(), para abrir um File que representa a raiz do armazenamento externo. Você deve então escrever os dados no seguinte diretório:

/Android/data/<package_name>/files/

<package_name>  é o nome do pacote da sua aplicação, como em “com.example.android.app“. Se o dispositivo do usuário estiver rodando a API Level 8 ou superior e a aplicação for desinstalada, esse diretório e todo o seu conteúdo será apagado.

Salvando arquivos que devem ser compartilhados

Se você quiser salvar arquivos que não sejam específicos da sua aplicação e que não deveriam ser apagados se a sua aplicação for desinstaladas, salve-os em um dos diretórios públicos do armazenamento externo. Esses diretórios estão localizados na raiz da mídia, como em Music/,Pictures/Ringtones/, dentro outro.

No API Level 8 ou superior, use getExternalStoragePublicDirectory(), passando o tipo do diretório público que você quer usar, como DIRECTORY_MUSIC,DIRECTORY_PICTURESDIRECTORY_RINGTONES, dentre outros. Esse método irá criar o diretório apropriado se for necessário.

Se você estiver usando a API Level 7 ou inferior, use getExternalStorageDirectory() para abrir um File que represente a raiz da mídia, e então salve seus arquivos em um dos seguintes diretórios:

  • Music/ – Media scanner classifies all media found here as user music.
  • Podcasts/ – Media scanner classifies all media found here as a podcast.
  • Ringtones/ – Media scanner classifies all media found here as a ringtone.
  • Alarms/ – Media scanner classifies all media found here as an alarm sound.
  • Notifications/ – Media scanner classifies all media found here as a notification sound.
  • Pictures/ – All photos (excluding those taken with the camera).
  • Movies/ – All movies (excluding those taken with the camcorder).
  • Download/ – Miscellaneous downloads.

Usando banco de dados


O Android fornece suporte completo para banco de dados SQLite. Qualquer banco de dados que você criar estará acessível pelo nome a qualquer classe da aplicação, mas não a classes externas a ela.

O método recomendado para criar um novo banco de dados SQLite é criar uma sub-classe de SQLiteOpenHelper e sobrecarregar o método onCreate(), no qual você pode executar um comando SQLite para criar tabelas na base 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);
    }
}

Você pode criar uma instância da sua implementação de SQLiteOpenHelper usando o cosntrutor que você definiu. Para escrever e ler do banco de dados, chame o método getWritableDatabase() e getReadableDatabase(), respectivamente. Esses dois métodos retornam um SQLiteDatabase que representa o banco de dados e fornece métodos para operações SQLite.

O Android não impõe limitações além dos conceitos do padrão SQLite. Recomenda-se incluir um campo chave com auto-incremento para ser usado como Identificador único para encontrar rapidamente um registro. Isso não é necessário para dados privativos, mas se você implementar um content provider, precisa implementar um identificador único usando a constante BaseColumns._ID.

Você pode executar consultas SQLite usando o método SQLiteDatabase query(), que aceita vários parâmetros de consulta, como a tabela a ser consultada, a projeção, seleção, colunas, grupos, etc. Para consultas mais complexas, como aquelas que necessitam de alias de colunas, você deveria usar SQLiteQueryBuilder, que fornece muitos métodos convenientes para a construção de consultas.

Todas as consultas SQLite irão retornar um Cursor que aponta para os campos encontrados pela consulta. O  Cursor sempre será o mecanismo pelo qual você poderá navegar pelos resultados de uma consulta ao banco de dados e ler linhas e colunas.

Para exemplos que demonstram como usar banco de dados SQLite no Android, veja as aplicações Note Pad e Searchable Dictionary.

Usando a conexão de rede


Você pode isar a rede (quando disponível) para armazenar e recuperar dados de seu próprio serviço baseado na web. Para executar operações via rede, use as classes dos seguintes pacotes: