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的使用,看视频也不懂,觉得超级麻烦。但是现在看看觉得也不是那么麻烦,掌握了逻辑,熟悉了过程,代码只是其次。