İçerik sağlayıcı ile ilgili temel bilgiler

İçerik sağlayıcı, merkezi bir veri deposuna erişimi yönetir. Sağlayıcı Android uygulamasının bir parçasıdır. Bu uygulama genellikle bahsedeceğim. Bununla birlikte, içerik sağlayıcılar öncelikli olarak diğer Bunlar, sağlayıcıya bir sağlayıcı istemci nesnesi aracılığıyla erişen uygulamalardır. Sağlayıcılar birlikte ve sağlayıcı müşterileri, veri işlemeyi sağlayan tutarlı, standart bir arayüz sunar. güvenli veri erişimi sunar.

İçerik sağlayıcılarla genellikle şu iki senaryodan biriyle çalışırsınız: başka bir uygulamada mevcut bir içerik sağlayıcıya erişmek için kullanılacak kod uygulamanıza yeni bir içerik sağlayıcı ekleyebilir ve mevcut verileri diğer uygulamalarla paylaşabilirsiniz.

Bu sayfa mevcut içerik sağlayıcılarla çalışmanın temellerini ele alır. Proje başlatma belgesini içerik sağlayıcılara göz atmak için İçerik sağlayıcı oluşturun.

Bu konuda aşağıdakiler açıklanmaktadır:

  • İçerik sağlayıcıların işleyiş şekli.
  • İçerik sağlayıcıdan veri almak için kullandığınız API.
  • İçerik sağlayıcıya veri eklemek, güncellemek veya silmek için kullandığınız API.
  • Sağlayıcılarla çalışmayı kolaylaştıran diğer API özellikleri.

Genel Bakış

İçerik sağlayıcı, harici uygulamalara verileri bir veya daha fazla tablo halinde sunar. ilişkisel veritabanında bulunan tablolara benzerdir. Satır, belirli bir türdeki örneği temsil eder temsil eder ve satırdaki her sütun tek bir veri parçasını temsil eder veri toplanmasını sağlar.

Bir içerik sağlayıcı, ve bileşenlerin sayısını artırır. Şekil 1'de gösterildiği gibi, bu özellikler aşağıdakileri içerir:

İçerik sağlayıcı ile diğer bileşenler arasındaki ilişki.

Şekil 1. İçerik sağlayıcı ile diğer bileşenler arasındaki ilişki.

Sağlayıcıya erişme

Bir içerik sağlayıcıdaki verilere erişmek istediğinizde, ContentResolver nesne Context. İlgili içeriği oluşturmak için kullanılan ContentResolver nesnesi, sağlayıcı nesnesiyle iletişim kurar ve ContentProvider uygulayan bir sınıfın örneği.

Sağlayıcı nesne, istemcilerden veri isteklerini alır, istenen işlemi gerçekleştirir ve sonuç. Bu nesne, sağlayıcı nesnesinde aynı şekilde adlandırılmış yöntemleri çağıran yöntemler içeriyor. ContentProvider somut alt sınıflarından birinin örneği. İlgili içeriği oluşturmak için kullanılan ContentResolver yöntemleri, "CRUD" (oluşturma, alma, güncelleme ve silme) işlevleri sunar.

Kullanıcı arayüzünden bir ContentProvider öğesine erişmek için sık kullanılan bir kalıp Arka planda eşzamansız sorgu çalıştırmak için CursorLoader. İlgili içeriği oluşturmak için kullanılan Kullanıcı arayüzündeki Activity veya Fragment, a Sorguya CursorLoader ekleyin. Bu da ContentProvider, ContentResolver kullanıyor.

Bu sayede, sorgu çalışırken kullanıcı arayüzü kullanılabilir olmaya devam eder. Bu desen, birkaç farklı nesnenin ve aynı zamanda altta yatan öğelerin depolama mekanizmasına yerleştirin.

ContentProvider, diğer sınıflar ve depolama arasındaki etkileşim.

Şekil 2. ContentProvider, diğer sınıflar ve depolama alanı arasındaki etkileşim.

Not: Bir sağlayıcıya erişmek için uygulamanızın genellikle belirli bir sağlayıcıyı talep etmesi gerekir izinlerini bildirmelidir. Bu geliştirme kalıbı İçerik sağlayıcı izinleri bölümü.

Android platformundaki yerleşik sağlayıcılardan biri de kullanıcı sözlüğü sağlayıcısıdır. Kullanıcının saklamak istediği standart olmayan kelimeleri depolar. Tablo 1, projenin veriler, bu sağlayıcının tablosunda aşağıdaki gibi görünebilir:

Tablo 1: Örnek kullanıcı sözlüğü tablosu.

kelime uygulama kimliği sıklığı yerel ayar _Kimlik
mapreduce kullanici1 100 en_US 1
precompiler kullanıcı14 200 fr_FR 2
applet kullanıcı2 225 tr_TR 3
const kullanici1 255 pt_BR 4
int kullanıcı5 100 tr_TR 5

1. tabloda her satır, standart bir sözlükte bulunabilir. Her sütun, o kelime için bir veri parçasını temsil eder; örneğin, ilk karşılaştığı yer. Sütun başlıkları, sağlayıcıdır. Örneğin, bir satırın yerel ayarına referans vermek için satırın locale sütununa başvurursunuz. Örneğin, _ID sütunu, Google Analytics 4'te veri gönderen bir birincil anahtar sütunu otomatik olarak sağlar.

Kullanıcı Sözlüğü Sağlayıcısı'ndan kelimelerin ve yerel ayarlarının listesini almak için ContentResolver.query() adlı kişiyi arayabilirsiniz. query() yöntemi ContentProvider.query() yöntemi Kullanıcı Sözlüğü Sağlayıcısı. Aşağıdaki kod satırlarında gösterilen ContentResolver.query() sesli arama:

