赞
踩
Android ContentProvider学习
一、 ContentProvider介绍
ContentProvider提供了对接数据库的接口,需要我们通过SQLiteOpenHelper来实现数据库本身的增删改查。ContentProvider不能简单理解数据库接口,因为当我们在其他app里面调用getContentResolver并进行增删改查的时候,能调到自定义ContentProvider的接口里面,这有点像进程间通信,实际上也的确是,底层利用Binder机制实现了跨进程调用ContentProvider。当然如果我们不在Manifest里面的Provider标签添加android:exported=“true”,那么其他app也无法使用这个contentProvider,当然这个时候也不需要利用ContentProvider了,可以使用更轻量级的SharedPreference来存储。
通过ContentResolver来查找ContentProvider是通过URI来查找的,一般URI的格式为schema+authority+path+id,如下图
我们知道URL是URI的一种,所以可以使用一般的http url来理解,比如我CSDN的首页https://blog.csdn.net/xiaoshixiu, schema为http://,authoriity为blog.csdn.net,path为xiaoshixiu,id为空。
二、 Demo
首先是ContentProvider端,自定义ContentProvider后,需要在Manifest里添加,当然Android Studio会自动添加。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.providertest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <provider android:name=".MyContentProvider" android:authorities="MyContentProviderAuthority" android:enabled="true" android:exported="true" ></provider> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
注意两个属性
android:authorities="MyContentProviderAuthority"
,一般Authority可以写成包名,比如com.mypackage.myapp
android:exported="true"
,表示其他app可以通过ContentResolver搜到本Provider提供的数据。
然后是自定义Provider
package com.example.providertest; 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.SQLiteOpenHelper; import android.net.Uri; import android.util.Log; import androidx.annotation.Nullable; public class MyContentProvider extends ContentProvider { private UriMatcher uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); private SQLiteDatabase db; private static String TABLE_NAME="MyTable"; public MyContentProvider() { //Authority在Manifest里面就定义了,实际上对比uri时,到ContentProvider里已经对比了Authority uriMatcher.addURI("MyContentProviderAuthority","MY",0); } //目前仅实现了onCreate,insert,query @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Implement this to handle requests to delete one or more rows. Log.d("MyContentProvider","delete"); throw new UnsupportedOperationException("Not yet implemented"); } @Override public String getType(Uri uri) { // TODO: Implement this to handle requests for the MIME type of the data // at the given URI. Log.d("MyContentProvider","getType"); throw new UnsupportedOperationException("Not yet implemented"); } //注意现在不能插入两条相同数据,会崩溃 @Override public Uri insert(Uri uri, ContentValues values) { // TODO: Implement this to handle requests to insert a new row. Log.d("MyContentProvider","insert"); long row; if(uriMatcher.match(uri)==0){ row =db.insert(TABLE_NAME,null,values); if(row>=0){ getContext().getContentResolver().notifyChange(uri,null); return ContentUris.withAppendedId(uri,row); } } throw new UnsupportedOperationException("Not yet implemented"); } @Override public boolean onCreate() { // TODO: Implement this to initialize your content provider on startup. Log.d("MyContentProvider","onCreate"); db=new MyDBHelper(getContext(),"MyDB",null,1).getWritableDatabase(); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO: Implement this to handle query requests from clients. Log.d("MyContentProvider","query"); if(uriMatcher.match(uri)==0){ return db.query(TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder,null); } throw new UnsupportedOperationException("Not yet implemented"); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO: Implement this to handle requests to update one or more rows. Log.d("MyContentProvider","update"); throw new UnsupportedOperationException("Not yet implemented"); } //自定义SQLiteOpenHelper,实现sql相关操作 public class MyDBHelper extends SQLiteOpenHelper{ public MyDBHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { Log.d("MyDBHelper","onCreate"); db.execSQL("CREATE TABLE IF NOT EXISTS "+TABLE_NAME+" (id INTEGER PRIMARY KEY,name VARCHAR(20))"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.d("MyDBHelper","onUpgrade"); } } }
然后是Activity和Layout
package com.example.providertest; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.EditText; public class MainActivity extends AppCompatActivity { private EditText editText_id; private EditText editText_name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText_id=(EditText)findViewById(R.id.et_input_id); editText_name=(EditText)findViewById(R.id.et_input_name); } //点击按钮则从EditText中获取数据,向ContentProvider里面插入数据 public void onClickInput(View view){ String id=editText_id.getText().toString(); String name=editText_name.getText().toString(); ContentValues contentValues=new ContentValues(); contentValues.put("id",id); contentValues.put("name",name); getContentResolver().insert(Uri.parse("content://"+"MyContentProviderAuthority"+"/MY"),contentValues); } }
Layout文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="50dp" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="id:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/et_input_id"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="name:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/et_input_name"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn_input" android:text="Input data" android:onClick="onClickInput"/> </LinearLayout>
接下来运行app
点击按钮后打印如下log:
05-03 15:16:13.129 29876-29876/com.example.providertest D/MyContentProvider: insert
接下来我们另外起一个进程,用来跨进程查找数据
package com.example.querycontent; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //可以跨进程查找ContentProvider数据 public void onclickquery(View view){ TextView textView=(TextView)findViewById(R.id.tv_query); Cursor cursor=getContentResolver().query(Uri.parse("content://"+"MyContentProviderAuthority"+"/MY"),new String[]{"id","name"}, null,null,null); StringBuffer stringBuffer=new StringBuffer(); while (cursor.moveToNext()){ stringBuffer.append("id:"+cursor.getInt(cursor.getColumnIndex("id"))+"\n"); stringBuffer.append("name:"+cursor.getString(cursor.getColumnIndex("name"))+"\n"); } textView.setText(stringBuffer.toString()); } //也可以跨进程插入数据 public void onClickInput(View view){ EditText editText_id; EditText editText_name; editText_id=(EditText)findViewById(R.id.et_input_id); editText_name=(EditText)findViewById(R.id.et_input_name); String id=editText_id.getText().toString(); String name=editText_name.getText().toString(); ContentValues contentValues=new ContentValues(); contentValues.put("id",id); contentValues.put("name",name); getContentResolver().insert(Uri.parse("content://"+"MyContentProviderAuthority"+"/MY"),contentValues); } }
Layout文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="50dp" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:id="@+id/tv_query" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onclickquery" android:text="query content"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="id:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/et_input_id"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="name:"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/et_input_name"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn_input" android:text="Input data" android:onClick="onClickInput"/> </LinearLayout>
运行app
点击query:
最后是资源链接:
https://download.csdn.net/download/xiaoshixiu/12385628
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。