Android - Fornitori di contenuti

Un componente del provider di contenuti fornisce i dati da un'applicazione ad altre su richiesta. Tali richieste vengono gestite dai metodi della classe ContentResolver. Un fornitore di contenuti può utilizzare diversi modi per archiviare i propri dati e i dati possono essere archiviati in un database, in file o persino su una rete.

Fornitore di contenuti

sometimes it is required to share data across applications. This is where content providers become very useful.

I fornitori di contenuti consentono di centralizzare i contenuti in un unico posto e di accedervi da molte applicazioni diverse secondo necessità. Un fornitore di contenuti si comporta in modo molto simile a un database in cui è possibile interrogarlo, modificarne il contenuto, nonché aggiungere o eliminare contenuto utilizzando i metodi insert (), update (), delete () e query (). Nella maggior parte dei casi questi dati vengono archiviati in un fileSQlite Banca dati.

Un fornitore di contenuti viene implementato come una sottoclasse di ContentProvider classe e deve implementare un set standard di API che consentano ad altre applicazioni di eseguire transazioni.

public class My Application extends  ContentProvider {
}

URI di contenuto

Per interrogare un provider di contenuti, specificare la stringa di query sotto forma di un URI che ha il seguente formato:

<prefix>://<authority>/<data_type>/<id>

Ecco i dettagli di varie parti dell'URI:

Suor n Parte e descrizione
1

prefix

Questo è sempre impostato su content: //

2

authority

Specifica il nome del fornitore di contenuti, ad esempio contatti , browser ecc. Per i fornitori di contenuti di terze parti, questo potrebbe essere il nome completo, come com.tutorialspoint.statusprovider

3

data_type

Indica il tipo di dati forniti da questo particolare provider. Ad esempio, se stai ottenendo tutti i contatti dal provider di contenuti Contatti , il percorso dati sarebbe persone e l'URI sarebbe simile a questo contenuto: // contatti / persone

4

id

Specifica il record specifico richiesto. Ad esempio, se stai cercando il numero di contatto 5 nel provider di contenuti Contatti, l'URI sarà simile a questo contenuto: // contatti / persone / 5 .

Crea fornitore di contenuti

Ciò comporta una serie di semplici passaggi per creare il proprio fornitore di contenuti.

  • Prima di tutto è necessario creare una classe Content Provider che estenda la ContentProviderbaseclass.

  • In secondo luogo, è necessario definire l'indirizzo URI del provider di contenuti che verrà utilizzato per accedere al contenuto.

  • Successivamente dovrai creare il tuo database per mantenere il contenuto. Di solito, Android utilizza il database SQLite e il framework deve sovrascrivere il metodo onCreate () che utilizzerà il metodo SQLite Open Helper per creare o aprire il database del provider. Quando la tua applicazione viene lanciata, il gestore onCreate () di ciascuno dei suoi Content Provider viene chiamato sul thread principale dell'applicazione.

  • Successivamente dovrai implementare le query del fornitore di contenuti per eseguire diverse operazioni specifiche del database.

  • Infine registra il tuo fornitore di contenuti nel tuo file di attività utilizzando il tag <provider>.

Ecco l'elenco dei metodi che devi sovrascrivere nella classe Content Provider per far funzionare il tuo Content Provider:

Fornitore di contenuti

  • onCreate() Questo metodo viene chiamato all'avvio del provider.

  • query()Questo metodo riceve una richiesta da un client. Il risultato viene restituito come oggetto Cursor.

  • insert()Questo metodo inserisce un nuovo record nel fornitore di contenuti.

  • delete() Questo metodo elimina un record esistente dal fornitore di contenuti.

  • update() Questo metodo aggiorna un record esistente dal fornitore di contenuti.

  • getType() Questo metodo restituisce il tipo MIME dei dati all'URI specificato.

Esempio

Questo esempio ti spiegherà come creare il tuo ContentProvider . Quindi seguiamo i seguenti passaggi in modo simile a quello che abbiamo seguito durante la creazione di Hello World Example -