Kotlin

// Queries the UserDictionary and returns results
cursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
        projection,                        // The columns to return for each row
        selectionClause,                   // Selection criteria
        selectionArgs.toTypedArray(),      // Selection criteria
        sortOrder                          // The sort order for the returned rows
)

Java

// Queries the UserDictionary and returns results
cursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    projection,                        // The columns to return for each row
    selectionClause,                   // Selection criteria
    selectionArgs,                     // Selection criteria
    sortOrder);                        // The sort order for the returned rows

Tablo 2'de, Arkadaş Bitkiler projesinin query(Uri,projection,selection,selectionArgs,sortOrder), SQL SELECT ifadesiyle eşleşiyor:

Tablo 2: SQL sorgusu ile karşılaştırıldığında query().

query() bağımsız değişken SELECT anahtar kelime/parametre Notlar
Uri FROM table_name Uri, table_name adlı sağlayıcıdaki tabloyla eşleniyor.
projection col,col,col,... projection, her satır için dahil edilen bir sütun dizisidir alındı.
selection WHERE col = value selection, satır seçiminde kullanılacak ölçütleri belirtir.
selectionArgs Tam olarak eşdeğeri yoktur. Seçilen bağımsız değişkenler ? seçim ifadesi.
sortOrder ORDER BY col,col,... sortOrder, satırların döndürülen Cursor.

İçerik URI'leri

İçerik URI'si, bir sağlayıcıdaki verileri tanımlayan bir URI'dir. İçerik URI'leri Tüm sağlayıcının (otoritesinin) sembolik adını ve bir bir tabloya (yol) işaret eden adlar girin. Aradığınızda bir istemci yöntemi kullanıyorsanız tablonun içerik URI'si bağımsız değişkendir.

Önceki kod satırlarında sabit değer CONTENT_URI, şunun içerik URI'sini barındırıyor: Kullanıcı Sözlüğü Sağlayıcısı'nın Words tablosu. ContentResolver nesne URI'nin yetkilisini ayrıştırır ve bunu sağlayıcıyı aşağıdakine göre çözmek için kullanır: bilinen sağlayıcıların yer aldığı bir sistem tablosuyla karşılaştırma. İlgili içeriği oluşturmak için kullanılan ContentResolver, daha sonra sorgu bağımsız değişkenlerini doğru sağlar.

ContentProvider, tabloya erişebilirsiniz. Sağlayıcının genellikle sunduğu her tablo için bir yolu vardır.

Önceki kod satırlarında, Words tablosunun tam URI'si şöyle olur:

content://user_dictionary/words
  • content:// dizesi, her zaman mevcut olan şemadır ve bunu bir içerik URI'si olarak tanımlar.
  • user_dictionary dizesi, sağlayıcının yetkilisidir.
  • words dizesi, tablonun yoludur.

Birçok sağlayıcı, kimlik değeri ekleyerek tablodaki tek bir satıra erişmenize olanak tanır bulunur. Örneğin, _ID değeri 4 kullanıyorsanız, şu içerik URI'sini kullanabilirsiniz:

Kotlin

val singleUri: Uri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4)

Java

Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

Bir satır kümesi alıp bunları güncellemek veya silmek istediğinizde genellikle kimlik değerlerini kullanırsınız bunlardan biri olabilir.

Not: Uri ve Uri.Builder sınıfları , dizelerden iyi biçimlendirilmiş URI nesneleri oluşturmaya yönelik kolaylık yöntemleri içerir. İlgili içeriği oluşturmak için kullanılan ContentUris sınıfı, kimlik değerlerinin eklenmesi için kolaylık yöntemleri içeriyor: URI'dır. Önceki snippet, Kullanıcı Sözlüğü Sağlayıcı içerik URI'sine kimlik eklemek için withAppendedId() kodunu kullanıyordu.

Sağlayıcıdan veri alma

Bu bölümde, Kullanıcı Sözlüğü Sağlayıcısı kullanılarak bir sağlayıcıdan nasıl veri alınacağı açıklanmaktadır açıklayacağım.

Daha net açıklamak gerekirse, bu bölümdeki kod snippet'leri Kullanıcı arayüzü iş parçacığında ContentResolver.query(). İçinde ancak gerçek kod, sorguları eşzamansız olarak ayrı bir iş parçacığında yapar. Şunları yapabilirsiniz: aşağıda açıklanan CursorLoader sınıfını kullanın: daha ayrıntılı olarak Yükleyiciler kılavuzu. Ayrıca, kod satırları yalnızca snippet'lerden oluşur. Tam bir bir uygulamadır.

Bir sağlayıcıdan veri almak için şu temel adımları uygulayın:

  1. Sağlayıcı için okuma erişimi izni isteyin.
  2. Sağlayıcıya sorgu gönderen kodu tanımlayın.

Okuma erişimi izni iste

Bir sağlayıcıdan veri almak için uygulamanızın sağlar. Çalışma zamanında bu izni isteyemezsiniz. Bunun yerine, <uses-permission>. öğesinin ve sağlar.

Manifest'inizde bu öğeyi belirttiğinizde bunu istemiş olursunuz ve izin vermiş olursunuz. Kullanıcılar uygulamanızı yüklediklerinde, arka arkaya isteyeceğim.

Kullandığınız sağlayıcıya ait okuma erişimi izninin tam adını da öğrenmek için diğer erişim izinlerinin adları arasında geçiş yapmak için sağlayıcının belgelerinden faydalanabilirsiniz.

