>  기사  >  Java  >  Android ContentProvider를 기반으로 한 요약 및 자세한 설명

Android ContentProvider를 기반으로 한 요약 및 자세한 설명

高洛峰
高洛峰원래의
2017-02-07 15:59:21981검색

1. 적용 가능한 시나리오
1) ContentProvider는 데이터 저장 및 읽기를 위한 통합 인터페이스를 제공합니다.
2) ContentProvider를 사용하면 애플리케이션에서 데이터 공유를 달성할 수 있습니다.
3) Android에 내장된 많은 데이터는 ContentProvider 형식을 사용합니다. 개발자가 호출할 수 있는 기능(비디오, 오디오, 사진, 주소록 등)
2. 관련 개념 소개
1) ContentProvider 소개
애플리케이션이 ContentProvider 클래스를 상속받아 이 클래스를 다시 작성하는 경우 다른 애플리케이션과 공유할 수 있도록 데이터를 제공하고 저장하는 방법입니다. 다른 방법을 사용하여 데이터를 외부에 공유할 수 있지만 데이터가 저장되는 방식에 따라 데이터 액세스 방법이 다릅니다. 예를 들어 파일 모드를 사용하여 외부에 데이터를 공유하는 경우 데이터를 읽고 쓰려면 파일 작업을 수행해야 합니다. sharedpreferences를 사용하여 데이터를 공유하는 경우 데이터를 읽고 쓰려면 sharedpreferences API를 사용해야 합니다. ContentProvider를 사용하여 데이터를 공유하면 데이터 액세스 방법을 통합할 수 있다는 이점이 있습니다.
2) Uri 클래스 소개
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
Content Provider에서 사용하는 쿼리 문자열이 표준과 다릅니다. SQL 쿼리. 우리는 선택, 추가, 삭제, 수정 등과 같은 많은 작업을 수행하기 위해 특수 URI를 사용합니다. 이 URI는 데이터 경로를 나타내는 "content://"와 선택적 식별 ​​데이터 ID의 세 부분으로 구성됩니다. . 다음은 몇 가지 URI 예시입니다.

content://media/internal/images  这个URI将返回设备上存储的所有图片
content://contacts/people/  这个URI将返回设备上的所有联系人信息
content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)

이 쿼리 문자열 형식은 일반적이지만 여전히 다소 혼란스러워 보일 수 있습니다. 이를 위해 Android는 클래스 변수 형식으로 제공되는 많은 쿼리 문자열을 포함하는 일련의 도움말 클래스(android.provider 패키지 아래)를 제공합니다. 이 방법을 사용하면 위에 표시된 대로 이해하기가 더 쉽습니다. /contacts/people/45 이 URI는 다음 형식으로 작성할 수 있습니다.
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
그런 다음 데이터 쿼리를 실행합니다.
Cursor cur = ManagedQuery( person, null, null, null);
이 쿼리는 모든 데이터 필드가 포함된 커서를 반환합니다. 이 커서를 반복하면 모든 데이터를 얻을 수 있습니다.

package com.wissen.testApp;
public class ContentProviderDemo extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
displayRecords();
    }
    private void displayRecords() {
 //该数组中包含了所有要返回的字段
     String columns[] = new String[] { People.NAME, People.NUMBER };
Uri mContacts = People.CONTENT_URI;
Cursor cur = managedQuery(
   mContacts,
   columns,  // 要返回的数据字段
  null,   // WHERE子句
  null,  // WHERE 子句的参数
         null  // Order-by子句
     );
if (cur.moveToFirst()) {
    String name = null;
    String phoneNo = null;
    do {
// 获取字段的值
     name = cur.getString(cur.getColumnIndex(People.NAME));
      phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER));
      Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show();
   } while (cur.moveToNext());
}
    }
}

위의 예는 관계를 읽는 방법을 보여줍니다. 시퀀스 개인 정보 테이블에 지정된 데이터 열 이름과 번호입니다.
레코드 수정:
ContentResolver.update() 메서드를 사용하여 데이터를 수정할 수 있습니다.

private void updateRecord(int recNo, String name) {
    Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
    ContentValues values = new ContentValues();
    values.put(People.NAME, name);
    getContentResolver().update(uri, values, null, null);
}

이제 위 메서드를 호출하여 지정된 레코드를 업데이트할 수 있습니다. :
updateRecord(10, "XYZ"); //10번째 레코드의 이름 필드 값을 "XYZ"로 변경합니다.
레코드 추가:
레코드를 추가하려면 ContentResolver.insert( ) 메소드, 이 메소드는 추가할 레코드의 대상 URI와 새 레코드 값을 포함하는 Map 객체를 허용합니다. 호출 후 반환 값은 레코드 번호를 포함한 새 레코드의 URI입니다.
위 예에서 우리는 모두 연락처 정보 책의 표준 콘텐츠 제공자를 기반으로 합니다. 이제 연락처 정보 책에 데이터를 추가하기 위해 insertRecord() 메서드를 계속 생성합니다.

private void insertRecords(String name, String phoneNo) {
    ContentValues values = new ContentValues();
    values.put(People.NAME, name);
    Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
    Log.d(”ANDROID”, uri.toString());
    Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
    values.clear();
    values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE);
    values.put(People.NUMBER, phoneNo);
    getContentResolver().insert(numberUri, values);
}