Passo Descrizione
1 Utilizzerai Android StudioIDE per creare un'applicazione Android e chiamarla My Application in un pacchetto com.example.MyApplication , con Activity vuota.
2 Modificare il file di attività principale MainActivity.java per aggiungere due nuovi metodi onClickAddName () e onClickRetrieveStudents () .
3 Crea un nuovo file java chiamato StudentsProvider.java nel pacchetto com.example.MyApplication per definire il tuo provider effettivo e i metodi associati.
4 Registra il tuo provider di contenuti nel tuo file AndroidManifest.xml utilizzando il tag <provider ... />
5 Modifica il contenuto predefinito del file res / layout / activity_main.xml per includere una piccola GUI per aggiungere i record degli studenti.
6 Non c'è bisogno di cambiare string.xml.Android Studio si prende cura del file string.xml.
7 Esegui l'applicazione per avviare l'emulatore Android e verifica il risultato delle modifiche apportate nell'applicazione.

Di seguito è riportato il contenuto del file di attività principale modificato src/com.example.MyApplication/MainActivity.java. Questo file può includere ciascuno dei metodi fondamentali del ciclo di vita. Abbiamo aggiunto due nuovi metodi onClickAddName () e onClickRetrieveStudents () per gestire l'interazione dell'utente con l'applicazione.

package com.example.MyApplication;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;

import android.content.ContentValues;
import android.content.CursorLoader;

import android.database.Cursor;

import android.view.Menu;
import android.view.View;

import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
   }
   public void onClickAddName(View view) {
      // Add a new student record
      ContentValues values = new ContentValues();
      values.put(StudentsProvider.NAME,
         ((EditText)findViewById(R.id.editText2)).getText().toString());

      values.put(StudentsProvider.GRADE,
         ((EditText)findViewById(R.id.editText3)).getText().toString());

      Uri uri = getContentResolver().insert(
         StudentsProvider.CONTENT_URI, values);

      Toast.makeText(getBaseContext(),
         uri.toString(), Toast.LENGTH_LONG).show();
   }
   public void onClickRetrieveStudents(View view) {
      // Retrieve student records
      String URL = "content://com.example.MyApplication.StudentsProvider";

      Uri students = Uri.parse(URL);
      Cursor c = managedQuery(students, null, null, null, "name");

      if (c.moveToFirst()) {
         do{
            Toast.makeText(this,
               c.getString(c.getColumnIndex(StudentsProvider._ID)) +
                  ", " +  c.getString(c.getColumnIndex( StudentsProvider.NAME)) +
                     ", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)),
            Toast.LENGTH_SHORT).show();
         } while (c.moveToNext());
      }
   }
}

Crea un nuovo file StudentsProvider.java nel pacchetto com.example.MyApplication e di seguito è riportato il contenuto disrc/com.example.MyApplication/StudentsProvider.java -

package com.example.MyApplication;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;

import android.database.Cursor;
import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;
import android.text.TextUtils;

public class StudentsProvider extends ContentProvider {
   static final String PROVIDER_NAME = "com.example.MyApplication.StudentsProvider";
   static final String URL = "content://" + PROVIDER_NAME + "/students";
   static final Uri CONTENT_URI = Uri.parse(URL);

   static final String _ID = "_id";
   static final String NAME = "name";
   static final String GRADE = "grade";

   private static HashMap<String, String> STUDENTS_PROJECTION_MAP;

   static final int STUDENTS = 1;
   static final int STUDENT_ID = 2;