Sağlayıcılara erişimde izinlerin rolü İçerik sağlayıcı izinleri bölümü.

Söz konusu izni Kullanıcı Sözlüğü Sağlayıcısı tanımlar android.permission.READ_USER_DICTIONARY ekler. Bu nedenle, sağlayıcıdan okumak isteyen uygulamanın bu izni istemesi gerekir.

Sorguyu oluşturma

Bir sağlayıcıdan veri almanın bir sonraki adımı sorgu oluşturmaktır. Aşağıdaki snippet Kullanıcı Sözlüğü Sağlayıcısı'na erişmek için bazı değişkenleri tanımlar:

Kotlin

// A "projection" defines the columns that are returned for each row
private val mProjection: Array<String> = arrayOf(
        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
private var selectionClause: String? = null

// Declares an array to contain selection arguments
private lateinit var selectionArgs: Array<String>

Java

// A "projection" defines the columns that are 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 selectionClause = null;

// Initializes an array to contain selection arguments
String[] selectionArgs = {""};

Sonraki snippet, ContentResolver.query() (Kullanıcı Sözlüğü kullanılarak) Örneğin, Provider (Sağlayıcı) Sağlayıcı istemci sorgusu, SQL sorgusuna benzer ve döndürülecek sütun kümesi, bir seçim ölçütü kümesi ve sıralama düzeni.

Sorgunun döndürdüğü sütun kümesine projeksiyon adı verilir ve değişken mProjection.

Alınacak satırları belirten ifade, seçim tümcesine bölünür ve seçim bağımsız değişkenleri. Seçim yan tümcesi, mantıksal ve boole ifadelerinin birleşiminden oluşur. sütun adlarını ve değerleri görebilirsiniz. Değişken mSelectionClause. Örneğin değiştirilebilir parametre olan ?, sorgu yöntemi kullanılarak mSelectionArgs değişkeni olan seçim bağımsız değişkenleri dizisinden.

Sonraki snippet'te kullanıcı bir kelime girmezse seçim ifadesi null ve sorgu, sağlayıcıdaki tüm kelimeleri döndürür. Kullanıcı giriş yaparsa anahtar kelime için seçim ifadesi UserDictionary.Words.WORD + " = ?" olarak ayarlanır ve seçim bağımsız değişkenleri dizisinin ilk öğesi, kullanıcının girdiği kelimeye ayarlanır.

Kotlin

/*
 * This declares a String array to contain the selection arguments.
 */
private lateinit var selectionArgs: Array<String>

// Gets a word from the UI
searchString = searchWord.text.toString()

// Insert code here to check for invalid or malicious input

// If the word is the empty string, gets everything
selectionArgs = searchString?.takeIf { it.isNotEmpty() }?.let {
    selectionClause = "${UserDictionary.Words.WORD} = ?"
    arrayOf(it)
} ?: run {
    selectionClause = null
    emptyArray<String>()
}

// Does a query against the table and returns a Cursor object
mCursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI, // The content URI of the words table
        projection,                       // The columns to return for each row
        selectionClause,                  // Either null or the word the user entered
        selectionArgs,                    // Either empty or the string the user entered
        sortOrder                         // The sort order for the returned rows
)