이런 식으로 insertRecords(name,phoneNo)를 호출하여 연락처 정보 목록에 연락처 이름과 전화번호를 추가할 수 있습니다.
기록 삭제:
Content Provider의 getContextResolver.delete() 메소드를 사용하여 기록을 삭제할 수 있습니다. 다음 기록은 기기의 모든 연락처 정보를 삭제하는 데 사용됩니다.

private void deleteRecords() {
    Uri uri = People.CONTENT_URI;
    getContentResolver().delete(uri, null, null);
}

你也可以指定WHERE条件语句来删除特定的记录:
getContentResolver().delete(uri, “NAME=” + “‘XYZ XYZ'”, null);
这将会删除name为‘XYZ XYZ'的记录。
3. 创建ContentProvider
要创建我们自己的Content Provider的话,我们需要遵循以下几步:
a. 创建一个继承了ContentProvider父类的类
b. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如:
public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);
c. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。
d. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。
e. 如果你要存储字节型数据,比如位图文件等,数据列其实是一个表示实际保存文件的URI字符串,通过它来读取对应的文件数据。处理这种数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源;如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。
f. 声明public static String型的变量,用于指定要从游标处返回的数据列。
g. 查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。
h. 在AndroidMenifest.xml中使用245134590f76a973a830651cacc0946c标签来设置Content Provider。
i. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:

  vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型)
  比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。
  vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型)
  比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。

下列代码将创建一个Content Provider,它仅仅是存储用户名称并显示所有的用户名称(使用 SQLLite数据库存储这些数据):

public class MyUsers {
    public static final String AUTHORITY  = “com.wissen.MyContentProvider”;
    // BaseColumn类中已经包含了 _id字段
   public static final class User implements BaseColumns {
 public static final Uri CONTENT_URI  = Uri.parse(”content://com.wissen.MyContentProvider”);
 // 表数据列
 public static final String  USER_NAME  = “USER_NAME”;
    }
}

上面的类中定义了Content Provider的CONTENT_URI,以及数据列。下面我们将定义基于上面的类来定义实际的Content Provider类:

public class MyContentProvider extends ContentProvider {
    private SQLiteDatabase     sqlDB;
    private DatabaseHelper    dbHelper;
    private static final String  DATABASE_NAME = “Users.db”;
    private static final int  DATABASE_VERSION= 1;
    private static final String TABLE_NAME= “User”;
    private static final String TAG = “MyContentProvider”;
    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 table ” + TABLE_NAME + “( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);”);
 }
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     db.execSQL(”DROP TABLE IF EXISTS ” + TABLE_NAME);
     onCreate(db);
 }
    }
    @Override
    public int delete(Uri uri, String s, String[] as) {
 return 0;
    }
    @Override
    public String getType(Uri uri) {
 return null;
    }
    @Override
    public Uri insert(Uri uri, ContentValues contentvalues) {
 sqlDB = dbHelper.getWritableDatabase();
 long rowId = sqlDB.insert(TABLE_NAME, “”, contentvalues);
 if (rowId > 0) {
     Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();
     getContext().getContentResolver().notifyChange(rowUri, null);
     return rowUri;
 }
 throw new SQLException(”Failed to insert row into ” + uri);
    }
    @Override
    public boolean onCreate() {
 dbHelper = new DatabaseHelper(getContext());
 return (dbHelper == null) ? false : true;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
 SQLiteDatabase db = dbHelper.getReadableDatabase();
 qb.setTables(TABLE_NAME);
 Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
 c.setNotificationUri(getContext().getContentResolver(), uri);
 return c;
    }
    @Override
    public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
 return 0;
    }
}
一个名为MyContentProvider的Content Provider创建完成了,它用于从Sqlite数据库中添加和读取记录。

Content Provider的入口需要在AndroidManifest.xml中配置:

<provider android:name=”MyContentProvider” android:authorities=”com.wissen.MyContentProvider” />

之后,让我们来使用这个定义好的Content Provider:
1)为应用程序添加ContentProvider的访问权限。
2)通过getContentResolver()方法得到ContentResolver对象。
3)调用ContentResolver类的query()方法查询数据,该方法会返回一个Cursor对象。
4)对得到的Cursor对象进行分析,得到需要的数据。
5)调用Cursor类的close()方法将Cursor对象关闭。

public class MyContentDemo extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 insertRecord(”MyUser”);
 displayRecords();
    }

    private void insertRecord(String userName) {
 ContentValues values = new ContentValues();
 values.put(MyUsers.User.USER_NAME, userName);
 getContentResolver().insert(MyUsers.User.CONTENT_URI, values);
    }
    private void displayRecords() {
 String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };
 Uri myUri = MyUsers.User.CONTENT_URI;
 Cursor cur = managedQuery(myUri, columns,null, null, null );
 if (cur.moveToFirst()) {
     String id = null;
     String userName = null;
     do {
  id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));
  userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));
  Toast.makeText(this, id + ” ” + userName, Toast.LENGTH_LONG).show();
    } while (cur.moveToNext());
}
    }
}

更多基于Android ContentProvider的总结详解相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.