Android四大组件——ContentProvider(整理)

一、运行时权限

1.1 配置< uses-permission>作用:

  • android 6.0以下的系统没有运行时权限,可以通过< uses-permission>的方式直接申请权限;
  • android 6.0以上的系统即使需要在运行时需要申请权限,也需要在androidManifest.xml文件中通过配置< uses-permission>来告知用户和系统该应用程序需要用到的权限;
  • 所有需要的权限都配置在AndroidManifest.xml文件中,最终可以在应用程序管理界面查看到所有的权限以及相应的申请情况。

1.2 运行时权限的作用

        针对android 6.0以上的系统,用户可以不用在安装时一次性授权,可以在使用过程中对某一项进行授权,并且即使该项不授权其他功能也能正常使用。
       只有危险权限需要运行时授权。

权限组名权限名
calendarread_calendar
write_calendar
cameracamera
contactsread_contacts
write_contacts
get_accounts
locationaccess_fine_loaction
access_coarse_location
microphonerecord_audio
phoneread_phone_state
call_phone
read_call_log
write_call_log
ado_voicemail
use_sip
process_outgoing_calls
sensorsbody_sensors
smssend_sms
receive_sms
read_sms
receive_wap_push
receive_mms
storageread_external_storage
write_external_storage

       注意:只要对权限组中的一个权限授权,会自动对该组中的其他所有权限授权,但只有在androidManifest.xml中引用过的权限才能使用。

1.3 运行时权限的申请与处理

  • 检验是否授权
    ContextCompat.checkSelfPermission(context, Manifest.permission.A)
    并与PackageManager.PERMISSION_GRANTED比较
  • 请求授权
    ActivityCompat.requestPermissions,可以组成授权字符串数组一次性循环检查并请求授权。
  • 处理请求结果
    需要重写onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 并自动调用。
  • 可在手机设置中重新修改授权

二、Content Provider

2.1 自定义Content Provider

       主要用于不同的应用程序之间实现数据共享功能。继承自ContentProvider,需要重写的方法如下,由于数据存储形式的不同,对应的数据操作方式也不同,而ContentProvider将所有的数据操作都看作对表格的维护,统一了操作形式,将实际的数据操作方法封装在ContentProvider的CRUD中,可以在一定程度上将数据操作与数据真实的存储方式解耦。主要用于共享数据时提供操作数据的方式。

2.1.1 注册ContentProvider

       android的四大组件均需要在AndroidManifest.xml文件中进行注册,而ContentProvider有以下可选属性:

  • enable:表示是否启用该组件
  • exported:表示是否允许外部应用访问该组件
  • grandUriPermissions:在具有ContentProvider内容的访问权限的应用中调用其它不具有权限的应用来打开对应内容的Uri时,是否可以通过权限传递的方式来使不具有权限的应用获取权限。
    • intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

2.1.2 实现ContentProvider

  • public boolean onCreate()
           当ContentResolver访问数据时内容。ContentProvider才会被初始化;返回true表示初始化成功。
  • public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
           其中,根据uri匹配对应的返回码,根据返回码判断具体的数据操作对象。projection表示查询的列名,selection、selectionArgs表示查询条件,sortOrder表示查询顺序。
           String bookid = uri.getPathSegments().get(1);
           将内容URI中的authority之后的部分以“/”分割,并将分割后的结果放入一个字符串列表,列表的第0个位置存放path,第1个位置存放id。
  • public Uri insert(Uri uri, ContentValues values)
           返回新纪录的URI
  • public int update(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
           返回受影响的数据记录条数。
  • public int delete(Uri uri, String selection, String[] selectionArgs)
           返回受影响的数据记录条数。
  • public String getType(Uri uri)
           返回MIME类型。

2.2 ContentResolver

       想要访问content provider中共享的数据,就一定需要使用Content Resolver类,可通过context中的getContentResolver() 方法获得Resolver实例,并利用uri对对相应内容进行CRUD操作。

2.3 UriMatcher

       UriMatcher用于注册和匹配URI,只有在UriMatcher中添加过的uri才能被其他应用程序访问。

  • 构建UriMatcher实例并添加uri
static {
	uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
	//public void addURI(String authority, String path, int code)
	uriMatcher.addURI(authority,"book",BOOK_All);
	uriMatcher.addURI(authority,"book/#",BOOK_ITEM);
	uriMatcher.addURI(authority,"*",TABLE_ALL);
}

       其中,UriMatcher.NO_MATCH= -1,表示没有匹配的uri则返回-1。addURI中authority、path表示输入的uri,*:表示任意长度的字符,#:表示任意长度的数字;code表示返回的匹配码。

  • 匹配uri
    uriMatcher.match(uri) 得到相应的返回码

2.4 ContentObserver

       ContentObserver用于监听数据的变化,当对应的uri数据发生变化时,会自动触发ContentObserver中的onChange()方法。

2.4.1 ContentService

       ContentService是一个系统级别的消息中心,也是通过binder机制实现的,且transact的方式是one-way,不需要等待消息返回再执行其他操作。其作用为:

  • 消息汇总:应用如果产生了一些消息,也可以向ContentService进行提交,供其进行消息传播。
  • 消息分发:应用可以向ContentService注册ContentObserver,订阅自身感兴趣的消息;一旦有这类消息产生,ContentService会将消息分发该相应的ContentObserver并进行相应操作:
    • 调用该ContentObserver的dispatchChange(selfChange, uri, userId)方法。
    • dispatchChange()方法可能是在Binder线程中同步执行,也可能是发送到一个与Handler绑定的线程中执行。
private void dispatchChange(boolean selfChange, Uri uri, int userId) {
    if (mHandler == null) {
        onChange(selfChange, uri, userId);
    } else {
        mHandler.post(new NotificationRunnable(selfChange, uri, userId));
    }
}

2.4.2 注册ContentObserver

       通过ContentResolver对象调用以下方法进行注册:

  • public final void registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer)
    • uri:表示订阅的消息来源
    • notifyForDescendants:表示是否监听uri的子节点的消息
    • observer:表示注册的observer

