| page.title=Preceitos do provedor de conteúdo |
| @jd:body |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <!-- In this document --> |
| <h2>Neste documento</h2> |
| <ol> |
| <li> |
| <a href="#Basics">Visão geral</a> |
| <ol> |
| <li> |
| <a href="#ClientProvider">Acesso a um provedor</a> |
| </li> |
| <li> |
| <a href="#ContentURIs">URIs de conteúdo</a> |
| </li> |
| </ol> |
| </li> |
| <li> |
| <a href="#SimpleQuery">Recuperação de dados do provedor</a> |
| <ol> |
| <li> |
| <a href="#RequestPermissions">Solicitação de permissão de acesso para leitura</a> |
| </li> |
| <li> |
| <a href="#Query">Construção da consulta</a> |
| </li> |
| <li> |
| <a href="#DisplayResults">Exibição dos resultados da consulta</a> |
| </li> |
| <li> |
| <a href="#GettingResults">Obtenção de dados de resultados da consulta</a> |
| </li> |
| </ol> |
| </li> |
| <li> |
| <a href="#Permissions">Permissões do provedor de conteúdo</a> |
| </li> |
| <li> |
| <a href="#Modifications">Inserção, atualização e exclusão de dados</a> |
| <ol> |
| <li> |
| <a href="#Inserting">Inserção de dados</a> |
| </li> |
| <li> |
| <a href="#Updating">Atualização de dados</a> |
| </li> |
| <li> |
| <a href="#Deleting">Exclusão de dados</a> |
| </li> |
| </ol> |
| </li> |
| <li> |
| <a href="#DataTypes">Tipos de dados do provedor</a> |
| </li> |
| <li> |
| <a href="#AltForms">Formas alternativas de acesso ao provedor</a> |
| <ol> |
| <li> |
| <a href="#Batch">Acesso em lote</a> |
| </li> |
| <li> |
| <a href="#Intents">Acesso a dados via intenções</a> |
| </li> |
| </ol> |
| </li> |
| <li> |
| <a href="#ContractClasses">Classes de contrato</a> |
| </li> |
| <li> |
| <a href="#MIMETypeReference">Referência de tipo MIME</a> |
| </li> |
| </ol> |
| |
| <!-- Key Classes --> |
| <h2>Classes principais</h2> |
| <ol> |
| <li> |
| {@link android.content.ContentProvider} |
| </li> |
| <li> |
| {@link android.content.ContentResolver} |
| </li> |
| <li> |
| {@link android.database.Cursor} |
| </li> |
| <li> |
| {@link android.net.Uri} |
| </li> |
| </ol> |
| |
| <!-- Related Samples --> |
| <h2>Exemplos relacionados</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> |
| Cursor (Pessoas)</a> |
| </li> |
| <li> |
| <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> |
| Cursor (Telefones)</a> |
| </li> |
| </ol> |
| |
| <!-- See also --> |
| <h2>Veja também</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> |
| Criação de um Provedor de conteúdo</a> |
| </li> |
| <li> |
| <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> |
| Provedor de agenda</a> |
| </li> |
| </ol> |
| </div> |
| </div> |
| |
| <!-- Intro paragraphs --> |
| <p> |
| O provedor de conteúdo gerencia o acesso a um repositório central de dados. Um provedor |
| é parte de um aplicativo do Android, que, em geral, fornece a própria IU para trabalhar com |
| os dados. Contudo, provedores de conteúdo destinam-se principalmente ao uso por outros |
| aplicativos, que acessam o provedor usando um objeto cliente do provedor. Juntos, provedores |
| e clientes do provedor oferecem interface padronizada e consistente para dados que também lidam com |
| comunicação em processos internos e garantem acesso a dados. |
| </p> |
| <p> |
| Esse tópico descreve os conceitos básicos do seguinte: |
| </p> |
| <ul> |
| <li>Como os provedores de conteúdo funcionam.</li> |
| <li>A API usada para recuperar dados de um provedor de conteúdo.</li> |
| <li>A API usada para inserir, atualizar ou excluir dados em um provedor de conteúdo.</li> |
| <li>Outros recursos de API que facilitam o trabalho com provedores.</li> |
| </ul> |
| |
| <!-- Basics --> |
| <h2 id="Basics">Visão geral</h2> |
| <p> |
| O provedor de conteúdo apresenta dados a aplicativos externos na forma de uma ou mais tabelas |
| similares às tabelas encontradas em um banco de dados relacional. Uma linha representa uma instância de algum tipo |
| de dados que o provedor coleta e cada coluna na linha representa uma parte individual de |
| dados coletados por uma instância. |
| </p> |
| <p> |
| Por exemplo: um dos provedores embutidos na plataforma do Android é o dicionário do usuário, que |
| armazena as grafias de palavras incomuns que o usuário deseja manter. A tabela 1 ilustra |
| como podem ser os dados nesta tabela do provedor: |
| </p> |
| <p class="table-caption"> |
| <strong>Tabela 1:</strong> Tabela de dicionário do usuário de exemplo. |
| </p> |
| <table id="table1" style="width: 50%;"> |
| <tr> |
| <th style="width:20%" align="center" scope="col">palavra</th> |
| <th style="width:20%" align="center" scope="col">id do aplicativo</th> |
| <th style="width:20%" align="center" scope="col">frequência</th> |
| <th style="width:20%" align="center" scope="col">localidade</th> |
| <th style="width:20%" align="center" scope="col">_ID</th> |
| </tr> |
| <tr> |
| <td align="center" scope="row">reduçãodomapa</td> |
| <td align="center">usuário1</td> |
| <td align="center">100</td> |
| <td align="center">en_US</td> |
| <td align="center">1</td> |
| </tr> |
| <tr> |
| <td align="center" scope="row">pré-compilador</td> |
| <td align="center">usuário14</td> |
| <td align="center">200</td> |
| <td align="center">fr_FR</td> |
| <td align="center">2</td> |
| </tr> |
| <tr> |
| <td align="center" scope="row">applet</td> |
| <td align="center">usuário2</td> |
| <td align="center">225</td> |
| <td align="center">fr_CA</td> |
| <td align="center">3</td> |
| </tr> |
| <tr> |
| <td align="center" scope="row">const</td> |
| <td align="center">usuário1</td> |
| <td align="center">255</td> |
| <td align="center">pt_BR</td> |
| <td align="center">4</td> |
| </tr> |
| <tr> |
| <td align="center" scope="row">int</td> |
| <td align="center">usuário5</td> |
| <td align="center">100</td> |
| <td align="center">en_UK</td> |
| <td align="center">5</td> |
| </tr> |
| </table> |
| <p> |
| Na tabela 1, cada linha representa uma instância de uma palavra que pode não ser |
| encontrada em um dicionário comum. Cada coluna representa alguns dados dessa palavra, como |
| a localidade em que foi encontrada pela primeira vez. Os cabeçalhos da coluna são nomes de coluna armazenados |
| no provedor. Para consultar a localidade de uma linha, consulte a sua coluna <code>locale</code>. Para |
| esse provedor, a coluna <code>_ID</code> serve como uma coluna de "chave principal" que |
| o provedor mantém automaticamente. |
| </p> |
| <p class="note"> |
| <strong>Observação:</strong> os provedores não precisam ter uma chave principal e não precisam |
| usar <code>_ID</code> como o nome de coluna de uma chave principal se uma for apresentada. Contudo, |
| se você deseja agrupar dados de um provedor em um {@link android.widget.ListView}, um dos |
| nomes de coluna deve ser <code>_ID</code>. Esse requisito é explicado com mais detalhes |
| na seção <a href="#DisplayResults">Exibição dos resultados da consulta</a>. |
| </p> |
| <h3 id="ClientProvider">Acesso a um provedor</h3> |
| <p> |
| Os aplicativos acessam dados a partir de um provedor de conteúdo |
| com um objeto cliente {@link android.content.ContentResolver}. Esse objeto tem métodos que chamam |
| métodos de nome idêntico no objeto do provedor, uma instância de uma das subclasses |
| concretas de {@link android.content.ContentProvider}. |
| Os métodos {@link android.content.ContentResolver} fornecem as funções básicas |
| do "CRUD" (criar, recuperar, atualizar e excluir) de armazenamento persistente. |
| </p> |
| <p> |
| O objeto {@link android.content.ContentResolver} no processo do aplicativo |
| cliente e o objeto {@link android.content.ContentProvider} no aplicativo que possui |
| o provedor lidam automaticamente com a comunicação de processos internos. |
| {@link android.content.ContentProvider} também age como uma camada de abstração entre |
| ser repositório de dados e a aparência externa de dados na forma de tabelas. |
| </p> |
| <p class="note"> |
| <strong>Observação:</strong> para acessar um provedor, o aplicativo normalmente precisa solicitar permissões |
| específicas no arquivo de manifesto. Isso é descrito com mais detalhes na seção |
| <a href="#Permissions">Permissões do provedor de conteúdo</a>. |
| </p> |
| <p> |
| Por exemplo: para obter uma lista das palavras e respectivas localidades do Provedor de dicionário do usuário, |
| chama-se {@link android.content.ContentResolver#query ContentResolver.query()}. |
| O método {@link android.content.ContentResolver#query query()} chama |
| o método {@link android.content.ContentProvider#query ContentProvider.query()} definido pelo |
| Provedor de dicionário do usuário. As linhas de código a seguir exibem |
| uma chamada {@link android.content.ContentResolver#query ContentResolver.query()}: |
| <p> |
| <pre> |
| // Queries the user dictionary and returns results |
| mCursor = getContentResolver().query( |
| UserDictionary.Words.CONTENT_URI, // The content URI of the words table |
| mProjection, // The columns to return for each row |
| mSelectionClause // Selection criteria |
| mSelectionArgs, // Selection criteria |
| mSortOrder); // The sort order for the returned rows |
| </pre> |
| <p> |
| A tabela 2 mostra como os argumentos para |
| {@link android.content.ContentResolver#query |
| query(Uri,projection,selection,selectionArgs,sortOrder)} correspondem a uma declaração SQL SELECT: |
| </p> |
| <p class="table-caption"> |
| <strong>Tabela 2:</strong> Query() comparada à consulta SQL. |
| </p> |
| <table id="table2" style="width: 75%;"> |
| <tr> |
| <th style="width:25%" align="center" scope="col">Argumento query()</th> |
| <th style="width:25%" align="center" scope="col">Palavra-chave/parâmetro de SELEÇÃO</th> |
| <th style="width:50%" align="center" scope="col">Observações</th> |
| </tr> |
| <tr> |
| <td align="center"><code>Uri</code></td> |
| <td align="center"><code>FROM <em>table_name</em></code></td> |
| <td><code>Uri</code> mapeia para a tabela no provedor chamado <em>table_name</em>.</td> |
| </tr> |
| <tr> |
| <td align="center"><code>projection</code></td> |
| <td align="center"><code><em>col,col,col,...</em></code></td> |
| <td> |
| <code>projection</code> é uma matriz de colunas que devem ser incluídas para cada linha |
| recuperada. |
| </td> |
| </tr> |
| <tr> |
| <td align="center"><code>selection</code></td> |
| <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td> |
| <td><code>selection</code> especifica o critério para a seleção de linhas.</td> |
| </tr> |
| <tr> |
| <td align="center"><code>selectionArgs</code></td> |
| <td align="center"> |
| (Não exatamente equivalente. Argumentos de seleção substituem marcadores de posição <code>?</code> |
| na cláusula de seleção.) |
| </td> |
| </tr> |
| <tr> |
| <td align="center"><code>sortOrder</code></td> |
| <td align="center"><code>ORDER BY <em>col,col,...</em></code></td> |
| <td> |
| <code>sortOrder</code> especifica a ordem em que as linhas aparecem |
| no {@link android.database.Cursor} retornado. |
| </td> |
| </tr> |
| </table> |
| <h3 id="ContentURIs">URIs de conteúdo</h3> |
| <p> |
| <strong>URI de conteúdo</strong> é uma URI que identifica dados em um provedor. URIs de conteúdo |
| contêm o nome simbólico de todo o provedor (sua <strong>autoridade</strong>) |
| e um nome que aponta para uma tabela (um <strong>caminho</strong>). Ao chamar |
| um método cliente para acessar uma tabela em um provedor, a URI de conteúdo da tabela é |
| um dos argumentos. |
| </p> |
| <p> |
| Nas linhas de código anteriores, a constante |
| {@link android.provider.UserDictionary.Words#CONTENT_URI} contém a URI de conteúdo |
| da tabela de "palavras" do dicionário do usuário. O objeto {@link android.content.ContentResolver} |
| analisa a autoridade da URI e usa-na para "determinar" o provedor |
| comparando a autoridade a uma tabela de provedores conhecidos do sistema. |
| O {@link android.content.ContentResolver} pode, então, enviar os argumentos da consulta ao provedor |
| correto. |
| </p> |
| <p> |
| O {@link android.content.ContentProvider} usa o caminho que é parte da URI de conteúdo para escolher |
| a tabela para acessar. Os provedores normalmente têm um <strong>caminho</strong> para cada tabela exposta. |
| </p> |
| <p> |
| Nas linhas de código anteriores, a URI completa da tabela de "palavras" é: |
| </p> |
| <pre> |
| content://user_dictionary/words |
| </pre> |
| <p> |
| onde a string <code>user_dictionary</code> é a autoridade do provedor e |
| a string <code>words</code> é o caminho da tabela. A string |
| <code>content://</code> (o <strong>esquema</strong>) está sempre presente |
| e identifica isso como uma URI de conteúdo. |
| </p> |
| <p> |
| Muitos provedores permitem acesso a uma única linha em uma tabela, por meio da anexação do valor de um ID |
| no fim da URI. Por exemplo, para recuperar uma linha em que <code>_ID</code> seja |
| <code>4</code> do dicionário do usuário, é possível usar essa URI de conteúdo: |
| </p> |
| <pre> |
| Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); |
| </pre> |
| <p> |
| Normalmente usam-se valores de ID ao recuperar um conjunto de linhas e, em seguida, é necessário atualizar ou excluir |
| uma delas. |
| </p> |
| <p class="note"> |
| <strong>Observação:</strong> as classes {@link android.net.Uri} e {@link android.net.Uri.Builder} |
| contêm métodos convenientes para a construção de objetos de URI bem formados a partir de strings. |
| As {@link android.content.ContentUris} contêm métodos conveniente para anexar valores de ID |
| a uma URI. O fragmento anterior usa {@link android.content.ContentUris#withAppendedId |
| withAppendedId()} para anexar um ID à URI de conteúdo UserDictionary. |
| </p> |
| |
| |
| <!-- Retrieving Data from the Provider --> |
| <h2 id="SimpleQuery">Recuperação de dados pelo Provedor</h2> |
| <p> |
| Esta seção descreve como recuperar dados de um provedor usando o Provedor de dicionário do usuário |
| como um exemplo. |
| </p> |
| <p class="note"> |
| Por uma questão de clareza, os fragmentos de código nesta seção chamam |
| {@link android.content.ContentResolver#query ContentResolver.query()} no "encadeamento da IU". |
| No código atual, contudo, deve-se realizar consultas assincronamente em um encadeamento separado. Um modo de fazê-lo |
| é usar a classe {@link android.content.CursorLoader}, descrita |
| com mais detalhes no guia <a href="{@docRoot}guide/components/loaders.html"> |
| Carregadores</a>. Além disso, as linhas de código são somente fragmentos — não mostram um aplicativo |
| completo. |
| </p> |
| <p> |
| Para recuperar dados de um provedor, siga essas etapas básicas: |
| </p> |
| <ol> |
| <li> |
| Solicite a permissão de acesso para leitura para um provedor. |
| </li> |
| <li> |
| Defina o código que envia uma consulta ao provedor. |
| </li> |
| </ol> |
| <h3 id="RequestPermissions">Solicitação de permissão de acesso para leitura</h3> |
| <p> |
| Para recuperar dados de um provedor, o aplicativo precisa de "permissão de acesso a leitura" |
| para o provedor. Não é possível solicitar essa permissão em tempo de execução. Em vez disso, deve-se especificar |
| que precisa dessa permissão no manifesto com o elemento |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> |
| e o nome da permissão exata definida |
| pelo provedor. Ao especificar esse elemento no manifesto, você está efetivamente "solicitando" essa |
| permissão para o aplicativo. Quando usuários instalam seu aplicativo, eles concedem essa solicitação |
| implicitamente. |
| </p> |
| <p> |
| Para encontrar o nome exato da permissão de acesso para leitura do provedor que está usando, bem |
| como os nomes de outras permissões de acesso usadas pelo provedor, consulte a documentação |
| do provedor. |
| </p> |
| <p> |
| O papel das permissões no acesso a provedores é descrito com mais detalhes na seção |
| <a href="#Permissions">Permissões do provedor de conteúdo</a>. |
| </p> |
| <p> |
| O Provedor de Dicionário do Usuário define a permissão |
| <code>android.permission.READ_USER_DICTIONARY</code> no arquivo de manifesto, portanto, se um |
| aplicativo quiser ler pelo provedor, deve solicitar essa permissão. |
| </p> |
| <!-- Constructing the query --> |
| <h3 id="Query">Construção da consulta</h3> |
| <p> |
| A próxima etapa na recuperação de dados de um provedor é construir uma consulta. Este primeiro fragmento |
| define algumas variáveis para acessar o Provedor de Dicionário do Usuário: |
| </p> |
| <pre class="prettyprint"> |
| |
| // A "projection" defines the columns that will be returned for each row |
| String[] mProjection = |
| { |
| UserDictionary.Words._ID, // Contract class constant for the _ID column name |
| UserDictionary.Words.WORD, // Contract class constant for the word column name |
| UserDictionary.Words.LOCALE // Contract class constant for the locale column name |
| }; |
| |
| // Defines a string to contain the selection clause |
| String mSelectionClause = null; |
| |
| // Initializes an array to contain selection arguments |
| String[] mSelectionArgs = {""}; |
| |
| </pre> |
| <p> |
| O próximo fragmento mostra como usar |
| {@link android.content.ContentResolver#query ContentResolver.query()} usando o Provedor de |
| Dicionário do Usuário como exemplo. Uma consulta cliente do provedor é similar a uma consulta SQL e contém um |
| conjunto de colunas para retornar, um conjunto de critérios de seleção e uma classificação ordenada. |
| </p> |
| <p> |
| O conjunto de colunas que a consulta deve retornar é chamado de <strong>projeção</strong> |
| (a variável <code>mProjection</code>). |
| </p> |
| <p> |
| A expressão que especifica as linhas a recuperar é dividida em uma cláusula de seleção |
| e em argumentos de seleção. A cláusula de seleção é uma combinação de expressões lógicas e booleanas |
| e nomes e valores de colunas (a variável <code>mSelectionClause</code>). Ao especificar |
| o parâmetro <code>?</code> substituível em vez de um valor, o método da consulta recupera o valor |
| da matriz de argumentos de seleção (a variável <code>mSelectionArgs</code>). |
| </p> |
| <p> |
| No próximo fragmento, se o usuário não inserir nenhuma palavra, a cláusula de seleção será definida como |
| <code>null</code> e a consulta retornará todas as palavras no provedor. Se o usuário inserir |
| uma palavra, a cláusula de seleção será definida como <code>UserDictionary.Words.WORD + " = ?"</code> |
| e o primeiro elemento da matriz de argumentos de seleção é definida como a palavra que o usuário inserir. |
| </p> |
| <pre class="prettyprint"> |
| /* |
| * This defines a one-element String array to contain the selection argument. |
| */ |
| String[] mSelectionArgs = {""}; |
| |
| // Gets a word from the UI |
| mSearchString = mSearchWord.getText().toString(); |
| |
| // Remember to insert code here to check for invalid or malicious input. |
| |
| // If the word is the empty string, gets everything |
| if (TextUtils.isEmpty(mSearchString)) { |
| // Setting the selection clause to null will return all words |
| mSelectionClause = null; |
| mSelectionArgs[0] = ""; |
| |
| } else { |
| // Constructs a selection clause that matches the word that the user entered. |
| mSelectionClause = UserDictionary.Words.WORD + " = ?"; |
| |
| // Moves the user's input string to the selection arguments. |
| mSelectionArgs[0] = mSearchString; |
| |
| } |
| |
| // Does a query against the table and returns a Cursor object |
| mCursor = getContentResolver().query( |
| UserDictionary.Words.CONTENT_URI, // The content URI of the words table |
| mProjection, // The columns to return for each row |
| mSelectionClause // Either null, or the word the user entered |
| mSelectionArgs, // Either empty, or the string the user entered |
| mSortOrder); // The sort order for the returned rows |
| |
| // Some providers return null if an error occurs, others throw an exception |
| if (null == mCursor) { |
| /* |
| * Insert code here to handle the error. Be sure not to use the cursor! You may want to |
| * call android.util.Log.e() to log this error. |
| * |
| */ |
| // If the Cursor is empty, the provider found no matches |
| } else if (mCursor.getCount() < 1) { |
| |
| /* |
| * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily |
| * an error. You may want to offer the user the option to insert a new row, or re-type the |
| * search term. |
| */ |
| |
| } else { |
| // Insert code here to do something with the results |
| |
| } |
| </pre> |
| <p> |
| Essa consulta é análoga à declaração SQL: |
| </p> |
| <pre> |
| SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; |
| </pre> |
| <p> |
| Nesta declaração SQL, os nomes de coluna reais são usados no lugar de constantes de classes de contrato. |
| </p> |
| <h4 id="Injection">Proteção contra inserções mal-intencionadas</h4> |
| <p> |
| Se os dados gerenciados pelo provedor de conteúdo estiverem em um banco de dados SQL, inclusive dados não confiáveis |
| externos nas declarações SQL brutas, existe a possibilidade de haver uma injeção de SQL. |
| </p> |
| <p> |
| Considere esta cláusula de seleção: |
| </p> |
| <pre> |
| // Constructs a selection clause by concatenating the user's input to the column name |
| String mSelectionClause = "var = " + mUserInput; |
| </pre> |
| <p> |
| Se você fizer isso, estará permitindo que o usuário concatene SQL mal-intencionados na sua declaração SQL. |
| Por exemplo: o usuário poderia inserir "nada; REMOVER TABELA *;" para <code>mUserInput</code>, o que |
| resultaria na cláusula de seleção <code>var = nothing; DROP TABLE *;</code>. Como |
| a cláusula de seleção é tratada como uma declaração SQL, isso pode fazer com que o provedor apague todas |
| as tabelas no banco de dados SQLite em questão (a menos que o provedor esteja configurado para capturar |
| tentativas de <a href="http://en.wikipedia.org/wiki/SQL_injection">injeção de SQL</a>). |
| </p> |
| <p> |
| Para evitar este problema, use uma cláusula de seleção que use <code>?</code> como um parâmetro |
| substituível e uma matriz de argumentos de seleção separada. Ao fazer isso, a inserção de dados do usuário |
| limita-se diretamente à consulta em vez de ser interpretada como parte de uma declaração SQL. |
| Pelo fato de não ser tratada como SQL, a inserção de dados do usuário não injeta SQL mal-intencionados. Em vez de usar |
| a concatenação para incluir a inserção de dados do usuário, use esta cláusula de seleção: |
| </p> |
| <pre> |
| // Constructs a selection clause with a replaceable parameter |
| String mSelectionClause = "var = ?"; |
| </pre> |
| <p> |
| Configure a matriz de argumentos de seleção desta maneira: |
| </p> |
| <pre> |
| // Defines an array to contain the selection arguments |
| String[] selectionArgs = {""}; |
| </pre> |
| <p> |
| Insira um valor na matriz de argumentos de seleção desta maneira: |
| </p> |
| <pre> |
| // Sets the selection argument to the user's input |
| selectionArgs[0] = mUserInput; |
| </pre> |
| <p> |
| Usar uma cláusula de seleção que use <code>?</code> como um parâmetro substituível e uma matriz |
| de argumentos de seleção é o melhor modo de especificar uma seleção, mesmo que o provedor se baseie |
| base em um banco de dados SQL. |
| </p> |
| <!-- Displaying the results --> |
| <h3 id="DisplayResults">Exibição dos resultados da consulta</h3> |
| <p> |
| O método cliente {@link android.content.ContentResolver#query ContentResolver.query()} sempre |
| retorna um {@link android.database.Cursor} contendo as colunas especificadas pela projeção |
| da consulta para as linhas que atendem aos critérios de seleção da consulta. |
| Um objeto {@link android.database.Cursor} fornece acesso para leitura aleatório para as linhas e colunas que |
| contém. Usando métodos {@link android.database.Cursor}, é possível repetir as linhas |
| nos resultados, determinar o tipo dos dados de cada coluna, extrair os dados de uma coluna e examinar |
| outras propriedades dos resultados. Algumas implementações do {@link android.database.Cursor} atualizam o objeto |
| automaticamente quando os dados do provedor mudam ou acionam métodos em um objeto observador |
| quando o {@link android.database.Cursor} muda, ou ambos. |
| </p> |
| <p class="note"> |
| <strong>Observação:</strong> os provedores podem restringir acesso a colunas com base na natureza |
| do objeto que realiza a consulta. Por exemplo: o Provedor de Contatos restringe o acesso de algumas colunas |
| a adaptadores de sincronização, por isso ela não os retornará a uma atividade ou serviço. |
| </p> |
| <p> |
| Se nenhuma linha atender aos critérios de seleção, o provedor |
| retorna um objeto {@link android.database.Cursor} para o qual |
| {@link android.database.Cursor#getCount Cursor.getCount()} é 0 (um cursor vazio). |
| </p> |
| <p> |
| Se ocorrer um erro interno, os resultados da consulta dependem do provedor determinado. Ele pode |
| escolher retornar <code>null</code> ou pode gerar uma {@link java.lang.Exception}. |
| </p> |
| <p> |
| Já que {@link android.database.Cursor} é uma "lista" de linhas, um bom modo de exibir |
| o conteúdo de um {@link android.database.Cursor} é vinculá-lo a uma {@link android.widget.ListView} |
| por meio de um {@link android.widget.SimpleCursorAdapter}. |
| </p> |
| <p> |
| O fragmento a seguir continua o código do fragmento anterior. Ele cria |
| um objeto {@link android.widget.SimpleCursorAdapter} contendo o {@link android.database.Cursor} |
| recuperado pela consulta e configura esse objeto para ser o adaptador de uma |
| {@link android.widget.ListView}: |
| </p> |
| <pre class="prettyprint"> |
| // Defines a list of columns to retrieve from the Cursor and load into an output row |
| String[] mWordListColumns = |
| { |
| UserDictionary.Words.WORD, // Contract class constant containing the word column name |
| UserDictionary.Words.LOCALE // Contract class constant containing the locale column name |
| }; |
| |
| // Defines a list of View IDs that will receive the Cursor columns for each row |
| int[] mWordListItems = { R.id.dictWord, R.id.locale}; |
| |
| // Creates a new SimpleCursorAdapter |
| mCursorAdapter = new SimpleCursorAdapter( |
| getApplicationContext(), // The application's Context object |
| R.layout.wordlistrow, // A layout in XML for one row in the ListView |
| mCursor, // The result from the query |
| mWordListColumns, // A string array of column names in the cursor |
| mWordListItems, // An integer array of view IDs in the row layout |
| 0); // Flags (usually none are needed) |
| |
| // Sets the adapter for the ListView |
| mWordList.setAdapter(mCursorAdapter); |
| </pre> |
| <p class="note"> |
| <strong>Observação:</strong> para retornar uma {@link android.widget.ListView} com um |
| {@link android.database.Cursor}, o cursor deve conter uma coluna chamada <code>_ID</code>. |
| Por isso, a consulta exibida anteriormente recupera a coluna <code>_ID</code> da |
| tabelas de "palavras", mesmo que a {@link android.widget.ListView} não a exiba. |
| Essa restrição também explica por que a maioria dos provedores tem uma coluna <code>_ID</code> para cada |
| tabela. |
| </p> |
| |
| <!-- Getting data from query results --> |
| <h3 id="GettingResults">Obtenção de dados de resultados da consulta</h3> |
| <p> |
| Em vez de simplesmente exibir resultados da consulta, é possível usá-los para outras tarefas. Por |
| exemplo: é possível recuperar grafias de um dicionário do usuário e, em seguida, procurá-los |
| em outros provedores. Para isso, repetem-se as linhas no {@link android.database.Cursor}: |
| </p> |
| <pre class="prettyprint"> |
| |
| // Determine the column index of the column named "word" |
| int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); |
| |
| /* |
| * Only executes if the cursor is valid. The User Dictionary Provider returns null if |
| * an internal error occurs. Other providers may throw an Exception instead of returning null. |
| */ |
| |
| if (mCursor != null) { |
| /* |
| * Moves to the next row in the cursor. Before the first movement in the cursor, the |
| * "row pointer" is -1, and if you try to retrieve data at that position you will get an |
| * exception. |
| */ |
| while (mCursor.moveToNext()) { |
| |
| // Gets the value from the column. |
| newWord = mCursor.getString(index); |
| |
| // Insert code here to process the retrieved word. |
| |
| ... |
| |
| // end of while loop |
| } |
| } else { |
| |
| // Insert code here to report an error if the cursor is null or the provider threw an exception. |
| } |
| </pre> |
| <p> |
| As implementações {@link android.database.Cursor} contêm diversos métodos "get" (obter) |
| para recuperar diferentes tipos de dados do objeto. Por exemplo, o fragmento anterior |
| usa {@link android.database.Cursor#getString getString()}. Elas também têm |
| um método {@link android.database.Cursor#getType getType()} que retorna um valor indicando |
| o tipo dos dados da coluna. |
| </p> |
| |
| |
| <!-- Requesting permissions --> |
| <h2 id="Permissions">Permissões do provedor de conteúdo</h2> |
| <p> |
| Um aplicativo do provedor pode especificar permissões que outros aplicativos devem ter para |
| acessar os dados do provedor. Essas permissões garantem que o usuário saiba quais dados |
| um aplicativo tentará acessar. Com base nos requisitos do provedor, outros aplicativos |
| solicitam as permissões de que precisam para acessar o provedor. Usuários finais veem as permissões |
| solicitadas quando instalam o aplicativo. |
| </p> |
| <p> |
| Se um aplicativo do provedor não especificar nenhuma permissão, outros aplicativos não terão |
| acesso aos dados do provedor. No entanto, os componentes no aplicativo do provedor sempre têm |
| acesso total para leitura e gravação, independentemente das permissões especificadas. |
| </p> |
| <p> |
| Como observado anteriormente, o Provedor de Dicionário do Usuário requer |
| a permissão <code>android.permission.READ_USER_DICTIONARY</code> para recuperar dados dele. |
| O provedor tem a permissão <code>android.permission.WRITE_USER_DICTIONARY</code> |
| separadamente para inserção, atualização ou exclusão de dados. |
| </p> |
| <p> |
| Para obter as permissões necessárias para acessar um provedor, um aplicativo as solicita |
| como um elemento <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> |
| no arquivo de manifesto. Quando o Android Package Manager (gerente de pacotes do Android) instala o aplicativo, o usuário |
| precisa aprovar todas as permissões que o aplicativo solicita. Se o usuário aprovar todas elas, |
| o gerente de pacotes continua a instalação; se o usuário não as aprovar, o gerente de pacotes |
| aborta a instalação. |
| </p> |
| <p> |
| O elemento |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> a seguir |
| solicita acesso para leitura ao Provedor de Dicionário do Usuário: |
| </p> |
| <pre> |
| <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> |
| </pre> |
| <p> |
| O impacto das permissões no acesso ao provedor é explicado com mais detalhes |
| no guia <a href="{@docRoot}guide/topics/security/security.html">Permissões e segurança</a>. |
| </p> |
| |
| |
| <!-- Inserting, Updating, and Deleting Data --> |
| <h2 id="Modifications">Inserção, atualização e exclusão de dados</h2> |
| <p> |
| Do mesmo modo que se recupera dados de um provedor, também usa-se a interação entre |
| um cliente do provedor e o {@link android.content.ContentProvider} do provedor para modificar dados. |
| Chama-se um método de {@link android.content.ContentResolver} com argumentos que são passados para |
| o método correspondente de {@link android.content.ContentProvider}. O provedor e o cliente |
| do provedor tratam automaticamente da segurança e da comunicação de processos internos. |
| </p> |
| <h3 id="Inserting">Inserção de dados</h3> |
| <p> |
| Para inserir dados em um provedor, chame |
| o método |
| {@link android.content.ContentResolver#insert ContentResolver.insert()}. Esse método insere uma nova linha no provedor e retorna uma URI de conteúdo dessa linha. |
| Este fragmento mostra como inserir uma nova palavra no Provedor de Dicionário do Usuário: |
| </p> |
| <pre class="prettyprint"> |
| // Defines a new Uri object that receives the result of the insertion |
| Uri mNewUri; |
| |
| ... |
| |
| // Defines an object to contain the new values to insert |
| ContentValues mNewValues = new ContentValues(); |
| |
| /* |
| * Sets the values of each column and inserts the word. The arguments to the "put" |
| * method are "column name" and "value" |
| */ |
| mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); |
| mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); |
| mNewValues.put(UserDictionary.Words.WORD, "insert"); |
| mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); |
| |
| mNewUri = getContentResolver().insert( |
| UserDictionary.Word.CONTENT_URI, // the user dictionary content URI |
| mNewValues // the values to insert |
| ); |
| </pre> |
| <p> |
| Os dados da nova linha vão para um objeto {@link android.content.ContentValues} único, que |
| tem forma semelhante a um cursor de uma linha. As colunas nesse objeto não precisam ter |
| o mesmo tipo de dados e, se você não quiser especificar um valor, pode definir uma coluna |
| como <code>null</code> usando {@link android.content.ContentValues#putNull ContentValues.putNull()}. |
| </p> |
| <p> |
| O fragmento não adiciona a coluna <code>_ID</code> porque essa coluna é mantida |
| automaticamente. O provedor atribui um valor exclusivo de <code>_ID</code> para cada linha |
| adicionada. Os provedores normalmente usam esse valor como a chave principal da tabela. |
| </p> |
| <p> |
| A URI de conteúdo retornada em <code>newUri</code> identifica a linha recentemente adicionada com |
| o seguinte formato: |
| </p> |
| <pre> |
| content://user_dictionary/words/<id_value> |
| </pre> |
| <p> |
| O <code><id_value></code> é o conteúdo de <code>_ID</code> da nova linha. |
| A maioria dos provedores pode detectar essa forma de URI de conteúdo automaticamente e, em seguida, realizar a operação |
| solicitada naquela linha. |
| </p> |
| <p> |
| Para obter o valor de <code>_ID</code> do {@link android.net.Uri} retornado, chame |
| {@link android.content.ContentUris#parseId ContentUris.parseId()}. |
| </p> |
| <h3 id="Updating">Atualização de dados</h3> |
| <p> |
| Para atualizar uma linha, use um objeto {@link android.content.ContentValues} com os valores |
| e os critérios de seleção atualizados, como se faz com uma inserção e em uma consulta, respectivamente. |
| O método cliente usado é |
| {@link android.content.ContentResolver#update ContentResolver.update()}. Só é necessário adicionar |
| valores ao objeto {@link android.content.ContentValues} das colunas que forem atualizadas. Se você |
| deseja apagar o conteúdo de uma coluna, defina o valor como <code>null</code>. |
| </p> |
| <p> |
| O fragmento a seguir altera todas as linhas cuja localidade tem o idioma "en" para |
| terem uma localidade de <code>null</code>. O valor de retorno é o número de linhas que foram atualizadas: |
| </p> |
| <pre> |
| // Defines an object to contain the updated values |
| ContentValues mUpdateValues = new ContentValues(); |
| |
| // Defines selection criteria for the rows you want to update |
| String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; |
| String[] mSelectionArgs = {"en_%"}; |
| |
| // Defines a variable to contain the number of updated rows |
| int mRowsUpdated = 0; |
| |
| ... |
| |
| /* |
| * Sets the updated value and updates the selected words. |
| */ |
| mUpdateValues.putNull(UserDictionary.Words.LOCALE); |
| |
| mRowsUpdated = getContentResolver().update( |
| UserDictionary.Words.CONTENT_URI, // the user dictionary content URI |
| mUpdateValues // the columns to update |
| mSelectionClause // the column to select on |
| mSelectionArgs // the value to compare to |
| ); |
| </pre> |
| <p> |
| Você também deve filtrar a inserção de dados do usuário ao chamar |
| {@link android.content.ContentResolver#update ContentResolver.update()}. Para saber mais sobre |
| isso, leia a seção <a href="#Injection">Proteção contra inserções mal-intencionadas</a>. |
| </p> |
| <h3 id="Deleting">Exclusão de dados</h3> |
| <p> |
| Excluir linhas é semelhante a recuperar dados de linhas: especificam-se critérios de seleção para as linhas |
| que se deseja excluir e o método cliente retorna o número de linhas excluídas. |
| O fragmento a seguir exclui linhas cujo appid (id do aplicativo) corresponda a "usuário". O método retorna |
| o número de linhas excluídas. |
| </p> |
| <pre> |
| |
| // Defines selection criteria for the rows you want to delete |
| String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; |
| String[] mSelectionArgs = {"user"}; |
| |
| // Defines a variable to contain the number of rows deleted |
| int mRowsDeleted = 0; |
| |
| ... |
| |
| // Deletes the words that match the selection criteria |
| mRowsDeleted = getContentResolver().delete( |
| UserDictionary.Words.CONTENT_URI, // the user dictionary content URI |
| mSelectionClause // the column to select on |
| mSelectionArgs // the value to compare to |
| ); |
| </pre> |
| <p> |
| Também se deve filtrar a inserção de dados do usuário ao chamar |
| {@link android.content.ContentResolver#delete ContentResolver.delete()}. Para saber mais sobre |
| isso, leia a seção <a href="#Injection">Proteção contra inserções mal-intencionadas</a>. |
| </p> |
| <!-- Provider Data Types --> |
| <h2 id="DataTypes">Tipos de dados do provedor</h2> |
| <p> |
| Provedores de conteúdo podem oferecer muitos tipos de dados diferentes. O Provedor de Dicionário do Usuário oferece somente |
| texto, mas provedores também podem oferecer os seguintes formatos: |
| </p> |
| <ul> |
| <li> |
| número inteiro |
| </li> |
| <li> |
| número inteiro longo (longo) |
| </li> |
| <li> |
| ponto flutuante |
| </li> |
| <li> |
| ponto flutuante longo (duplo) |
| </li> |
| </ul> |
| <p> |
| Outros tipos de dados que provedores usam com frequência são objetos binários largos (BLOB) implementados como uma |
| matriz de byte de 64 kB. É possível ver os tipos de dados disponíveis consultando |
| os métodos "get" da classe {@link android.database.Cursor}. |
| </p> |
| <p> |
| O tipo dos dados para cada coluna em um provedor normalmente é listado na documentação do provedor. |
| Os tipos de dados do Provedor de Dicionário do Usuário são listados na documentação de referência |
| para sua classe de contrato {@link android.provider.UserDictionary.Words} (classes de contrato são |
| descritas na seção <a href="#ContractClasses">Classes de contrato</a>). |
| Também é possível determinar o tipo dos dados chamando {@link android.database.Cursor#getType |
| Cursor.getType()}. |
| </p> |
| <p> |
| Os provedores também mantêm informações do tipo MIME de dados para cada URI de conteúdo que definem. É possível |
| usar as informações do tipo MIME para descobrir se o aplicativo pode tratar de dados que |
| o provedor fornece ou para escolher um tipo de tratamento com base no tipo MIME. Normalmente é necessário ter |
| o tipo MIME ao trabalhar com um provedor que contenha estruturas |
| complexas de dados ou arquivos. Por exemplo: a tabela {@link android.provider.ContactsContract.Data} |
| no Provedor de contatos usa tipos MIME para etiquetar o tipo dos dados de contato armazenados em cada |
| linha. Para obter o tipo MIME correspondente a uma URI de conteúdo, chame |
| {@link android.content.ContentResolver#getType ContentResolver.getType()}. |
| </p> |
| <p> |
| A seção <a href="#MIMETypeReference">Referência de tipo MIME</a> descreve |
| a sintaxe de tipos MIME padrão e personalizados. |
| </p> |
| |
| |
| <!-- Alternative Forms of Provider Access --> |
| <h2 id="AltForms">Formas alternativas de acessar o provedor</h2> |
| <p> |
| Três formas alternativas de acesso ao provedor são importantes no desenvolvimento do aplicativo: |
| </p> |
| <ul> |
| <li> |
| <a href="#Batch">Acesso em lote</a>: É possível criar um lote de chamadas de acesso com métodos na |
| classe {@link android.content.ContentProviderOperation} e, em seguida, aplicá-los com |
| {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. |
| </li> |
| <li> |
| Consultas assíncronas: Devem-se realizar consultas em um encadeamento separado. Um modo de fazer isso é |
| usar um objeto {@link android.content.CursorLoader}. Os exemplos |
| no guia <a href="{@docRoot}guide/components/loaders.html">Carregadores</a> demonstram |
| como fazer isso. |
| </li> |
| <li> |
| <a href="#Intents">Acesso a dados via intenções</a> Embora não seja possível enviar uma intenção |
| diretamente a um provedor, é possível enviar uma intenção ao aplicativo do provedor, que |
| normalmente é o recomendável para modificar os dados do provedor. |
| </li> |
| </ul> |
| <p> |
| O acesso em lote e a modificação via intenções são descritos nas seções a seguir. |
| </p> |
| <h3 id="Batch">Acesso em lote</h3> |
| <p> |
| O acesso em lote a um provedor é útil para inserir uma grande quantidade de linhas ou para inserir |
| linhas em diversas tabelas na mesma chamada de método ou, em geral, para realizar um conjunto de |
| operações dentre limites de processo como uma transação (uma operação atômica). |
| </p> |
| <p> |
| Para acessar um provedor em "modo de lote", |
| cria-se uma matriz de objetos {@link android.content.ContentProviderOperation} e, em seguida, |
| envia-os a um provedor de conteúdo com |
| {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Confere-se a |
| <em>autoridade</em> do provedor de conteúdo para esse método em vez de para uma URI de conteúdo específica. |
| Isso permite que cada objeto {@link android.content.ContentProviderOperation} na matriz trabalhe |
| com uma tabela diferente. Chamar {@link android.content.ContentResolver#applyBatch |
| ContentResolver.applyBatch()} retorna uma matriz de resultados. |
| </p> |
| <p> |
| A descrição da classe de contrato {@link android.provider.ContactsContract.RawContacts} |
| contém um fragmento de código que demonstra a inserção em lote. |
| O aplicativo de exemplo do <a href="{@docRoot}resources/samples/ContactManager/index.html">Gerente de contato</a> |
| contém um exemplo de acesso em lote em seu |
| arquivo de origem <code>ContactAdder.java</code>. |
| </p> |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h2>Exibição de dados usando um aplicativo auxiliar</h2> |
| <p> |
| Se o seu aplicativo <em>tem</em> permissões de acesso, ainda é possível usar |
| uma intenção para exibir dados em outro aplicativo. Por exemplo: o aplicativo Agenda aceita |
| uma intenção {@link android.content.Intent#ACTION_VIEW} que exibe uma data ou evento específico. |
| Isso permite a exibição de informações da agenda sem precisar criar a própria IU. |
| Para saber mais sobre esse recurso, consulte |
| o guia <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Provedor de agenda</a>. |
| </p> |
| <p> |
| O aplicativo para o qual você enviou uma intenção não precisa ser o aplicativo |
| associado ao provedor. Por exemplo: você pode recuperar um contato |
| do Provedor de Contatos e, em seguida, enviar uma intenção {@link android.content.Intent#ACTION_VIEW} |
| que contém a URI de conteúdo da imagem do contato para um visualizador de imagens. |
| </p> |
| </div> |
| </div> |
| <h3 id="Intents">Acesso a dados via intenções</h3> |
| <p> |
| Intenções podem fornecer acesso indireto a um provedor de conteúdo. Basta permitir que o usuário acesse |
| dados em um provedor mesmo se o aplicativo não tiver permissões de acesso, tanto |
| retornando uma intenção de resultado de um aplicativo que tem permissões quanto ativando |
| um aplicativo que tem permissões e permitindo que o usuário trabalhe nele. |
| </p> |
| <h4>Obtenção de acesso com permissões temporárias</h4> |
| <p> |
| É possível acessar dados em um provedor de conteúdo, mesmo sem s permissões |
| de acesso adequadas. Basta enviar uma intenção a um aplicativo que tenha as permissões e |
| receber de volta uma intenção de resultado contendo permissões da "URI". |
| Essas são permissões para uma URI de conteúdo específica que duram enquanto durar a atividade |
| que as recebeu. O aplicativo que tem permissões permanentes concedem permissões |
| temporárias ativando um sinalizador na intenção de resultado: |
| </p> |
| <ul> |
| <li> |
| <strong>Permissão de leitura:</strong> |
| {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} |
| </li> |
| <li> |
| <strong>Permissão de gravação:</strong> |
| {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} |
| </li> |
| </ul> |
| <p class="note"> |
| <strong>Observação:</strong> esses sinalizadores não fornecem acesso geral de leitura ou gravação ao provedor |
| cuja autoridade esteja contida na URI de conteúdo. O acesso destina-se somente à URI. |
| </p> |
| <p> |
| Um provedor define permissões de URI para URIs de conteúdo no manifesto usando o atributo |
| <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code> |
| do elemento |
| <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code>, |
| bem como o elemento filho |
| <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code> |
| do elemento |
| <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> |
| . O mecanismo das permissões de URI é explicado com mais detalhes |
| no guia <a href="{@docRoot}guide/topics/security/security.html">Permissões e segurança</a>, |
| na seção "Permissões da URI". |
| </p> |
| <p> |
| Por exemplo: é possível recuperar dados de um contato no Provedor de Contatos, mesmo sem |
| a permissão {@link android.Manifest.permission#READ_CONTACTS}. Você pode desejar fazer |
| isso em um aplicativo que envie e-mails de parabenização a um contato no aniversário dele. Em vez de |
| solicitar {@link android.Manifest.permission#READ_CONTACTS}, que fornece acesso a todos |
| os contatos do usuário e suas informações, é preferível deixar que o usuário controle quais |
| contatos serão usados pelo seu aplicativo. Para isso, use o processo a seguir: |
| </p> |
| <ol> |
| <li> |
| O aplicativo envia uma intenção contendo a ação |
| {@link android.content.Intent#ACTION_PICK} e o tipo MIME |
| {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} dos "contatos" usando |
| o método {@link android.app.Activity#startActivityForResult |
| startActivityForResult()}. |
| </li> |
| <li> |
| Como essa intenção corresponde ao filtro de intenções da |
| atividade de "seleção" do aplicativo Pessoas, a atividade ficará em primeiro plano. |
| </li> |
| <li> |
| Na atividade de seleção, o usuário seleciona |
| um contato para atualizar. Quando isso acontece, a atividade de seleção chama |
| {@link android.app.Activity#setResult setResult(resultcode, intent)} |
| para configurar uma intenção para retornar ao aplicativo. A intenção contém a URI de conteúdo |
| do contato que o usuário selecionou e os sinalizadores "extras" |
| {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Esses sinalizadores concedem |
| permissão de URI para que o aplicativo leia dados do contato apontados pela |
| URI de conteúdo. A atividade de seleção, em seguida, chama {@link android.app.Activity#finish()} para |
| retornar o controle para o aplicativo. |
| </li> |
| <li> |
| A atividade volta ao primeiro plano e o sistema chama o |
| método {@link android.app.Activity#onActivityResult onActivityResult()} |
| da sua atividade. Esse método recebe a intenção de resultado criada pela atividade de seleção |
| no aplicativo Pessoas. |
| </li> |
| <li> |
| Com a URI de conteúdo da intenção de resultado, é possível ler os dados do contato |
| a partir do Provedor de Contatos, mesmo que não tenha solicitado permissão permanente de acesso a leitura |
| para o provedor no manifesto. Pode-se, então, pode obter as informações de data de nascimento do contato |
| ou seu endereço de e-mail e, assim, enviar um e-mail de parabenização. |
| </li> |
| </ol> |
| <h4>Uso de outro aplicativo</h4> |
| <p> |
| Um modo simples que permite ao usuário modificar dados para os quais você não tem permissões de acesso é |
| ativar um aplicativo que tenha permissões e deixar o usuário fazer o resto. |
| </p> |
| <p> |
| Por exemplo: o aplicativo Agenda aceita uma |
| intenção {@link android.content.Intent#ACTION_INSERT} que permite a ativação da |
| IU de inserção do aplicativo. Você pode passar dados "extras" nessa intenção que o aplicativo |
| usa para "pré-preencher" a IU. como os eventos recorrentes têm sintaxe complexa, o modo |
| recomendado de inserir eventos no Provedor de Agenda é ativar o aplicativo Agenda com um |
| {@link android.content.Intent#ACTION_INSERT} e, em seguida, deixar o usuário inserir o evento. |
| </p> |
| <!-- Contract Classes --> |
| <h2 id="ContractClasses">Classes de contrato</h2> |
| <p> |
| As classes de contrato definem constantes que ajudam os aplicativos a trabalhar com URIs de conteúdo, nomes |
| de colunas, ações de intenções e outros recursos de um provedor de conteúdo. Elas não estão |
| automaticamente inclusas em um provedor; o desenvolvedor do provedor deve defini-las e |
| disponibilizá-las a outros desenvolvedores. Muitos dos provedores incluídos na plataforma |
| do Android têm classes de contrato correspondentes no pacote {@link android.provider}. |
| </p> |
| <p> |
| Por exemplo: o Provedor de Dicionário do Usuário tem uma classe de contrato |
| {@link android.provider.UserDictionary} que contém constantes de URI de conteúdo e de nome de coluna. |
| A URI de conteúdo da tabela de "palavras" é definida na constante |
| {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}. |
| A classe {@link android.provider.UserDictionary.Words} também contém constantes de nome de coluna |
| que são usadas nos fragmentos de exemplo neste guia. Por exemplo, uma projeção de consulta pode ser |
| definida como: |
| </p> |
| <pre> |
| String[] mProjection = |
| { |
| UserDictionary.Words._ID, |
| UserDictionary.Words.WORD, |
| UserDictionary.Words.LOCALE |
| }; |
| </pre> |
| <p> |
| Outra classe de contrato é {@link android.provider.ContactsContract} para o Provedor de Contatos. |
| A documentação de referência desta classe contém fragmentos de código de exemplo. Uma das suas |
| subclasses, {@link android.provider.ContactsContract.Intents.Insert}, é uma classe |
| de contrato que contém constantes para intenções e dados da intenção. |
| </p> |
| |
| |
| <!-- MIME Type Reference --> |
| <h2 id="MIMETypeReference">Referência do tipo MIME</h2> |
| <p> |
| Provedores de conteúdo podem retornar tipos MIME de mídia, strings de tipos MIME personalizados ou ambos. |
| </p> |
| <p> |
| Tipos MIME têm o formato |
| </p> |
| <pre> |
| <em>type</em>/<em>subtype</em> |
| </pre> |
| <p> |
| Por exemplo: o tipo MIME <code>text/html</code> conhecido tem o tipo <code>text</code> |
| e o subtipo <code>html</code>. Se o provedor retornar esse tipo para uma URI, |
| uma consulta usando essa URI retornará um texto que contém tags HTML. |
| </p> |
| <p> |
| Strings de tipo MIME personalizado, também chamadas de tipos MIME "específicos do fornecedor" (vendor-specific), têm mais |
| valores de <em>tipo</em> e <em>subtipo</em> complexos. O valor de <em>tipo</em> é sempre |
| </p> |
| <pre> |
| vnd.android.cursor.<strong>dir</strong> |
| </pre> |
| <p> |
| para diversas linhas ou |
| </p> |
| <pre> |
| vnd.android.cursor.<strong>item</strong> |
| </pre> |
| <p> |
| para uma única linha. |
| </p> |
| <p> |
| O <em>subtipo</em> é específico do provedor. Os provedores embutidos do Android normalmente têm um subtipo |
| simples. Por exemplo, quando o aplicativo de contatos cria uma linha para um número de telefone, |
| ele configura o seguinte tipo MIME na linha: |
| </p> |
| <pre> |
| vnd.android.cursor.item/phone_v2 |
| </pre> |
| <p> |
| Observe que o valor do subtipo é simplesmente <code>phone_v2</code>. |
| </p> |
| <p> |
| Outros desenvolvedores de provedor podem criar os próprios padrões de subtipos com base |
| na autoridade do provedor e nos nomes da tabela. Por exemplo: considere um provedor que contenha horários de trens. |
| A autoridade do provedor é <code>com.example.trains</code> e ele contém as tabelas |
| Linha1, Linha2 e Linha3. Em resposta à URI de conteúdo |
| </p> |
| <p> |
| <pre> |
| content://com.example.trains/Line1 |
| </pre> |
| <p> |
| para a tabela Linha1, o provedor retorna o tipo MIME |
| </p> |
| <pre> |
| vnd.android.cursor.<strong>dir</strong>/vnd.example.line1 |
| </pre> |
| <p> |
| Em resposta à URI de conteúdo |
| </p> |
| <pre> |
| content://com.example.trains/Line2/5 |
| </pre> |
| <p> |
| da linha 5 na tabela Linha2, o provedor retorna o tipo MIME |
| </p> |
| <pre> |
| vnd.android.cursor.<strong>item</strong>/vnd.example.line2 |
| </pre> |
| <p> |
| A maioria dos provedores define constantes de classe de contrato para os tipos MIME que usam. |
| A classe de contrato {@link android.provider.ContactsContract.RawContacts} do Provedor de Contatos, |
| por exemplo, define a constante |
| {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} para o tipo MIME |
| de uma linha exclusiva do contato bruto. |
| </p> |
| <p> |
| URIs de conteúdo de linhas exclusivas são descritas na seção |
| <a href="#ContentURIs">URIs de conteúdo</a>. |
| </p> |