// Some providers return null if an error occurs, others throw an exception
when (mCursor?.count) {
    null -> {
        /*
         * Insert code here to handle the error. Be sure not to use the cursor!
         * You might want to call android.util.Log.e() to log this error.
         */
    }
    0 -> {
        /*
         * Insert code here to notify the user that the search is unsuccessful. This isn't
         * necessarily an error. You might 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
    }
}

Java

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] selectionArgs = {""};

// Gets a word from the UI
searchString = searchWord.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(searchString)) {
    // Setting the selection clause to null returns all words
    selectionClause = null;
    selectionArgs[0] = "";

} else {
    // Constructs a selection clause that matches the word that the user entered
    selectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments
    selectionArgs[0] = searchString;

}

// 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
    projection,                       // The columns to return for each row
    selectionClause,                  // Either null or the word the user entered
    selectionArgs,                    // Either empty or the string the user entered
    sortOrder);                       // 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 can
     * 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 is unsuccessful. This isn't necessarily
     * an error. You can 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

}

Bu sorgu, aşağıdaki SQL deyimine benzer:

SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC;

Bu SQL deyiminde, sözleşme sınıfı sabit değerleri yerine gerçek sütun adları kullanılır.

Kötü amaçlı girişlere karşı koru

İçerik sağlayıcı tarafından yönetilen veriler, güvenilir olmayan harici kaynaklar dahil olmak üzere bir SQL veritabanındaysa verilerin ham SQL ifadelerine yüklenmesi SQL yerleştirmeye yol açabilir.

Şu seçim deyimini göz önünde bulundurun:

Kotlin

// Constructs a selection clause by concatenating the user's input to the column name
var selectionClause = "var = $mUserInput"

Java

// Constructs a selection clause by concatenating the user's input to the column name
String selectionClause = "var = " + userInput;

Bunu yaparsanız kullanıcının SQL ifadenize kötü amaçlı SQL eklemesine izin vermiş olursunuz. Örneğin, kullanıcı "nothing; TABLO AÇILIR *;" Bu, mUserInput için sonuç, var = nothing; DROP TABLE *; seçim ifadesiyle sonuçlanır.

seçim yan tümcesi bir SQL deyimi olarak kabul edilir; bu, sağlayıcının tüm anahtar kelimeleri sağlayıcı yakalayacak şekilde ayarlanmadığı sürece, temel SQLite veritabanındaki SQL yerleştirme denemeleri.

Bu sorunu önlemek için, değiştirilebilir öğe olarak ? kullanan bir seçim ifadesi kullanın parametresini kullanabilirsiniz. Bu şekilde, kullanıcı bir SQL ifadesinin parçası olarak yorumlanmak yerine doğrudan sorguya bağlıdır. SQL olarak işlenmediğinden, kullanıcı girişi kötü amaçlı SQL yerleştiremez. Bunun yerine birleştirmeyi kullanıcı girişini dahil etmek için kullanın, şu seçim ifadesini kullanın:

Kotlin

// Constructs a selection clause with a replaceable parameter
var selectionClause = "var = ?"

Java

// Constructs a selection clause with a replaceable parameter
String selectionClause =  "var = ?";

Seçim bağımsız değişkenleri dizisini şu şekilde ayarlayın:

Kotlin

// Defines a mutable list to contain the selection arguments
var selectionArgs: MutableList<String> = mutableListOf()

Java

// Defines an array to contain the selection arguments
String[] selectionArgs = {""};

Seçim bağımsız değişkenleri dizisine aşağıdaki gibi bir değer girin:

Kotlin

// Adds the user's input to the selection argument
selectionArgs += userInput

Java

// Sets the selection argument to the user's input
selectionArgs[0] = userInput;

Değiştirilebilir parametre olarak ? kullanan bir seçim ifadesi ve seçim bağımsız değişkenleri dizisi, sağlayıcı her zaman geçerli olmasa bile bir seçimi belirtmek için nasıl çalıştıracağınızı öğreneceksiniz.

Sorgu sonuçlarını görüntüle

ContentResolver.query() istemci yöntemi her zaman sorgunun etiketi tarafından belirtilen sütunları içeren bir Cursor sorgunun seçim ölçütüyle eşleşen satırlar için projeksiyon. CEVAP Cursor nesnesi, içerdiği satır ve sütunlara rastgele okuma erişimi sağlar içerir.

Cursor yöntemlerini kullanarak sonuçlarını incelemeli, her sütunun veri türünü belirleme, verileri bir sütundan çıkarma ve diğer sütunları özelliklerini ekler.

Bazı Cursor uygulamaları otomatik olarak sağlayıcının verileri değiştiğinde nesneyi güncelleme, gözlemci nesnesinde yöntemleri tetikleme (Cursor veya her ikisi de değiştiğinde)

Not: Sağlayıcı, nesneden ibaret değildir. Örneğin, Kişi Sağlayıcı bazı sütunların erişimini senkronizasyon bağdaştırıcılarını bir etkinlik veya hizmete döndürmez.

Seçim ölçütleriyle eşleşen satır yoksa sağlayıcı Cursor nesnesini döndürür Cursor.getCount() 0 - diğer bir deyişle, boş bir imleç.

Dahili bir hata oluşursa sorgunun sonuçları ilgili sağlayıcıya bağlıdır. Projenin null hatasını döndürür, yoksa Exception hatası verebilir.

Cursor bir satır listesi olduğundan, bir Cursor öğesinin içeriği, onu bir ListView SimpleCursorAdapter kullanarak.

Aşağıdaki snippet, önceki snippet'teki kodu devam ettirir. Bu, Cursor içeren SimpleCursorAdapter nesne sorgu tarafından alınır ve bu nesneyi bir ListView.

Kotlin

// Defines a list of columns to retrieve from the Cursor and load into an output row
val wordListColumns : Array<String> = arrayOf(
        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 receive the Cursor columns for each row
val wordListItems = intArrayOf(R.id.dictWord, R.id.locale)

// Creates a new SimpleCursorAdapter
cursorAdapter = SimpleCursorAdapter(
        applicationContext,             // The application's Context object
        R.layout.wordlistrow,           // A layout in XML for one row in the ListView
        mCursor,                        // The result from the query
        wordListColumns,                // A string array of column names in the cursor
        wordListItems,                  // An integer array of view IDs in the row layout
        0                               // Flags (usually none are needed)
)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter)

Java

// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] wordListColumns =
{
    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 receive the Cursor columns for each row
int[] wordListItems = { R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter
cursorAdapter = 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
    wordListColumns,                       // A string array of column names in the cursor
    wordListItems,                         // An integer array of view IDs in the row layout
    0);                                    // Flags (usually none are needed)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter);

Not: Bir ListView öğesini Cursor, imleç _ID adlı bir sütun içermelidir. Bu nedenle, daha önce gösterilen sorgu_ID Words tablosunu ListView göstermese bile. Bu kısıtlama, çoğu sağlayıcının her bir veri için neden bir _ID sütunu nasıl hazırlanabileceğini.

Sorgu sonuçlarından veri alma

Sorgu sonuçlarını görüntülemenin yanı sıra, başka görevler için de kullanabilirsiniz. Örneğin, Örneğin, Kullanıcı Sözlüğü Sağlayıcı'dan yazımları getirebilir ve daha sonra, diğer sağlayıcılar. Bunu yapmak için, aşağıdaki örnekte gösterildiği gibi Cursor içindeki satırlar üzerinde yineleme yaparsınız:

Kotlin

/*
* Only executes if the cursor is valid. The User Dictionary Provider returns null if
* an internal error occurs. Other providers might throw an Exception instead of returning null.
*/
mCursor?.apply {
    // Determine the column index of the column named "word"
    val index: Int = getColumnIndex(UserDictionary.Words.WORD)

    /*
     * 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 get an
     * exception.
     */
    while (moveToNext()) {
        // Gets the value from the column
        newWord = getString(index)

        // Insert code here to process the retrieved word
        ...
        // End of while loop
    }
}

Java

// 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 might 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 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
}

Cursor uygulamaları birkaç "get" içeriyor yöntemleri veri almanın başka yolları da var. Örneğin, önceki snippet'te getString() kullanır. Ayrıca, getType() yöntemi, sütunun veri türünü belirtir.

Sorgu sonucu kaynaklarını serbest bırakın

Cursor nesne olmalıdır artık ihtiyaç duyulmuyorlarsa kapatılabilir, böylece bunlarla ilişkili kaynaklar serbest bırakılır gerekir. Bu işlem, close() veya Java programlama dilinde bir try-with-resources ifadesi veya Kotlin programlama dilinde use() işlevi.

İçerik sağlayıcı izinleri

Bir sağlayıcının uygulaması, diğer uygulamaların sahip olması gereken izinleri belirtebilir ve sağlayıcının verilerine erişebilir. Bu izinler, kullanıcının hangi verileri emin olun. Sağlayıcının gereksinimlerine bağlı olarak diğer uygulamalar Sağlayıcıya erişmek için ihtiyaç duydukları izinleri isteme. Son kullanıcılar istenen izin vermiş olursunuz.

Bir sağlayıcının uygulaması herhangi bir izin belirtmezse diğer uygulamaların sağlayıcı dışa aktarılmadığı sürece sağlayıcının verilerine erişemez. Ayrıca bileşenler bağlantısından bağımsız olarak her zaman tam okuma ve yazma erişimine izin verilmez.

Kullanıcı Sözlüğü Sağlayıcısı, android.permission.READ_USER_DICTIONARY içinden veri alma izni. Sağlayıcının ayrı bir android.permission.WRITE_USER_DICTIONARY veri ekleme, güncelleme veya silme izni.

Bir uygulama, bir sağlayıcıya erişmek için gereken izinleri almak amacıyla onlardan <uses-permission>. öğesine sahip olmayabilir. Android Paket Yöneticisi uygulamayı yüklediğinde, kullanıcı uygulamanın istediği tüm izinleri onaylamalıdır. Kullanıcı onaylarsa Paket Yöneticisi, yükleme işlemine devam eder. Kullanıcı bunları onaylamazsa Paket Yöneticisi yükleme işlemini durdurur.

Aşağıdaki örnek <uses-permission>. öğesi, Kullanıcı Sözlüğü Sağlayıcısı'na okuma erişimi ister:

<uses-permission android:name="android.permission.READ_USER_DICTIONARY">

İzinlerin sağlayıcı erişimi üzerindeki etkisi şu makalede daha ayrıntılı olarak açıklanmıştır: Güvenlik ipuçları.

Veri ekleme, güncelleme ve silme

Bir sağlayıcıdan veri aldığınız gibi Google Analytics 360 ve verileri değiştirmek için sağlayıcı müşterisi ve sağlayıcının ContentProvider. Şunlara aktarılan bağımsız değişkenlerle bir ContentResolver yöntemini çağırıyorsunuz: karşılık gelen ContentProvider yöntemini kullanır. Sağlayıcı ve sağlayıcı ve işlemler arası iletişimi otomatik olarak yönetir.

Veri ekle

Bir sağlayıcıya veri eklemek için ContentResolver.insert(). yöntemidir. Bu yöntem sağlayıcıya yeni bir satır ekler ve bu satır için bir içerik URI'si döndürür. Aşağıdaki snippet'te, yeni bir kelimenin Kullanıcı Sözlüğü Sağlayıcısı'na nasıl ekleneceği gösterilmektedir:

Kotlin

// Defines a new Uri object that receives the result of the insertion
lateinit var newUri: Uri
...
// Defines an object to contain the new values to insert
val newValues = ContentValues().apply {
    /*
     * Sets the values of each column and inserts the word. The arguments to the "put"
     * method are "column name" and "value".
     */
    put(UserDictionary.Words.APP_ID, "example.user")
    put(UserDictionary.Words.LOCALE, "en_US")
    put(UserDictionary.Words.WORD, "insert")
    put(UserDictionary.Words.FREQUENCY, "100")

}

newUri = contentResolver.insert(
        UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
        newValues                           // The values to insert
)

Java

// Defines a new Uri object that receives the result of the insertion
Uri newUri;
...
// Defines an object to contain the new values to insert
ContentValues newValues = new ContentValues();

/*
 * Sets the values of each column and inserts the word. The arguments to the "put"
 * method are "column name" and "value".
 */
newValues.put(UserDictionary.Words.APP_ID, "example.user");
newValues.put(UserDictionary.Words.LOCALE, "en_US");
newValues.put(UserDictionary.Words.WORD, "insert");
newValues.put(UserDictionary.Words.FREQUENCY, "100");

newUri = getContentResolver().insert(
    UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
    newValues                           // The values to insert
);

Yeni satıra ilişkin veriler tek bir ContentValues nesnesine yerleştirilir. Bu nesne, tek satırlık bir imlece benzer. Bu nesnedeki sütunların, hiçbir değer belirtmek istemiyorsanız bunun yerine bir sütun ayarlayabilirsiniz. ContentValues.putNull() kullanarak null adresine.

Önceki snippet, _ID sütununu eklemiyor, çünkü bu sütun korunuyor otomatik olarak oluşturur. Sağlayıcı,_ID eklendi. Sağlayıcılar genellikle bu değeri tablonun birincil anahtarı olarak kullanır.

newUri işlevinde döndürülen içerik URI'si, şu biçimdedir:

content://user_dictionary/words/<id_value>

<id_value>, yeni satırda _ID sütununun içeriğidir. Çoğu sağlayıcı bu içerik URI'si biçimini otomatik olarak algılar ve daha sonra istenen aynı satır üzerinde işlem yapabilirsiniz.

Döndürülen Uri öğesinden _ID değerini almak için şunu çağırın: ContentUris.parseId().

Verileri güncelle

Bir satırı güncellemek için güncellenmiş bir ContentValues nesnesi kullanın değerleri ekleyin. Kullandığınız istemci yöntemi ContentResolver.update() Yalnızca eklemeniz gereken değerlerini, güncellediğiniz sütunlar için ContentValues nesnesine ekleyin. Şu durumda: bir sütunun içeriğini temizlemek istiyorsanız değeri null olarak ayarlayın.

Aşağıdaki snippet, yerel ayarı "en" diline sahip olan tüm satırları yerel ayarı null. Döndürülen değer, güncellenen satır sayısıdır.

Kotlin

// Defines an object to contain the updated values
val updateValues = ContentValues().apply {
    /*
     * Sets the updated value and updates the selected words.
     */
    putNull(UserDictionary.Words.LOCALE)
}

// Defines selection criteria for the rows you want to update
val selectionClause: String = UserDictionary.Words.LOCALE + "LIKE ?"
val selectionArgs: Array<String> = arrayOf("en_%")

// Defines a variable to contain the number of updated rows
var rowsUpdated: Int = 0
...
rowsUpdated = contentResolver.update(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        updateValues,                      // The columns to update
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

Java

// Defines an object to contain the updated values
ContentValues updateValues = new ContentValues();

// Defines selection criteria for the rows you want to update
String selectionClause = UserDictionary.Words.LOCALE +  " LIKE ?";
String[] selectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows
int rowsUpdated = 0;
...
/*
 * Sets the updated value and updates the selected words.
 */
updateValues.putNull(UserDictionary.Words.LOCALE);

rowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    updateValues,                      // The columns to update
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

Telefon ettiğinizde kullanıcı girişini temizleyin ContentResolver.update() Şu konu hakkında daha fazla bilgi edinmek için: Kötü amaçlı girişlere karşı koruma bölümünü okuyun.

Verileri sil

Satır silmek, satır verilerini almaya benzer. Satırlar için seçim ölçütlerini belirtirsiniz istemci yöntemi, silinen satır sayısını döndürür. Aşağıdaki snippet, uygulama kimliği "user" ile eşleşen satırları siler. Yöntem, Silinen satır sayısı.

Kotlin

// Defines selection criteria for the rows you want to delete
val selectionClause = "${UserDictionary.Words.APP_ID} LIKE ?"
val selectionArgs: Array<String> = arrayOf("user")

// Defines a variable to contain the number of rows deleted
var rowsDeleted: Int = 0
...
// Deletes the words that match the selection criteria
rowsDeleted = contentResolver.delete(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

Java

// Defines selection criteria for the rows you want to delete
String selectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] selectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted
int rowsDeleted = 0;
...
// Deletes the words that match the selection criteria
rowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

Telefon ettiğinizde kullanıcı girişini temizleyin ContentResolver.delete() Şu konu hakkında daha fazla bilgi edinmek için: Kötü amaçlı girişlere karşı koruma bölümünü okuyun.

Sağlayıcı veri türleri

İçerik sağlayıcılar birçok farklı veri türü sunabilir. Kullanıcı Sözlüğü Sağlayıcısı yalnızca metinle beraber, sağlayıcılar aşağıdaki biçimleri de sunabilir:

  • Tam sayı
  • uzun tam sayı (uzun)
  • kayan nokta
  • uzun kayan nokta (çift)

Sağlayıcıların sıklıkla kullandığı bir diğer veri türü de 64 KB baytlık dizi. Cursor sınıfı "get" yöntemlerine göz atın.

Bir sağlayıcıdaki her sütunun veri türü genellikle sağlayıcının belgelerinde listelenir. Kullanıcı Sözlük Sağlayıcısı'na ait veri türleri, referans dokümanlarda listelenmiştir UserDictionary.Words. Sözleşmeli sınıflar Sözleşmeli sınıflar bölümünde açıklanmıştır. Veri türünü, Cursor.getType() işlevini çağırarak da belirleyebilirsiniz.

Sağlayıcılar, tanımladıkları her içerik URI'si için MIME veri türü bilgilerini de korur. Şunları yapabilirsiniz: uygulamanızın sağlayıcı tarafından sunulan veya MIME türüne göre işleme türü seçilebilir. Genellikle MIME türü: Karmaşık bir MIME türü olabilir.

Örneğin, ContactsContract.Data Kişiler Sağlayıcısı tablosunda bulunan tablo, her bir sağlayıcıda depolanan kişi verilerinin türünü etiketlemek için MIME türlerini kullanır satırı. İçerik URI'sine karşılık gelen MIME türünü almak için ContentResolver.getType()

MIME türü referansı bölümünde hem standart hem de özel MIME türlerinin söz dizimini destekler.

Alternatif sağlayıcı erişimi biçimleri

Uygulama geliştirmede üç alternatif sağlayıcı erişimi biçimi önemlidir:

  • Toplu erişim: Aşağıdaki yöntemlerle bir grup erişim çağrısı oluşturabilirsiniz: ContentProviderOperation sınıfını kullanmak ve ardından ContentResolver.applyBatch().
  • Eşzamansız sorgular: Sorguları ayrı bir iş parçacığında yapın. Şunları yapabilirsiniz: CursorLoader nesnesi kullanın. Bu bölümdeki örnekler Yükleyiciler kılavuzu gösterimi bunu nasıl yapacağınızı öğrenebilirsiniz.
  • Amaç kullanarak veri erişimi: Amaç gönderemeseniz bile doğrudan sağlayıcıya gönderirseniz sağlayıcının uygulamasına bir intent gönderebilirsiniz. verilerini değiştirmek için genellikle en iyi donanıma sahiptir.

Toplu erişim ve intent kullanarak değiştirme işlemi aşağıdaki bölümlerde açıklanmıştır.

Toplu erişim

Sağlayıcıya toplu erişim, çok sayıda satır eklemek için aynı yöntem çağrısında birden çok tablolarda yer alan satırlara ve genellikle İşlem olarak işlem sınırlarının ötesine geçen işlemler, atomik işlem olarak adlandırılır.

Bir sağlayıcıya toplu modda erişmek için ContentProviderOperation nesnelik bir dizi oluşturabilir ve ardından bir içerik sağlayıcıya göndererek ContentResolver.applyBatch(). Geçerseniz içerik sağlayıcının bu yöntem için yetkilendirmesi yapar.

Bu şekilde, dizideki her ContentProviderOperation nesnesi çalışır karşılaştırabilirsiniz. ContentResolver.applyBatch() işlevine yapılan bir çağrı bir dizi sonuç döndürür.

ContactsContract.RawContacts sözleşme sınıfının açıklaması Toplu eklemeyi gösteren bir kod snippet'i içerir.

Amaçları kullanarak veri erişimi

Amaçlar, içerik sağlayıcıya dolaylı erişim sağlayabilir. Kullanıcının erişmesine izin verebilirsiniz bir sağlayıcıdaki diğer verileri izinleri olan bir uygulamadan veya bir bir uygulamadır.

Geçici izinlerle erişim elde etme

Uygun erişiminiz olmasa bile bir içerik sağlayıcıdaki verilere erişebilirsiniz bu izinlere sahip olan bir uygulamaya intent göndererek URI izinleri içeren bir sonuç niyeti geri alma. Bunlar, alan adını alan etkinliğe kadar devam eden belirli bir içerik URI'sına yönelik izinlerdir. yardımcı olur. Kalıcı izinlere sahip olan uygulama geçici izin verir izinleri için sonuç amacında bir işaret ayarlayın:

Not: Bu flag'ler sağlayıcıya genel okuma veya yazma erişimi vermez yetkileri içerik URI'sinde bulunur. Erişim yalnızca URI'nın kendisi içindir.

Başka bir uygulamaya içerik URI'leri gönderirken aşağıdakilerden en az birini ekleyin işaretidir. İşaretler, alan adı alan tüm uygulamalara aşağıdaki özellikleri sağlar bir amaç türündeyse ve Android 11 (API düzeyi 30) veya sonraki sürümleri hedefliyorsa:

Bir sağlayıcı, android:grantUriPermissions. özelliğinin <provider> öğesinin yanı sıra <grant-uri-permission> alt öğesi <provider> öğesine dokunun. URI izinleri mekanizması bkz. Android'de izinler rehberini inceleyin.

Örneğin, Kişi Sağlayıcı'da bir kişinin verilerini almasanız bile READ_CONTACTS iznine sahip olmanız gerekir. Şunu yapmak isteyebilirsiniz: doğum günündeki kişiye e-selamlama gönderen bir uygulama içinde bunu yapabilirsiniz. Şunun yerine: READ_CONTACTS istiyor. Bu da size tüm ve tüm bilgileri, kullanıcının hangi bilgileri uygulamanızın kullandığı kişiler. Bunun için aşağıdaki işlemi uygulayın:

  1. Uygulamanızda, işlemi içeren bir intent gönderin ACTION_PICK ve "kişiler" MIME türü CONTENT_ITEM_TYPE, yöntem startActivityForResult().
  2. Bu intent, reklamverenin amaç filtresiyle eşleşir. Kişiler uygulamasının "seçimi" söz konusu etkinlik ön plana gelir.
  3. Seçim etkinliğinde, kullanıcı bir iletişim bilgilerini girin. Bu durumda seçim etkinliği setResult(resultcode, intent). bir niyet oluşturabilirsiniz. Amaç, içerik URI'sini barındırır kullanıcının seçtiği kişi ve "ekstralar" bayraklar FLAG_GRANT_READ_URI_PERMISSION Bu işaretler URI verir tarafından işaret edilen kişinin verilerini okuması için uygulama izninizin içerik URI'si. Ardından seçim etkinliği, finish() öğesini çağırarak uygulamanıza dönün.
  4. Etkinliğiniz ön plana geri döner ve sistem, etkinliğinizin onActivityResult(). yöntemidir. Bu yöntem, uygulamasıdır.
  5. Sonuç amacındaki içerik URI'si ile kişinin verilerini okuyabilirsiniz Kalıcı okuma erişimi izni istememiş olsanız bile Kişiler Sağlayıcısı'ndan manifest dosyanızdaki sağlayıcıya ekleyin. Ardından, kişinin doğum günü bilgilerini öğrenebilirsiniz veya e-posta adresine gidip e-selamlama mesajını gönderin.

Başka bir uygulama kullan

Kullanıcının erişim izninizin olmadığı verileri değiştirmesine olanak sağlamanın bir başka yolu da kullanıcının gerekli izinlere sahip bir uygulamayı etkinleştirmesini sağlar.

Örneğin, Takvim uygulaması aşağıdakileri etkinleştirmenizi sağlayan ACTION_INSERT intent'i içerir: kullanıcı arayüzü ekleyin. "Ekstralar" uygulama bu amaca yönelik verileri önceden doldurmak için kullanılır. Düzenli etkinlikler karmaşık bir söz dizimine sahip olduğundan tercih edilen Etkinlikleri Takvim Sağlayıcısı'na eklemenin yolu, Takvim uygulamasını ACTION_INSERT'ı tıklayın ve kullanıcının etkinliği oraya eklemesine izin verin.

Yardımcı uygulama kullanarak verileri görüntüleyin

Uygulamanızın erişim izinleri varsa, başka bir uygulamada veri görüntüleme niyetinde olmalıdır. Örneğin, Takvim uygulaması Belirli bir tarihi veya etkinliği gösteren ACTION_VIEW niyeti. Bu, kendi kullanıcı arayüzünüzü oluşturmak zorunda kalmadan takvim bilgilerini görüntülemenizi sağlar. Bu özellik hakkında daha fazla bilgi edinmek için Takvim sağlayıcısına genel bakış.

Niyeti gönderdiğiniz uygulamanın, aynı uygulama tarafından sağlayıcıyla ilişkilendirilebilir. Örneğin, Sağlayıcı ile iletişime geçin, ardından bir ACTION_VIEW niyeti gönderin bir resim görüntüleyiciye kişinin resminin içerik URI'sını içerir.

Sözleşmeli sınıflar

Sözleşme sınıfı, uygulamaların içerik URI'leri ile çalışmasına yardımcı olan sabit değerleri tanımlar. içerik sağlayıcının adları, amaç işlemleri ve diğer özellikleri. Sözleşmeli sınıflar otomatik olarak eklenir. Bunları sağlayıcının geliştiricisi tanımlamalı ve daha sonra diğer geliştiricilerin kullanımına sunun. Android'e dahil olan sağlayıcıların çoğu platform için android.provider paketinde ilgili sözleşme sınıfları bulunuyor.

Örneğin, Kullanıcı Sözlük Sağlayıcısı'nın bir sözleşme sınıfı vardır. İçerik URI'si ve sütun adı sabitleri içeren UserDictionary. İlgili içeriği oluşturmak için kullanılan Words tablosunun içerik URI'si sabit değerde tanımlanır UserDictionary.Words.CONTENT_URI. UserDictionary.Words sınıfı, sütun adı sabitlerini de içerir. Bunlar bu kılavuzdaki örnek snippet'lerde kullanılır. Örneğin, bir sorgu projeksiyonu şu şekilde tanımlanır:

Kotlin

val projection : Array<String> = arrayOf(
        UserDictionary.Words._ID,
        UserDictionary.Words.WORD,
        UserDictionary.Words.LOCALE
)

Java

String[] projection =
{
    UserDictionary.Words._ID,
    UserDictionary.Words.WORD,
    UserDictionary.Words.LOCALE
};

Diğer bir sözleşme sınıfı ise Kişi Sağlayıcı için ContactsContract. Bu sınıfın referans belgeleri örnek kod snippet'lerini içerir. Bunlardan biri alt sınıflar, ContactsContract.Intents.Insert, bir sözleşmedir amaç ve amaç verileri için sabit değerler içeren bir sınıftır.

MIME türü referansı

İçerik sağlayıcılar; standart MIME medya türlerini, özel MIME türü dizelerini veya her ikisini birden döndürebilir.

MIME türleri aşağıdaki biçimdedir:

type/subtype

Örneğin, iyi bilinen text/html MIME türü text türüne ve html alt türünü seçin. Sağlayıcı, URI için bu türü döndürürse bu, URI kullanılarak yapılan sorgu, HTML etiketleri içeren metni döndürür.

Sağlayıcıya özgü MIME türleri olarak da adlandırılan özel MIME türü dizelerinde daha fazla karmaşık type ve subtype değerleri. Birden fazla satır için tür değeri her zaman şu olur:

vnd.android.cursor.dir

Tek bir satır için tür değeri her zaman şu olur:

vnd.android.cursor.item

subtype, sağlayıcıya özeldir. Android yerleşik sağlayıcıları genellikle basit bir alt türdür. Örneğin, Kişiler uygulaması bir telefon numarası için satır oluşturduğunda, satırda aşağıdaki MIME türünü ayarlar:

vnd.android.cursor.item/phone_v2

Alt tür değeri: phone_v2.

Diğer sağlayıcı geliştiriciler, sağlayıcının koduna bağlı olarak kendi alt tür kalıplarını oluşturabilirler. yetki ve tablo adlarına yer verir. Örneğin, tren tarifeleri içeren bir sağlayıcı düşünün. Sağlayıcının yetkisi com.example.trains şeklindedir ve tabloları içerir Satır1, Satır2 ve Satır3. Satır1 tablosunun aşağıdaki içerik URI'sine yanıt olarak:

content://com.example.trains/Line1

sağlayıcı şu MIME türünü döndürür:

vnd.android.cursor.dir/vnd.example.line1

Satır2 tablosunun 5. satırı için aşağıdaki içerik URI'sine yanıt olarak:

content://com.example.trains/Line2/5

sağlayıcı şu MIME türünü döndürür:

vnd.android.cursor.item/vnd.example.line2

Çoğu içerik sağlayıcı, kullandıkları MIME türleri için sözleşme sınıfı sabitleri tanımlar. İlgili içeriği oluşturmak için kullanılan Kişi Sağlayıcı sözleşme sınıfı ContactsContract.RawContacts, Örneğin, Şu MIME türü için CONTENT_ITEM_TYPE: tek bir ham kişi satırı ekleyin.

Tek satırlar için İçerik URI'leri İçerik URI'leri bölümüne bakın.