2.4.3 产生消息

       通过ContentResolver对象调用以下方法产生消息,一般在ContentProvider的CRUD操作结束时调用,表示数据发生变化:

  • public void notifyChange(Uri uri, ContentObserver observer)
    • uri:变化数据对应的uri;
    • observer:发起数据变化消息的observer;若为null,则表示该消息没有发起者;若不为null,则表示该消息由传入的observer对象发起,如果希望该observer能收到自身发起的消息,需要重写public boolean deliverSelfNotifications()使其返回true(默认返回false)。

2.4.4 创建ContentObserver

public class MyContentObserver extends ContentObserver {
    
    public MyContentObserver(Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
    }
}
  • 构造方法
           需要传入handler对象,如果handler对象不为null,则onChange()方法在handler绑定的线程中执行,若handler绑定的线程为主线程,则可以更新UI;如果handler对象为null,则onChange()方法在binder线程中执行。
  • onChange
           传入参数表示收到的消息是否由自身发起,对应notifyChange中的observer;如果重写了deliverSelfNotifications()使其返回true,且该消息由自身发起,则selfChange为true。如果deliverSelfNotifications()返回false,且该消息由自身发起,该observer接收不到该消息。

三、DocumentsProvider

3.1 存储访问框架SAF(storage access framework)

       将多个DocumentsProvider子类所提供的内容组合在一块,并提供统一的系统级浏览界面,可以进行CRUD操作。其组成部分如下:

  • Document Provider
    DocumentsProvider是一个继承自ContentProvider的抽象类,而其具体的实现类称作Document Provider,即文档提供者。
  • Picker
    系统级浏览界面,可根据Client的需求筛选符合条件的所有Document Provider并将其内容展示出来。DocumentUI,intent-filter中没有设置category为launcher。
  • Client
    发起调用并在onActivityResult()中接收数据以及对数据进行操作;
    • 调用方式
      startActivityForResult(intent, requestCode)
      • ACTION_OPEN_DOCUMENT
        • 查看文件必须设置文件类型
          • intent.setType(" * / * ");
      • ACTION_CREATE_DOCUMENT
        • 新建文件
          • 发起 ACTION_CREATE_DOCUMENT的意图Intent
          • 设置文件名intent.putExtra(Intent.EXTRA_TITLE, fileName)
          • 设置保存路径的文件类型
      • uri是DocumentUI返回的

3.2 ParcelFileDescriptor

3.2.1 FileDescriptor

       FileDescriptor是一个用于表述指向文件的引用的抽象化概念。在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。 当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。只适用于UNIX、Linux这样的操作系统,且Linux的设计思想是把一切设备都视作文件。
       每一个文件描述符会与一个打开文件相对应,同时,不同的文件描述符也会指向同一个文件。相同的文件可以被不同的进程打开也可以在同一个进程中被多次打开。系统为每一个进程维护了一个文件描述符表,该表的值都是从0开始的,所以在不同的进程中可以看到相同的文件描述符,这种情况下相同文件描述符有可能指向同一个文件,也有可能指向不同的文件。
       FileDescriptor实际用途是创建FileInputStream 或 FileOutputStream。

