Android ContentProvider
應(yīng)用場景:
在Android官方指出的Android的數(shù)據(jù)存儲方式總共有五種,分別是:Shared Preferences、網(wǎng)絡(luò)存儲、文件存儲、外儲存儲、SQLite。但是我們知道一般這些存儲都只是在單獨的一個應(yīng)用程序之中達到一個數(shù)據(jù)的共享,而且這些知識在前面我都有介紹,有時候我們需要操作其他應(yīng)用程序的一些數(shù)據(jù),例如我們需要操作系統(tǒng)里的媒體庫、通訊錄等,這時我們就可能通過ContentProvider來滿足我們的需求了
ContentProvider概述:
ContentProvider向我們提供了我們在應(yīng)用程序之前共享數(shù)據(jù)的一種機制,而我們知道每一個應(yīng)用程序都是運行在不同的應(yīng)用程序的,數(shù)據(jù)和文件在不同應(yīng)用程序之間達到數(shù)據(jù)的共享不是沒有可能,而是顯得比較復(fù)雜,而正好Android中的ContentProvider則達到了這一需求,比如有時候我們需要操作手機里的聯(lián)系人,手機里的多媒體等一些信息,我們都可以用到這個ContentProvider來達到我們所需。
如何理解ContentProvider
上面說了一大堆ContentProvider的概述,可能大家還是不太特別理解ContentProvider到底是干什么的,那么我們以一個網(wǎng)站來形象的描述這個ContentProvider吧,可以這么理解為ContentProvider就是一個網(wǎng)站,它向我們?nèi)ピL問網(wǎng)站這里的數(shù)據(jù)達到了一種可能,它就是一個向外提供數(shù)據(jù)的接口。那么既然它是向外提供數(shù)據(jù),我們有時候也需要去修改數(shù)據(jù),這時我們就可以用到另外一個類來實現(xiàn)這個對數(shù)據(jù)的修改ContentResolver類,這個類就可以通過URI來操作數(shù)據(jù)。至于這些類的作用及描述在下面就會一一的介紹到。
如何實現(xiàn)ContentProvider
理解了ContentProvider類,那么我們怎么去實現(xiàn)ContentProvider呢?怎么樣讓外部程序去訪問或者修改我們的數(shù)據(jù)呢?這樣的一個操作其實是非常簡單的,我們只需要下面的兩步就可以實現(xiàn)ContentProvider
1、? 編寫一個實現(xiàn)ContentProvider的子類,這個子類必須要實現(xiàn)一些必須實現(xiàn)的方法,在ContentProvider類里面,有一系列針對于數(shù)據(jù)的增、刪、改、查等方法
2、? ContentProvider也是Android中的四大組件,因此也必須在AndroidMainfest.xml中完成對ContentProvider的注冊。注冊方式為:
?
與ContentProvider相關(guān)操作的類介紹
從Uri談起
什么是Uri?
Uri是指通用資源標志符
A:前綴表明數(shù)據(jù)受控于一個內(nèi)容提供者。它從不修改,也就是schema
B:是指在AndroidMainfest.xml中我們注冊的provider中的android:authorities屬性所對應(yīng)的
C:具體操作于哪個條目
D:具體指定到哪個條目下的哪條記錄
再看它的類結(jié)構(gòu)和常用方法:
Uri
在這個里它是沒有構(gòu)造方法的,它通常通過下面的這個方法來返回一個Uri對象
?
方法名稱 |
描述 |
public static Uri parse (String uriString) |
通過一個傳入的字符串來構(gòu)造一個Uri對象 |
?
熟悉完Uri類再看與之相關(guān)的另外兩個類
UriMatcher類:
因為Uri代表了要操作的數(shù)據(jù),所以我們經(jīng)常需要解析Uri,并從Uri中獲取數(shù)據(jù)。Android系統(tǒng)提供了兩個用于操作Uri的工具類,分別為UriMatcher 和ContentUris 。掌握它們的使用,會便于我們的開發(fā)工作。
先看下它比較常用的幾個方法:
?
方法名稱 |
描述 |
public void addURI (String authority, String path, int code) |
往UriMatcher類里添加一個拼湊的Uri,在此我們可以理解為UriMatcher為一個Uri的容器,為個容器里面包含著我們即將可能要操作的Uri,它用于我們業(yè)務(wù)邏輯的處理,特別是第三個參數(shù)code,如果通過下面的match()方法匹配成功就返回這個code值 |
public int match (Uri uri) |
與傳入的Uri匹配,它會首先與找我們之前通過addURI方法添加進來的Uri匹配,如果匹配成功就返回之前我們設(shè)置的code值,否則返回一個UriMatcher.NO_MATCH常量值為-1 |
?
熟悉完上面的方法,那么我們再來看它如何使用:
UriMatcher類用于匹配Uri,它的用法如下:
UriMatcher類的用法
首先第一步把你需要匹配Uri路徑全部給注冊上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼
UriMatcher? sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content:// com.jiahui.provider.myprovider/person路徑,返回匹配碼為1
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person”, 1);//添加需要匹配uri,如果匹配就會返回匹配碼
//如果match()方法匹配content:// com.jiahui.provider.myprovider /person/230路徑,返回匹配碼為2
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person/#”, 2);//#號為通配符
switch (sMatcher.match(Uri.parse("content:// com.jiahui.provider.myprovider /person/10" ) )) {
?? case 1
??? break;
?? case 2
??? break;
?? default://不匹配
??? break;
}
注冊完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調(diào)用addURI()方法傳入的第三個參數(shù),假設(shè)匹配content://cn.itcast.provider.personprovider/person路徑,返回的匹配碼為1
再看另外一個工具類
ContentUris:
它用于在Uri后面追加一個ID或者解析出傳入的Uri所帶上的ID值,常用的兩個方法如下:
?
方法名稱 |
描述 |
public static Uri withAppendedId (Uri contentUri, long id) |
用于為路徑加上ID部分 |
public static long parseId (Uri contentUri) |
從路徑中獲取ID部分 |
?
熟悉完上面所提及的相關(guān)的類,接下來我們再看這個ContentProvider核心類
ContentProvider
常用方法
?
方法名稱 |
描述 |
public abstract boolean onCreate () |
在ContentProvider創(chuàng)建后被調(diào)用。 |
public abstract Uri insert (Uri uri, ContentValues values) |
根據(jù)Uri插入values對就的數(shù)據(jù) |
public abstract int delete (Uri uri, String selection, String[] selectionArgs) |
根據(jù)Uri刪除selection指定的條件所匹配的全部記錄 |
public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) |
根據(jù)Uri修改selection指定的條件所匹配的全部記錄 |
public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) |
根據(jù)Uri查詢出selection指定的條件所匹配的全部記錄,并且可以指定查詢哪些列(projection),以什么方式(sortOrder)排序 |
public abstract String getType (Uri uri) |
返回當前Uri所數(shù)據(jù)的MIME類型,如果該Uri對應(yīng)的數(shù)據(jù)可能包括多條記錄,那么MIME類型字符串就是以vnd.android.cursor.dir/開頭,如果Uri對應(yīng)的數(shù)據(jù)只包含一條記錄,那么MIME類型字符串就是以vnd.android.cursor.item/開頭 |
?
既然我們知道了ContentProvider類是向外提供數(shù)據(jù)的一種機制,那么在之前我們也說過要想來操作這個對外提供的數(shù)據(jù),我們就用到了另外一個類:
ContentResolver
在這個類里面也定義了一系列的增、刪、改、查方法,與其ContentProvider定義的方法基本上相同,在此不再復(fù)核。讀者可以自己查閱相關(guān)文檔。
可能大家在這里還是有點理不清這些類的一些關(guān)系,特別是ContentResolver與ContentProvider與Uri類的關(guān)系,那么我上張圖吧,或許對大家有所幫助:
好了熟悉完上面所述的這么多類那么我們就在實踐中見證真理吧:
實例:
實現(xiàn)效果:
代碼實現(xiàn):
?
先開發(fā)我們自己的ContentProvider:
千萬別忘記了要在AndroidMainfest.xml文件中注冊這個組件哦:
然后在一個主Activity編寫一些實現(xiàn)代碼:
package com.jiahui.provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import com.jiahui.model.Person;
public class ContentProviderDemoActivity extends Activity {
private Button btnadd, btnqueryall;
private EditText edtname, edtage;
private ListView lvall;
private List<Person> persons;
private SimpleAdapter simpleAdapter;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
List<Map<String, Object>> data = (List<Map<String, Object>>) msg.obj;
System.out.println(data.size());
simpleAdapter = new SimpleAdapter(
ContentProviderDemoActivity.this, data, R.layout.list_item,
new String[] { "id", "name", "age" }, new int[] {
R.id.tvId, R.id.tvname, R.id.tvage });
lvall.setAdapter(simpleAdapter);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
persons = new ArrayList<Person>();
btnqueryall = (Button) this.findViewById(R.id.btnqueryall);
btnadd = (Button) this.findViewById(R.id.btnadd);
edtname = (EditText) this.findViewById(R.id.edtname);
edtage = (EditText) this.findViewById(R.id.edtage);
lvall = (ListView) this.findViewById(R.id.lvall);
btnadd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = ContentProviderDemoActivity.this
.getContentResolver();
Uri url = Uri
.parse("content://com.jiahui.provider.myprovider/person");
ContentValues values = new ContentValues();
values.put("name", edtname.getText().toString());
values.put("age", edtage.getText().toString());
Uri result = contentResolver.insert(url, values);
System.out.println(result.toString());
if (ContentUris.parseId(result)>0) {
Toast.makeText(ContentProviderDemoActivity.this, "添加成功", Toast.LENGTH_LONG).show();
//添加成功后再啟動線程查詢
MyThread thread = new MyThread(ContentProviderDemoActivity.this);
thread.start();
}
}
});
//查詢所有
btnqueryall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyThread thread = new MyThread(ContentProviderDemoActivity.this);
thread.start();
}
});
lvall.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Toast.makeText(ContentProviderDemoActivity.this, position,
// Toast.LENGTH_LONG).show();
System.out.println("position:" + position);
Person person = persons.get(position);
Bundle bundle = new Bundle();
bundle.putInt("id", person.getId());
bundle.putString("name", person.getName());
bundle.putInt("age", person.getAge());
Intent intent = new Intent(ContentProviderDemoActivity.this,
ItemActivity.class);
intent.putExtra("item", bundle);
startActivityForResult(intent, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode==2) {
MyThread thread = new MyThread(ContentProviderDemoActivity.this);
thread.start();
}
}
class MyThread extends Thread {
Context context;
public MyThread(Context context) {
//一定要清空。否則會 有問題,每執(zhí)行一次都會把之前的全部的item加進去
persons.clear();
lvall.setAdapter(null);
this.context = context;
}
@Override
public void run() {
Uri url = Uri
.parse("content://com.jiahui.provider.myprovider/person");
Cursor cursor = context.getContentResolver().query(url,
new String[] { "_id", "name", "age" }, null, null, "_id");
while (cursor.moveToNext()) {
// System.out.println("_id:"
// + cursor.getInt(cursor.getColumnIndex("_id")));
// System.out.println("name:"
// + cursor.getString(cursor.getColumnIndex("name")));
// System.out.println("age:"
// + cursor.getInt(cursor.getColumnIndex("age")));
Person person = new Person();
person.setId(cursor.getInt(cursor.getColumnIndex("_id")));
person.setName(cursor.getString(cursor.getColumnIndex("name")));
person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
persons.add(person);
}
cursor.close();
List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
Map<String, Object> map=null;
for (int i = 0; i < persons.size(); i++) {
map = new HashMap<String, Object>();
map.put("id", persons.get(i).getId());
map.put("name", persons.get(i).getName());
map.put("age", persons.get(i).getAge());
data.add(map);
}
if (data.size()>=persons.size()) {
}
Message msg = handler.obtainMessage();
msg.obj = data;
handler.sendMessage(msg);
}
}
}
ItemActivity代碼:
?
??
?
?在手機開發(fā)中SQLite的使用demo
簡單的bean類
package com.easyway.android.sql; /** * 普通JavaBean * @author longgangbai * */ public class CityBean { public static final String ID = "_id"; public static final String CITY = "city"; public static final String CODE = "code"; private String id; private String city; private String code; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } }
?
?
界面展現(xiàn)類:
package com.easyway.android.sql; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; /** * * * 本例實現(xiàn)SQLite數(shù)據(jù)庫增加、刪除、修改、模糊查詢操作。這里不是最好的實現(xiàn)方法, * 如想研究SQL如何封裝,請詳細查看SQLiteDatebase類. * 查看SQL語句:String sql = SQLiteQueryBuilder.buildQueryString(); * * * @author longgangbai */ public class AndroidSQL extends Activity { private static String DB_NAME = "mycity.db"; private static int DB_VERSION = 1; private static int POSTION; private ListView listview; private Cursor cursor; private SQLiteDatabase db; private SQLiteHelper dbHelper; private ListAdapter listAdapter; private EditText etCity; private EditText etCode; private Button bt_add; private Button bt_modify; private Button bt_query; private List<CityBean> cityList = new ArrayList<CityBean>(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); etCity = (EditText) findViewById(R.id.etCity); etCode = (EditText) findViewById(R.id.etCode); bt_add = (Button) findViewById(R.id.bt_add); bt_modify = (Button) findViewById(R.id.bt_modify); bt_query = (Button) findViewById(R.id.bt_query); try{ /* 初始化并創(chuàng)建數(shù)據(jù)庫 */ dbHelper = new SQLiteHelper(this, DB_NAME, null, DB_VERSION); /* 創(chuàng)建表 */ db = dbHelper.getWritableDatabase(); //調(diào)用SQLiteHelper.OnCreate() /* 查詢表,得到cursor對象 */ cursor = db.query(SQLiteHelper.TB_NAME, null, null, null, null, null, CityBean.CODE + " DESC"); cursor.moveToFirst(); while(!cursor.isAfterLast() && (cursor.getString(1) != null)){ CityBean city = new CityBean(); city.setId(cursor.getString(0)); city.setCity(cursor.getString(1)); city.setCode(cursor.getString(2)); cityList.add(city); cursor.moveToNext(); } }catch(IllegalArgumentException e){ //當用SimpleCursorAdapter裝載數(shù)據(jù)時,表ID列必須是_id,否則報錯column '_id' does not exist e.printStackTrace(); //當版本變更時會調(diào)用SQLiteHelper.onUpgrade()方法重建表 注:表以前數(shù)據(jù)將丟失 ++ DB_VERSION; dbHelper.onUpgrade(db, --DB_VERSION, DB_VERSION); // dbHelper.updateColumn(db, SQLiteHelper.ID, "_"+SQLiteHelper.ID, "integer"); } listview = (ListView)findViewById(R.id.listView); listAdapter = new ListAdapter(); listview.setAdapter(listAdapter); listview.setOnItemClickListener(new ListView.OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> parent, View view, int postion, long arg3) { setSelectedValues(postion); } }); /* 插入表數(shù)據(jù)并ListView顯示更新 */ bt_add.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View arg0) { if(etCity.getText().length() > 1 && etCode.getText().length() >1){ ContentValues values = new ContentValues(); values.put(CityBean.CITY, etCity.getText().toString().trim()); values.put(CityBean.CODE, etCode.getText().toString().trim()); //插入數(shù)據(jù) 用ContentValues對象也即HashMap操作,并返回ID號 Long cityID = db.insert(SQLiteHelper.TB_NAME, CityBean.ID, values); CityBean city = new CityBean(); city.setId(""+cityID); city.setCity(etCity.getText().toString().trim()); city.setCode(etCode.getText().toString().trim()); cityList.add(city); listview.setAdapter(new ListAdapter()); resetForm(); } } }); /* 查詢表,模糊條件查詢 */ bt_query.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View view) { cityList.removeAll(cityList); String sql = null; String sqlCity = etCity.getText().length() > 0 ? CityBean.CITY + " like '%" + etCity.getText().toString().trim() + "%'" : ""; String sqlCode = etCode.getText().length() > 0 ? CityBean.CITY + " like '%" + etCity.getText().toString().trim() + "%'" : ""; if( (!"".equals(sqlCity)) && (!"".equals(sqlCode)) ){ sql = sqlCity + " and" + sqlCode; }else if(!"".equals(sqlCity)){ sql = sqlCity; }else if(!"".equals(sqlCode)){ sql = sqlCode; } cursor = db.query(true, SQLiteHelper.TB_NAME, new String[]{CityBean.ID, CityBean.CITY, CityBean.CODE}, sql, null, null, null, null, null); cursor.moveToFirst(); while(!cursor.isAfterLast() && (cursor.getString(1) != null)){ CityBean city = new CityBean(); city.setId(cursor.getString(0)); city.setCity(cursor.getString(1)); city.setCode(cursor.getString(2)); cityList.add(city); cursor.moveToNext(); } listview.setAdapter(new ListAdapter()); resetForm(); } }); /* 修改表數(shù)據(jù) */ bt_modify.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View arg0) { ContentValues values = new ContentValues(); values.put(CityBean.CITY, etCity.getText().toString().trim()); values.put(CityBean.CODE, etCode.getText().toString().trim()); db.update(SQLiteHelper.TB_NAME, values, CityBean.ID + "=" + cityList.get(POSTION).getId(), null); cityList.get(POSTION).setCity(etCity.getText().toString().trim()); cityList.get(POSTION).setCode(etCode.getText().toString().trim()); listview.setAdapter(new ListAdapter()); resetForm(); } }); } /* 設(shè)置選中ListView的值 */ public void setSelectedValues(int postion){ POSTION = postion; etCity.setText(cityList.get(postion).getCity()); etCode.setText(cityList.get(postion).getCode()); } /* 重值form */ public void resetForm(){ etCity.setText(""); etCode.setText(""); } @Override protected void onDestroy() { db.delete(SQLiteHelper.TB_NAME, null, null); super.onDestroy(); } private class ListAdapter extends BaseAdapter{ public ListAdapter(){ super(); } @Override public int getCount() { return cityList.size(); } @Override public Object getItem(int postion) { return postion; } @Override public long getItemId(int postion) { return postion; } @Override public View getView(final int postion, View view, ViewGroup parent) { view = getLayoutInflater().inflate(R.layout.listview, null); TextView tv = (TextView) view.findViewById(R.id.tvCity); tv.setText("" + cityList.get(postion).getCity()); TextView bu = (TextView) view.findViewById(R.id.btRemove); bu.setText(R.string.delete); bu.setId(Integer.parseInt(cityList.get(postion).getId())); /* 刪除表數(shù)據(jù) */ bu.setOnClickListener(new Button.OnClickListener(){ @Override public void onClick(View view) { try{ db.delete(SQLiteHelper.TB_NAME, CityBean.ID + "=" + view.getId(), null); cityList.remove(postion); listview.setAdapter(new ListAdapter()); }catch(Exception e){ e.printStackTrace(); } } }); return view; } } }
?
?
?
SQLite實現(xiàn)類:
package com.easyway.android.sql; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase.CursorFactory; /** * 實現(xiàn)對表的創(chuàng)建、更新、變更列名操作 * * 在Android 中針對少量數(shù)據(jù)的操作在SQLite操作實現(xiàn)相關(guān)功能功能 * ,但是必須繼承SQLiteOpenHelper,實現(xiàn)相關(guān)的功能。 * * * @author longgangbai * */ public class SQLiteHelper extends SQLiteOpenHelper { public static final String TB_NAME = "citys"; public SQLiteHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * 創(chuàng)建新表 */ @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + TB_NAME + "(" + CityBean.ID + " integer primary key," + CityBean.CITY + " varchar," + CityBean.CODE + " integer"+ ")"); } /** * 當檢測與前一次創(chuàng)建數(shù)據(jù)庫版本不一樣時,先刪除表再創(chuàng)建新表 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TB_NAME); onCreate(db); } /** * 變更列名 * @param db * @param oldColumn * @param newColumn * @param typeColumn */ public void updateColumn(SQLiteDatabase db, String oldColumn, String newColumn, String typeColumn){ try{ db.execSQL("ALTER TABLE " + TB_NAME + " CHANGE " + oldColumn + " "+ newColumn + " " + typeColumn ); }catch(Exception e){ e.printStackTrace(); } } }
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
