1.從學習android到至今已經有一年的時間了,四大組件中用到了三個唯獨contentprovider沒有被用到過,而且對這個也不是很理解,但是學習《android開發藝術探究》之後在第二章的IPC機制中,提到一種方法就是contentprovider。通過contentprovider可以實現數據共享。
2.contentprovider暴露數據的接口,這樣其他的程序可以通過Uri來訪問這個contentprovider的數據。我們知道每個app運行的時候都佔用一個進程,contentprovider可以實現進程間的通訊。這個demo分爲倆部分,一個是提供contentprovider的應用的app,我們稱爲service,另外一個應用程序我們稱爲client,也就是說這次我們要寫倆個應用程序。
3.Service端。第一步首先要繼承contentprovider,代碼如下:
package com.example.lenovo.contentprovidertest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.Nullable;
/**
* Created by lenovo on 21/6/2016.
*/
public class MyContentProvider extends ContentProvider {
SQLiteDatabase writedb;
SQLiteDatabase readb;
Database d;
final static String uri="content://com.example.lenovo.contentprovidertest.MyContentProvider1";
final static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(uri,"Login",1);
}
@Override
public boolean onCreate() {
d=new Database(getContext(),"Login",null,1);
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
readb=d.getReadableDatabase();
Cursor cursor= readb.rawQuery("select * from user ",null);
return cursor;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
writedb=d.getWritableDatabase();
writedb.insert("user",null,values);
return uri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
下面有幾個需要注意的地方:
oncreate(),方法運行在主線程中,因此在這個方法中我們不能做耗時操作。
UriMatcher類的作用:就是將authorities 和具體訪問的資源綁定起來,並且設置一個code,當匹配成功就會返回這個code。
例如:www.baidu.sa.html www.baidu就相當於我們這的authorities sa.html 相當具體的資源。關於contentprovider的uri不懂的可以找找資料看看。這裏不細說
當你繼承Contentprovider的時候,會要求重寫一些方法,那些方法都需要我們自己來實現,在我貼的代碼中,我是通過Sqliteopenhelper來管理一個數據庫的。具體代碼如下:
package com.example.lenovo.contentprovidertest;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by lenovo on 21/6/2016.
*/
class Database extends SQLiteOpenHelper{
public String table="create table if not exists user(_id integer primary key autoincrement,name varchar(20),password varchar(20))";
public Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public Database(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(table);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
寫好了這個Sqlieopenhelper之後,我們就可以在contentprovider類中,在相應的方法中,調用數據庫相應的操作。例如在contentprovider方法裏面有insert方法 那麼,在哪個方法內部我們需要調用數據庫執行insert的sql語句。詳細代碼請看上面的內容。
之後MainActivity的運行界面如下:
將username和password,輸入內容之後,通過調用contentprovider的insert方法保存起來。通過上面代碼可知,在insert方法中,我其實也是調用表的數據庫的insert操作。
寫完後最後一步就是在Manifest.xml裏面配置provider的信息。代碼如下:
<provider
android:authorities="com.example.lenovo.contentprovidertest.MyContentProvider1"
android:name=".MyContentProvider"
android:exported="true"
/>
注意:exported 這個屬性要設置爲true。true表示可以在不同的進程中調用,false表示不可以。默認情況爲false。
之後安裝這個程序 輸入 內容然後保存起來,每當保存成功後 會有一個Toast彈出來。
4.再建立一個客戶端來調用service裏面的contentprovider。MainActivity的代碼如下:
package com.example.lenovo.clientcontentprivider;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
final static String uri="content://com.example.lenovo.contentprovidertest.MyContentProvider1/Login";
ContentResolver contentResolver;
Button but;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
but= (Button) findViewById(R.id.query);
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
contentResolver=getContentResolver();
Cursor cursor=contentResolver.query(Uri.parse(uri), null, null, null, null);
while (cursor.moveToNext())
{
String s=cursor.getString(cursor.getColumnIndex("name"));
String s1= cursor.getString(cursor.getColumnIndex("password"));
Toast.makeText(MainActivity.this,s, Toast.LENGTH_SHORT).show();
}
cursor.close();
}
});
}
}
通過contentResolver.query方法來查詢 Service應用保存的那些username,和password的數據。
總結:contentprovider這個類,主要是把一些需要跨進程調用的數據,保存到數據庫中,其他應用程序通過一個uri來訪問那個數據庫,進而查詢到數據。
這篇文章主要針對一些對contentprovider瞭解點的人,但是又不是很明白。最開始我也不是很懂contentprovider的使用,看視頻也不懂,覺得超級麻煩。但是現在看看覺得也不是那麼麻煩,掌握了邏輯,熟悉了過程,代碼只是其次。