3.2.2 Parcel

  • 作用:Parcel是一个容器,它主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据。
  • 使用原因:由于每个进程使用的是虚拟地址空间,所以如果在跨进程传递时传递的是对象引用,即对象对应的虚拟内存地址,则在另一个进程中是无法找到对应的数据的。而parcel则是将对象的主要特征提取并打包,传递给另一个进程后根据这些特征重新生成一个对象。

3.2.3 生成ParcelFileDescriptor

       将FileDescriptor写入Parcel并在读取时返回一个ParcelFileDescriptor对象用于操作原始的文件描述符。ParcelFileDescriptor是原始描述符的一个复制,对象和fd不同,但是都操作于同一文件流,使用同一个文件位置指针。通过调用ParcelFileDescriptor的静态方法可以生成ParcelFileDescriptor对象。

  • public static ParcelFileDescriptor open(File file, int mode)
  • public static ParcelFileDescriptor open(File file, int mode, Handler handler,
    final OnCloseListener listener)
    • mode
      • MODE_APPEND:在文档末尾继续写入;
      • MODE_CREATE:如果文件不存在,则新建文件;
      • MODE_READ_ONLY:以只读方式打开文档;
      • MODE_READ_WRITE:以读写方式打开文档;
      • MODE_TRUNCATE:打开文件时删除文件内容;
      • MODE_WRITE_ONLY:以只写的方式打开文档。
    • handler:调用ParcelFileDescriptor的close()方法触发listener的callback时,触发动作产生的线程上的handler。
    • listener:在关闭ParcelFileDescriptor执行的callback方法。

3.3 自定义DocumentsProvider

3.3.1 注册DocumentsProvider

<provider
	android:name="com.example.MyCloudProvider"
	android:authorities="com.example.mycloudprovider"
	android:exported="true"
	android:grantUriPermissions="true"
	android:permission="android.permission.MANAGE_DOCUMENTS"
	android:enabled="@bool/isAtLeastKitKat">
	<intent-filter>
		<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
	</intent-filter>
</provider>
  • exported="true"
  • 设置android:permission="android.permission.MANAGE_DOCUMENTS"
           只有拥有该权限的用户才能访问该DocumentsProvider组件,而此处的权限只有系统才能获取,即DocumentsProvider只有系统级的浏览界面才能访问。
  • android.content.action.DOCUMENTS_PROVIDER

3.3.2 文件结构

在这里插入图片描述

图1 文件结构
  • 每个根目录都有一个唯一的 COLUMN_ROOT_ID
  • 每个根目录下都有唯一的一个Document。该Document下有 1 至 N 个Documents;
  • 每个Document都有唯一的一个 COLUMN_DOCUMENT_ID
  • Document可以是特定的 MIME 类型,也可以是包含子Documents的目录,为MIME_TYPE_DIR 类型;
  • 每个Document都可以具有不同的功能,用COLUMN_FLAGS表示。例如:
    • FLAG_SUPPORTS_WRITE:支持写入
    • FLAG_SUPPORTS_DELETE:支持删除
    • FLAG_SUPPORTS_THUMBNAIL:支持缩略图
    • . . .

3.3.3 MatrixCursor

       当需要返回Cursor对象时,可以创建一张虚拟数据表,即MatrixCursor,该数据表可自动扩容。

  • 构造方法
    • public MatrixCursor(String[] columnNames)
    • public MatrixCursor(String[] columnNames, int initialCapacity)
      • columnNames:数据表对应的列名,顺序与字符串顺序一致;
      • initialCapacity:数据表容量,默认为0。
  • 填充数据
    • public void addRow(Object[] columnValues)
      顺序需与columnNames一致。数据一次性添加一行。
    • public RowBuilder newRow()
      生成数据行的构造器。数据依次添加。
      • public RowBuilder add(String columnName, Object value)

3.3.4 实现DocumentsProvider

  • public boolean onCreate()
    返回true表示初始化成功。
  • public Cursor queryRoots(String[] projection) throws FileNotFoundException
    拼凑根节点的Cursor
    • 传入参数
      • projection:筛选条件中需要展示的列名;
    • 返回值
      • Cursor
        DocumentsContract.Root中列出的列名以及对应的值
        • COLUMN_DOCUMENT_ID
        • COLUMN_FLAGS
          • FLAG_SUPPORTS_CREATE
          • FLAG_SUPPORTS_SEARCH
          • . . .
        • . . .
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
	MatrixCursor matrixCursor=new MatrixCursor(projection==null?DEFAULT_ROOT_PROJECTION:projection);
	MatrixCursor.RowBuilder rowBuilder=matrixCursor.newRow();
	File homeDir=new File(Environment.getExternalStorageDirectory(),"myfile");
	rowBuilder.add(Root.COLUMN_DOCUMENT_ID,homeDir.getAbsolutePath());
	rowBuilder.add(Root.COLUMN_ROOT_ID,homeDir.getAbsolutePath());
	rowBuilder.add(Root.COLUMN_FLAGS,Root.FLAG_LOCAL_ONLY|Root.FLAG_SUPPORTS_SEARCH|Root.FLAG_SUPPORTS_CREATE);
	rowBuilder.add(Root.COLUMN_TITLE,"My Application");
	rowBuilder.add(Root.COLUMN_ICON,icon);
	return matrixCursor;
}
  • public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException
    • 拼凑子节点的Cursor
    • DocumentsContract.Document中列出的列名以及对应的值