   static final UriMatcher uriMatcher;
   static{
      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
      uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS);
      uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID);
   }

   /**
      * Database specific constant declarations
   */
   
   private SQLiteDatabase db;
   static final String DATABASE_NAME = "College";
   static final String STUDENTS_TABLE_NAME = "students";
   static final int DATABASE_VERSION = 1;
   static final String CREATE_DB_TABLE =
      " CREATE TABLE " + STUDENTS_TABLE_NAME +
         " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
         " name TEXT NOT NULL, " +
         " grade TEXT NOT NULL);";

   /**
      * Helper class that actually creates and manages
      * the provider's underlying data repository.
   */
   
   private static class DatabaseHelper extends SQLiteOpenHelper {
      DatabaseHelper(Context context){
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
      }

      @Override
      public void onCreate(SQLiteDatabase db) {
         db.execSQL(CREATE_DB_TABLE);
      }

      @Override
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         db.execSQL("DROP TABLE IF EXISTS " +  STUDENTS_TABLE_NAME);
         onCreate(db);
      }
   }

   @Override
   public boolean onCreate() {
      Context context = getContext();
      DatabaseHelper dbHelper = new DatabaseHelper(context);

      /**
         * Create a write able database which will trigger its
         * creation if it doesn't already exist.
      */
         
      db = dbHelper.getWritableDatabase();
      return (db == null)? false:true;
   }

   @Override
   public Uri insert(Uri uri, ContentValues values) {
      /**
         * Add a new student record
      */
      long rowID = db.insert(	STUDENTS_TABLE_NAME, "", values);

      /**
         * If record is added successfully
      */
      if (rowID > 0) {
         Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
         getContext().getContentResolver().notifyChange(_uri, null);
         return _uri;
      }
        
      throw new SQLException("Failed to add a record into " + uri);
   }

   @Override
   public Cursor query(Uri uri, String[] projection, 
      String selection,String[] selectionArgs, String sortOrder) {
      SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
      qb.setTables(STUDENTS_TABLE_NAME);

      switch (uriMatcher.match(uri)) {
         case STUDENTS:
            qb.setProjectionMap(STUDENTS_PROJECTION_MAP);
         break;

         case STUDENT_ID:
            qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1));
         break;
         
         default:   
      }

      if (sortOrder == null || sortOrder == ""){
         /**
            * By default sort on student names
         */
         sortOrder = NAME;
      }
      
      Cursor c = qb.query(db,	projection,	selection, 
         selectionArgs,null, null, sortOrder);
      /**
         * register to watch a content URI for changes
      */
      c.setNotificationUri(getContext().getContentResolver(), uri);
      return c;
   }

   @Override
   public int delete(Uri uri, String selection, String[] selectionArgs) {
      int count = 0;
      switch (uriMatcher.match(uri)){
         case STUDENTS:
            count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs);
         break;

         case STUDENT_ID:
            String id = uri.getPathSegments().get(1);
            count = db.delete( STUDENTS_TABLE_NAME, _ID +  " = " + id +
               (!TextUtils.isEmpty(selection) ? " 
               AND (" + selection + ')' : ""), selectionArgs);
            break;
         default:
            throw new IllegalArgumentException("Unknown URI " + uri);
      }

      getContext().getContentResolver().notifyChange(uri, null);
      return count;
   }

   @Override
   public int update(Uri uri, ContentValues values, 
      String selection, String[] selectionArgs) {
      int count = 0;
      switch (uriMatcher.match(uri)) {
         case STUDENTS:
            count = db.update(STUDENTS_TABLE_NAME, values, selection, selectionArgs);
         break;

         case STUDENT_ID:
            count = db.update(STUDENTS_TABLE_NAME, values, 
               _ID + " = " + uri.getPathSegments().get(1) +
               (!TextUtils.isEmpty(selection) ? " 
               AND (" +selection + ')' : ""), selectionArgs);
            break;
         default:
            throw new IllegalArgumentException("Unknown URI " + uri );
      }
        
      getContext().getContentResolver().notifyChange(uri, null);
      return count;
   }

   @Override
   public String getType(Uri uri) {
      switch (uriMatcher.match(uri)){
         /**
            * Get all student records
         */
         case STUDENTS:
            return "vnd.android.cursor.dir/vnd.example.students";
         /**
            * Get a particular student
         */
         case STUDENT_ID:
            return "vnd.android.cursor.item/vnd.example.students";
         default:
            throw new IllegalArgumentException("Unsupported URI: " + uri);
      }
   }
}

Di seguito verrà visualizzato il contenuto modificato del file AndroidManifest.xml . Qui abbiamo aggiunto il tag <provider ... /> per includere il nostro fornitore di contenuti:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.MyApplication">

   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:theme="@style/AppTheme">
         <activity android:name=".MainActivity">
            <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
         </activity>
        
      <provider android:name="StudentsProvider"
         android:authorities="com.example.MyApplication.StudentsProvider"/>
   </application>
</manifest>

Di seguito sarà il contenuto di res/layout/activity_main.xml file-

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="com.example.MyApplication.MainActivity">

   <TextView
      android:id="@+id/textView1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Content provider"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:textSize="30dp" />

   <TextView
      android:id="@+id/textView2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Tutorials point "
      android:textColor="#ff87ff09"
      android:textSize="30dp"
      android:layout_below="@+id/textView1"
      android:layout_centerHorizontal="true" />

   <ImageButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/imageButton"
      android:src="@drawable/abc"
      android:layout_below="@+id/textView2"
      android:layout_centerHorizontal="true" />

   <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/button2"
      android:text="Add Name"
      android:layout_below="@+id/editText3"
      android:layout_alignRight="@+id/textView2"
      android:layout_alignEnd="@+id/textView2"
      android:layout_alignLeft="@+id/textView2"
      android:layout_alignStart="@+id/textView2"
      android:onClick="onClickAddName"/>

   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText"
      android:layout_below="@+id/imageButton"
      android:layout_alignRight="@+id/imageButton"
      android:layout_alignEnd="@+id/imageButton" />

   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText2"
      android:layout_alignTop="@+id/editText"
      android:layout_alignLeft="@+id/textView1"
      android:layout_alignStart="@+id/textView1"
      android:layout_alignRight="@+id/textView1"
      android:layout_alignEnd="@+id/textView1"
      android:hint="Name"
      android:textColorHint="@android:color/holo_blue_light" />

   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText3"
      android:layout_below="@+id/editText"
      android:layout_alignLeft="@+id/editText2"
      android:layout_alignStart="@+id/editText2"
      android:layout_alignRight="@+id/editText2"
      android:layout_alignEnd="@+id/editText2"
      android:hint="Grade"
      android:textColorHint="@android:color/holo_blue_bright" />

   <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Retrive student"
      android:id="@+id/button"
      android:layout_below="@+id/button2"
      android:layout_alignRight="@+id/editText3"
      android:layout_alignEnd="@+id/editText3"
      android:layout_alignLeft="@+id/button2"
      android:layout_alignStart="@+id/button2"
      android:onClick="onClickRetrieveStudents"/>
</RelativeLayout>

Assicurati di avere il seguente contenuto di res/values/strings.xml file:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My Application</string>
</resources>;

Proviamo a eseguire il nostro file modificato My Applicationapplicazione che abbiamo appena creato. Presumo che tu abbia creato il tuoAVDdurante l'impostazione dell'ambiente. Per eseguire l'app dall'IDE di Android Studio, apri uno dei file di attività del tuo progetto e fai clic sull'icona Esegui dalla barra degli strumenti. Android Studio installa l'app sul tuo AVD e la avvia e se tutto va bene con la configurazione e l'applicazione, verrà visualizzata la seguente finestra dell'emulatore, sii paziente perché potrebbe richiedere del tempo in base alla velocità del tuo computer -

Ora entriamo in studente Name e Grade e infine fare clic su Add Namepulsante, questo aggiungerà il record dello studente nel database e farà lampeggiare un messaggio in basso che mostra l'URI di ContentProvider insieme al numero di record aggiunto nel database. Questa operazione si avvale del nsinsert()metodo. Ripetiamo questo processo per aggiungere qualche altro studente nel database del nostro fornitore di contenuti.

Una volta che hai finito di aggiungere record nel database, ora è il momento di chiedere a ContentProvider di restituirci quei record, quindi facciamo clic Retrieve Students pulsante che recupererà e visualizzerà tutti i record uno per uno, secondo l'implementazione del nostro query() metodo.

È possibile scrivere attività a fronte di operazioni di aggiornamento ed eliminazione fornendo funzioni di callback in MainActivity.java file e quindi modificare l'interfaccia utente per avere pulsanti per l'aggiornamento e le operazioni di eliminazione nello stesso modo in cui abbiamo fatto per le operazioni di aggiunta e lettura.

In questo modo puoi utilizzare il fornitore di contenuti esistente come la Rubrica oppure puoi utilizzare il concetto di fornitore di contenuti nello sviluppo di belle applicazioni orientate al database in cui puoi eseguire tutti i tipi di operazioni di database come leggere, scrivere, aggiornare ed eliminare come spiegato sopra nell'esempio.