@Override
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
	final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
	final File parent = new File(parentDocumentId);
	for (File file : parent.listFiles()) {
		// 不显示隐藏的文件或文件夹
		if (!file.getName().startsWith(".")) {
		// 添加文件的名字, 类型, 大小等属性
			includeFile(result, file);
		}
	}
	return result;
}
private void includeFile(MatrixCursor result, File file) throws FileNotFoundException {
	MatrixCursor.RowBuilder row = result.newRow();
	row.add(Document.COLUMN_DOCUMENT_ID, file.getAbsolutePath());
	row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
	String mimeType = getDocumentType(file.getAbsolutePath());
	row.add(Document.COLUMN_MIME_TYPE, mimeType);
	int flags =file.canWrite()?
                        Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_RENAME
                | (mimeType.equals(Document.MIME_TYPE_DIR) ? Document.FLAG_DIR_SUPPORTS_CREATE : 0): 0;
	if (mimeType.startsWith("image/"))
		flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
	row.add(Document.COLUMN_FLAGS, flags);
	row.add(Document.COLUMN_SIZE, file.length());
	row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
} 
@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
	File file = new File(documentId);
	if (file.isDirectory())
		return Document.MIME_TYPE_DIR;
	final int lastDot = file.getName().lastIndexOf('.');
	if (lastDot >= 0) {
		final String extension = file.getName().substring(lastDot + 1);
		final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
		if (mime != null) {
			return mime;
		}
	}
	return "application/octet-stream";
}

  • public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException
    • 拼凑叶子节点的Cursor
@Override
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
	MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
	includeFile(result, new File(documentId));
	return result;
}
  • public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal signal) throws FileNotFoundException
    当通过ContentResolver调用openFileDescriptor(Uri uri, String mode)时系统会调用此方法。
@Override
public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal signal) throws FileNotFoundException {
	return ParcelFileDescriptor.open(new File(documentId),ParcelFileDescriptor.parseMode(mode));
}
  • Document.FLAG_SUPPORTS_THUMBNAIL需要重写public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException

3.3.5 使用DocumentsProvider

  • 新建文件
    • 获取Uri:intent.getData()
    • 需要重写public String createDocument(String parentDocumentId, String mimeType, String displayName)
      • 新建文件并返回对应的DocumentId
  • 删除文件
    • 前提:Document.COLUMN_FLAGS包含SUPPORTS_DELETE
      DocumentsContract.deleteDocument(getContentResolver(), intent.getData());
    • 需要重写public void deleteDocument(String documentId) throws FileNotFoundException
  • 数据处理
    • 直接使用Uri;
      • content://com.example.myapplication.MyDocumentsProvider/document/%2Fstorage%2Femulated%2F0%2Fmyfile%2F1.txt
      • Uri与documentId有关;content://authority/document/documentId的URI形式。
      • 通过authority找到对应的Provider,再调用Provider的createDocument()、deleteDocument()以及openDocument()方法。
    • 通过Uri得到ParcelFileDescriptor
      • getContentResolver().openFileDescriptor(Uri uri, String mode);
      • 系统自动调用DocumentsProvider的openDocument()方法;
    • 通过Uri得到IO流
      • getContentResolver().openInputStream(uri);
      • 函数内部也是通过FileDescriptor生成的IO流。

四、FileProvider

4.1 使用场景

  • 需要使用file的Uri形式
  • Uri.fromFile(File file)方法可以得到file的Uri形式,但其形式为file:///storage/emulated/0/myfile/11165797.jpg,即" file:// "+真实路径;
  • Android 7.0+不允许暴露真实路径,所以不能使用file://的形式传递文件的标识。

4.2 配置FileProvider

4.2.1 FileProvider注册:

<provider
    android:authorities="com.example.loki.myapplication.MyFileProvider"
	android:grantUriPermissions="true"
    android:name="android.support.v4.content.FileProvider">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
		<!-- 路径匹配信息 -->
        android:resource="@xml/filepath"
    />
</provider>
  • authority:自定义,provider的标识;
  • name:provider的类名,使用SDK中自带的类,android.support.v4.content.FileProvider
  • <meta-data>
    • name固定为android.support.FILE_PROVIDER_PATHS
    • resource:自定义的xml文件,用于映射共享路径。在resource包下新建xml文件夹。
      • name:表示虚拟目录
      • path:在标签对应的目录下的真实路径
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="selfDefinition"
        path="myflie"/>
</paths>
子节点含义路径
files-pathgetFileDir()/data/data/packageName/files/
cache-pathgetCacheDir()/data/data/packageName/cache/
external-pathEnvironment.getExternalStorageDirectory()/sdcard/
external-files-pathEnvironment.getExternalFilesDirs()/sdcard/Android/data/packageName/files/
external-cache-pathEnvironment.getExternalCacheDirs()/sdcard/Android/data/packageName/cache/

4.2.2 使用FileProvider

  • FileProvider.getUriForFile(Context context, String authority, File file)
    • content://com.example.myapplication.MyFileProvider/selfDefinition/NewFolder/1.txt
    • 将path中标注的路径替换为name中的虚拟路径
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.example.tigongzhe; import android.R.integer; 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.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.tigongzhe" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.tigongzhe.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name=".provider" android:authorities="com.example.tigongzhe.provider" android:multiprocess="true" android:exported="true" android:permission="com.example.tigongzhe.permission" ></provider> </application> <permission android:name="com.example.tigongzhe.permission" android:protectionLevel="normal"></permission> </manifest> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++package com.example.tigongzhe; import android.R.integer; 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.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.SyncStateContract.Helpers; import android.text.Selection; import android.util.Log; public class provider extends ContentProvider { private MyOpenHelper myOpenHelper; private SQLiteDatabase sqLiteDatabase; private static final UriMatcher URI_MATCHER=new UriMatcher(UriMatcher.NO_MATCH); private final String TAG="provider"; private static final String authority="com.example.tigongzhe.provider"; static { URI_MATCHER.addURI(authority, "contacter", 1); URI_MATCHER.addURI(authority, "contacter/#", 2); } private static final String _id="id"; private static final String name="name"; private static final String num="num"; @Override public boolean onCreate() { // TODO Auto-generated method stub myOpenHelper=new MyOpenHelper(getContext(), DB_Name, null, version_1); return true; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub int flag=URI_MATCHER.match(uri); switch (flag) { case 2: return "vnd.android.cursor.item/contacter"; case 1: return "vnd.android.dir.item/contacter"; default: throw new IllegalArgumentException("异常参数"); } } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: sqLiteDatabase.insert(Table_Name, name, values); break; case 2: long id=sqLiteDatabase.insert(Table_Name, name, values); ContentUris.withAppendedId(uri, id); default: break; } return uri; } @Override public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3, String arg4) { // TODO Auto-generated method stub Cursor cursor; sqLiteDatabase=myOpenHelper.getReadableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); break; case 2: long id=ContentUris.parseId(uri); arg2=(arg2==null||"".equals(arg2.trim()))? _id+"="+id:arg2+"and"+_id+"="+id; cursor=sqLiteDatabase.query(Table_Name, arg1, arg2, arg3, null, null,arg4); default: throw new IllegalArgumentException("参数错误"); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))? _id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.update(Table_Name, values,selection, selectionArgs); default: break; } return num; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub int num=0; sqLiteDatabase=myOpenHelper.getWritableDatabase(); int flag=URI_MATCHER.match(uri); switch (flag) { case 1: num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); break; case 2: long id=ContentUris.parseId(uri); selection=(selection==null||"".equals(selection.trim()))?_id+"="+id:selection+"and"+_id+"="+id; num=sqLiteDatabase.delete(Table_Name, selection, selectionArgs); default: throw new IllegalArgumentException("异常参数"); } return num; } private final String DB_Name = "mydb.db"; private final String Table_Name="contacter"; private final int version_1=1; private class MyOpenHelper extends SQLiteOpenHelper { public MyOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * @description 当数据表无连接时创建新的表 */ @Override public void onCreate(SQLiteDatabase db) { String sql = " create table if not exists " + Table_Name + "(id INTEGER PRIMARY KEY AUTOINCREMENT," + "name varchar(64),num varchar(64))"; db.execSQL(sql); } /** * @description 当版本更新时触发的方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = " drop table if exists " + Table_Name; db.execSQL(sql); onCreate(db); } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值